39

I write an application that attempts to modify phone call state. It works well on Android 2.2 or less, but throw an exception on Android 2.3 because of the lack of permission on android.permission.MODIFY_PHONE_STATE permission (I declared this permission on AndroidManifest.xml). Any idea? Below is the exception log:

01-15 09:14:23.210: ERROR/AndroidRuntime(404): FATAL EXCEPTION: main
01-15 09:14:23.210: ERROR/AndroidRuntime(404): java.lang.RuntimeException: Unable to start receiver test.PhoneReceiver: java.lang.SecurityException: Neither user 10031 nor current process has android.permission.MODIFY_PHONE_STATE.
01-15 09:14:23.210: ERROR/AndroidRuntime(404):     at android.app.ActivityThread.handleReceiver(ActivityThread.java:1780)
01-15 09:14:23.210: ERROR/AndroidRuntime(404):     at android.app.ActivityThread.access$2400(ActivityThread.java:117)
01-15 09:14:23.210: ERROR/AndroidRuntime(404):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:978)
01-15 09:14:23.210: ERROR/AndroidRuntime(404):     at android.os.Handler.dispatchMessage(Handler.java:99)
01-15 09:14:23.210: ERROR/AndroidRuntime(404):     at android.os.Looper.loop(Looper.java:123)
01-15 09:14:23.210: ERROR/AndroidRuntime(404):     at android.app.ActivityThread.main(ActivityThread.java:3647)
01-15 09:14:23.210: ERROR/AndroidRuntime(404):     at java.lang.reflect.Method.invokeNative(Native Method)
01-15 09:14:23.210: ERROR/AndroidRuntime(404):     at java.lang.reflect.Method.invoke(Method.java:507)
01-15 09:14:23.210: ERROR/AndroidRuntime(404):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
01-15 09:14:23.210: ERROR/AndroidRuntime(404):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
01-15 09:14:23.210: ERROR/AndroidRuntime(404):     at dalvik.system.NativeStart.main(Native Method)
Bao Le
  • 16,643
  • 9
  • 65
  • 68

5 Answers5

55

The problem you're having was introduced in Android 2.3 (Gingerbread). Any code you have that requires MODIFY_PHONE_STATE will work all the way up to (and including) Android 2.2, but will break for Android 2.3+.

A change was checked in by David Brown that limits the use of the MODIFY_PHONE_STATE permission to system apps. System apps are either

  1. Pre-installed into a system folder on the ROM
  2. Compiled by a manufacturer using their security certificate

I suspect you're trying to use a hidden API like ITelephony. I was - and I got burned by this change. The Android team's justification is that it was a hidden API that you shouldn't have been using it in the first place.

That said, there was an enhancement request opened to create a proper public Telephony API, but Google killed the ticket. It appears their stance is that they do not intend to reverse direction and these APIs are not for public consumption.

Skylar Sutton
  • 4,632
  • 3
  • 27
  • 39
20

MODIFY_PHONE_STATE is a system-only permission, so apps are not allowed to get it.

This may have changed from previous versions of the platform, but that is okay because it is only protecting private APIs, so if you are doing something that requires it, you are using private APIs that are not supported and will result in things like your app breaking on different builds of the platform.

The stack crawl you include is not complete, so there is no way to tell what you are actually doing.

Dan J
  • 25,433
  • 17
  • 100
  • 173
hackbod
  • 90,665
  • 16
  • 140
  • 154
  • 1
    My app tries to block an incoming call that relies on internal API. That works perfectly on Android 2.2 and earlier, but Android 2.3. Do you have any idea – Bao Le Jan 19 '11 at 17:07
  • 7
    Yes you are using a private API, and the API no longer works. This is what happens when you rely on APIs. This is why we try so hard to make it clear when you are not using public APIs, and run the risk of running into a problem. – hackbod Jan 20 '11 at 03:24
  • 4
    Android badly needs a proper full public telephony API Dianne! Please!! :) – Donal Rafferty Mar 08 '11 at 12:46
  • 1
    Is there a reason we cannot just use reflection to access the private APIs if Android will not provide them by default? – Tom Aug 18 '11 at 22:55
  • 3
    Um, that is what this whole question is about. The app is using private implementation, that implementation changed, the app broke. Using stuff not in the supported SDK means your app can break at any time, on any device, on any version of Android. – hackbod Aug 19 '11 at 06:53
6

Try this.

public static void answerPhoneHeadsethook(Context context) {
    // Simulate a press of the headset button to pick up the call
    // SettingsClass.logMe(tag, "Simulating headset button");
    Intent buttonDown = new Intent(Intent.ACTION_MEDIA_BUTTON);
    buttonDown.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_HEADSETHOOK));
    context.sendOrderedBroadcast(buttonDown, "android.permission.CALL_PRIVILEGED");

    // froyo and beyond trigger on buttonUp instead of buttonDown
    Intent buttonUp = new Intent(Intent.ACTION_MEDIA_BUTTON);
    buttonUp.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_HEADSETHOOK));
    context.sendOrderedBroadcast(buttonUp, "android.permission.CALL_PRIVILEGED");
}
user1163234
  • 2,407
  • 6
  • 35
  • 63
