Reject an incoming call - android

I am working on an android that will allow the user to add numbers to a blacklist. When an incoming number matches a number in the blacklist then the call should be rejected, even if the phone does ring briefly and then disconnects the call.
Everything I've found including on SO, says it can't be done without creating AIDL in com.android.internal.telephony which I've created but I can't add the modify phone state permission as it says it needs to be a system app.
I am targetting ICS upwards and I have seen other apps block calls in ICS and up so how is this done. I've also tried adding the modify phone state permission to the manifest file and it displays an error saying that it is only available for system apps so how do I get around this issue. I don't want the app to have to be rooted.
Thanks for any help you can provide

I've found the answer by a bit of luck.
Instead of adding permission MODIFY_PHONE_STATE add permission CALL_PHONE
Create a new package called com.android.internal.telephony
Inside this package create a file called ITelephony.aidl and add the following content
package com.android.internal.telephony;
interface ITelephony {
boolean endCall();
void answerRingingCall();
void silenceRinger();
}
Use the below code in order to block the call
try
{
TelephonyManager tm = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
Class c = Class.forName(tm.getClass().getName());
Method m = c.getDeclaredMethod("getITelephony");
m.setAccessible(true);
com.android.internal.telephony.ITelephony telephonyService = (ITelephony)m.invoke(tm);
//telephonyService.silenceRinger();
telephonyService.endCall();
}
catch (Exception e)
{
Log.d("BLOCK CALL", e.toString());
Toast.makeText(context, e.toString(), Toast.LENGTH_LONG).show();
}
Hope this helps others, its not too easy to find. I don't understand why Google removed the ability to do this without mucking about like this though.

Related

Why is the IncomingNumber always empty?

I'm totally new to mobile programming and to Xamarin or Xamarin.Forms. So I thought about starting small and trying a first app that is showing the phone number of an incoming call (just to know how to get this information into my app).
After a lot of trying and searching the net and not finding appropriate answers, I managed to at least be able to hit break points when there's an incoming call.
For that I created a class called StateListener in the Android specific project of my Xamarin.Forms solution. This class looks like that:
public class StateListener : PhoneStateListener
{
public override void OnCallStateChanged(CallState state, string incomingNumber)
{
base.OnCallStateChanged(state, incomingNumber);
switch (state)
{
case CallState.Ringing:
break; // <== set break point here
case CallState.Offhook:
break;
case CallState.Idle:
break;
}
}
}
And I instantiated this class in my MainActivity's OnCreate method like this:
StateListener phoneStateListener = new StateListener();
TelephonyManager telephonyManager = (TelephonyManager)GetSystemService(Context.TelephonyService);
telephonyManager.Listen(phoneStateListener, PhoneStateListenerFlags.CallState);
Now, when I run my little solution then the break point (see comment in code) is hit, but unfortunately the incomingNumber of the OnCallStateChanged method is always empty.
Following the unsatisfying documentation about the OnCallStateChanged method I set the needed Permission.ReadPhoneState permission in the manifest file, but that didn't help.
Maybe you can?
As doc says:
If application does not have READ_CALL_LOG permission or carrier
privileges (see TelephonyManager.hasCarrierPrivileges()), an empty
string will be passed as an argument.
so please check your application permissions.
It seems that once you emulated your app you have to set any new permissions manually inside the emulated Android, your app won't ask for it, since it's already installed.
After I gave my app the "Phone" permissions inside the emulated Android and restarted my app, I got the incomingNumber.

Android (Lollipop) cannot detect ongoing phone call from second SIM

I have a piece of code that makes phone calls and hangs up after a certain amount of time.
I've managed to make calls from both SIMs (using different tricks for the 2nd SIM), however, Android does not seem to be able to detect whether the 2nd SIM is off-hook;
Take a look at this piece of code:
Class<?> c = Class.forName(telMgr.getClass().getName());
Method m = c.getDeclaredMethod("getITelephony");
m.setAccessible(true);
ITelephony telephonyService = (ITelephony)m.invoke(telMgr);
if (telephonyService.isOffhook()) { // DO SOMETHING }
If the first SIM makes the call, I get isOffHook() to be true, but from the second SIM, the phone is in progress, but I get false.
Is there a way to detect if I'm off-hook on both SIMs?
Thanks
Thanks for the comments, but I have found a solution.
Rather than use old methodology of retrieving the ITelephony "instance" from the TelephonyManager (I used this trick in older versions cause other ways were making me troubles), I use the TelephonyManager directly by calling getCallState(), and it seems informative and accurate for both SIMs.
A code sample:
TelephonyManager telMgr = (TelephonyManager)(this.getMainContext()
.getSystemService(Context.TELEPHONY_SERVICE));
/* Making a call... */
if (telMgr.getCallState() != TelephonyManager.CALL_STATE_OFFHOOK) { /* Do your stuff */ }
Simple and straight forward. Working with my current 5.1 Lollipop version.

PhoneStateListener - what can I expect from onCellInfoChanged?

I posted this on Android dev group. I'm hoping I can get some feedback here.
The PhoneStateListener's callbacks onCellLocationChanged and onSignalStrengthsChanged were the goto methods for when I wanted to handle cell and signal data changes in GSM and CDMA. With API 17+, I can see that there's a new callback (onCellInfoChanged) for handling both cell and signal changes.
Looking at the documentation, it's not clear what I can expect from the introduction of this new callback.
Will LTE changes always and only trigger onCellInfoChanged?
Will GSM/CDMA changed remain on the older callbacks?
Does one overlap with the other? (i.e. Both old and new get triggered for LTE or GSM/CDMA.)
It may very well be that different OEMs will have different implementations (sigh!), but I'm hoping there are guidelines that everyone's supposed to follow.
Can anyone shed some light on this?
Thanks,
Sebouh
I didn't test if but it looks from the code that both will be called.
I downloaded code source of Android 4.3(API 18) using the SDK Manager.
The following observations made me think that both would be called.
The class that triggers these events is: com.android.server.TelephonyRegistry
It notifies the listener though:
public void listen(String pkgForDebug, IPhoneStateListener callback, int events, boolean notifyNow)
This same function calls for both type of notifications(Location and CellInfo) in a non exclusive way.
On line 256:
if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION)) {
try {
if (DBG_LOC) Slog.d(TAG, "listen: mCellLocation=" + mCellLocation);
r.callback.onCellLocationChanged(new Bundle(mCellLocation));
} catch (RemoteException ex) {
remove(r.binder);
}
}
This one will call onCellLocationChanged even on new LTE phone since there is nothing from the above code that would prevent this. This needs double checking that there is no upper layer that filters the events themselves
On line 300 in the same code:
if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO)) {
try {
if (DBG_LOC) Slog.d(TAG, "listen: mCellInfo=" + mCellInfo);
r.callback.onCellInfoChanged(mCellInfo);
} catch (RemoteException ex) {
remove(r.binder);
}
}
There are other things from the code that look like CDMA will be calling the newer API. For example com.android.internal.telephony.cdma.CdmaLteServiceStateTracker seems to be dealing with CDMA and LTE. Again it would require a more careful look but that should give you a good place to start.
You can also try to simulate that with the emulator.

Use android RootTools library to gain permission android.permission.STATUS_BAR

I am trying to code an app that calls a method in android StatusBarManager. I did it the same way as the hack to expand the android status bar:
try {
Object service = getSystemService("statusbar");
Class<?> statusbarManager = Class.forName("android.app.StatusBarManager");
Method expand = statusbarManager.getMethod("disable", new Class[] { int.class });
expand.invoke(service, 0x00200000);
} catch (Exception e) {
e.printStackTrace();
System.out.println("DISABLE HOME ERROR");
}
Except the method I want to call is disable() instead of expand().
However, I am getting a security exception "neither and user nor the current process has permission android.permission.STATUS_BAR.
I tried adding it to the manifest but because it is a system apps permission, it only works if I copy my app to /system/app.
I messed around with RootTools http://code.google.com/p/roottools/ but couldn't figure out how to set the permissions. I tried setPermissions(0) and setUserPermissions("android.permissions.status_bar") but none works. I am not really sure how to use this library.
Any help would be greatly appreciated!

How to programatically hide Caller ID on Android

on Android phones, under Call -> Additional settings -> Caller ID
it is possible to hide your caller ID. I want to do that programatically from my code, but was not able to find a way to do that.
I searched through
android.provider
android.telephony
for 2.1 release and was not able to find it.
Has anybody successfully solved this issue?
Thanks in advance. Best regards.
Here I will describe two approaches I tried.
1.) It is possible to display Additional Call Settings screen from your application. Although it looks like it is part of the Settings application, that is not true. This Activity is part of the Native Phone Application, and it may be approached with the following intent:
Intent additionalCallSettingsIntent = new Intent("android.intent.action.MAIN");
ComponentName distantActivity = new ComponentName("com.android.phone", "com.android.phone.GsmUmtsAdditionalCallOptions");
additionalCallSettingsIntent.setComponent(distantActivity);
startActivity(additionalCallSettingsIntent);
Then user has to manually press on the CallerID preference and gets radio button with 3 options.
This was not actually what I wanted to achieve when I asked this question. I wanted to avoid step where user has to select any further options.
2.) When approach described under 1.) is executed in the Native Phone Application, function setOutgoingCallerIdDisplay() from com.android.internal.telephony.Phone has been used.
This was the basis for the next approach: use Java Reflection on this class and try to invoke the function with appropriate parameters:
try
{
Class <?> phoneFactoryClass = Class.forName("com.android.internal.telephony.PhoneFactory");
try
{
Method getDefaultPhoneMethod = phoneFactoryClass.getDeclaredMethod("getDefaultPhone");
Method makeDefaultPhoneMethod = phoneFactoryClass.getMethod("makeDefaultPhone" , Context.class);
try
{
makeDefaultPhoneMethod.invoke(null, this);
Object defaultPhone = getDefaultPhoneMethod.invoke(null);
Class <?> phoneInterface = Class.forName("com.android.internal.telephony.Phone");
Method getPhoneServiceMethod = phoneInterface.getMethod("setOutgoingCallerIdDisplay", int.class, Message.class);
getPhoneServiceMethod.invoke(defaultPhone, 1, null);
}
catch (InvocationTargetException ex)
{
ex.printStackTrace();
}
catch (IllegalAccessException ex)
{
ex.printStackTrace();
}
}
catch (NoSuchMethodException ex)
{
ex.printStackTrace();
}
}
catch (ClassNotFoundException ex)
{
ex.printStackTrace();
}
Firstly I tried just to use getDefaultPhone(), but I get RuntimeException
"PhoneFactory.getDefaultPhone must be called from Looper thread"
Obviously, issue lies in the fact that I tried to call this method from the Message Loop that was not the Native Phone App one.
Tried to avoid this by making own default phone, but this was a security violation:
ERROR/AndroidRuntime(2338): java.lang.SecurityException: Permission Denial: not allowed to send broadcast android.provider.Telephony.SPN_STRINGS_UPDATED from pid=2338, uid=10048
The only way to overcome (both of) this would be to sign your app with the same key as the core systems app, as described under
Run secure API calls as root, android
I'm not sure if this is a global feature, but Australian phones can hide their number by prefixing the caller's number with #31# or 1831. This may not be the perfect solution, but a prefix like this could possibly work for your requirements during coding.

Categories

Resources