5

I got the solution.

Rather to override incoming call screen, do below two things. which will allow you to access accept and decline button and also allow you to show screen above your incoming call screen.

(1) Make one receiver class:

public class MyPhoneReceiver extends BroadcastReceiver {
@Override
public void onReceive(final Context context, final Intent intent) {
    Bundle extras = intent.getExtras();
    if (extras != null) 
    {
        String state = extras.getString(TelephonyManager.EXTRA_STATE);
        if (state.equals(TelephonyManager.EXTRA_STATE_RINGING)) 
            String phoneNumber = extras.getString(TelephonyManager.EXTRA_INCOMING_NUMBER);

        Intent i = new Intent(context, IncomingCallActivity.class);
        i.putExtras(intent);
        i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(i);
    }
    }
}

(2) your activity xml look like:

RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="top"
android:gravity="top"
android:orientation="vertical"
android:windowAnimationStyle="@android:style/Animation.Translucent"
android:windowBackground="@android:color/transparent"
android:windowIsTranslucent="true"

(3)Make your activity's layout transparent(which will come above calling screen),write below code in menifest

<activity android:name=".IncomingCallActivity" 
         android:theme="@android:style/Theme.Translucent">
</activity>

(4)In menifest add your broad cast receiver

<receiver android:name="MyPhoneReceiver" >
        <intent-filter>
            <action android:name="android.intent.action.PHONE_STATE" >
            </action>
        </intent-filter>
</receiver>

(5) add below code in oncreate() of IncomingCallActivity

getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
this.requestWindowFeature(Window.FEATURE_NO_TITLE);

Cheers!

Let me know if you face any problem!

B770
  • 1,272
  • 3
  • 17
  • 34
Dhrupal
  • 1,863
  • 1
  • 23
  • 38
  • 1
    You mean you successfully used the aidl technique and used the above logic for the activity to allow user to answer the call using on screen buttons (that u defined in your activity xml) ? That would be great, if it really works that way.. – omkar.ghaisas Apr 17 '12 at 12:59
  • No, this code will allow you to put your things above the original incoming call screen and allow you to access default incoming and outgoing call button same time.. – Dhrupal Apr 23 '12 at 10:03
  • @Dhrupal , can you please explain more how you did it. What are you actually doing in your activty. I have similar requiremnet, i want to show some extra information for incoming calls – png Jun 06 '12 at 06:53
  • Thanks a lot. Everything works except if you are in your current application . If in the current app, the dialer view is pushed to back and the override screen comes over the current activity of the app. Did you face this issue. Thanks again for your replay – png Jun 07 '12 at 12:21
  • Yes i have also faced this problem. I have finished that activity on onStop(). – Dhrupal Jun 07 '12 at 12:28
  • I have finished all activities of that application on onStop(). – Dhrupal Jun 07 '12 at 12:38
  • i had two issues, one was that if the app was background when call comes, and if i try to bring app to foreground by long Home press , its always this overide screnn that pops up . This issue can be solved by our suggestion. But what i have mentioned here is a different one. If the app is in foreground and call comes, i am facing this problem. Thanks a lot – png Jun 09 '12 at 10:59
  • @Preetha: have you tried this thing on actual device? Try to test it in device with below code containing your activity which is foreground.@Override public void onStop() { super.onStop();finish();} – Dhrupal Jun 11 '12 at 05:26
  • @Dhrupal: in this case we are passing touch event to the screen below( i.e. native incoming screen), so if i want to access views on my screen (say some button), would that be possible...? – Vikram Singh Nov 17 '13 at 12:43
  • Hi, Nice solution! I'm trying to implement this, but i get an exception; Caused by: android.util.AndroidRuntimeException: requestFeature() must be called before adding content pls help – SamAko Feb 16 '14 at 11:24
  • 2
    @elimence call window request feature before setContentView(id); – Vikrant_Dev Feb 26 '14 at 10:08
-5

If your application for Gingerbread is running on a tablet and there is no phone, then this is expected behavior. You'll need to make the telephony related permissions in your manifest non-mandatory to run on tablets.

Try this in your manifest:

<uses-feature android:name="android.hardware.telephony" 
    android:required="false" />

Of course, I'm making a big assumption about the tablet. You can also see the Android reference here.

Jerry Brady
  • 3,050
  • 24
  • 30
  • 3
    Thanks. My app does use telephony related features. It turned into problem on Gingerbread/Android 2.3, but alway works fine on Android 2.2 – Bao Le Jan 17 '11 at 16:33