web-dev-qa-db-fra.com

Comment accorder l'autorisation MODIFY_PHONE_STATE pour les applications exécutées sur Gingerbread

J'écris une application qui tente de modifier l'état des appels téléphoniques. Cela fonctionne bien sur Android 2.2 ou moins, mais lève une exception sur Android 2.3 en raison du manque d'autorisation sur Android.permission.MODIFY_PHONE_STATE permission (j'ai déclaré cette autorisation sur AndroidManifest.xml). Une idée? Voici le journal des exceptions:

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)
37
Bao Le

MODIFY_PHONE_STATE est une autorisation système uniquement, les applications ne sont donc pas autorisées à l'obtenir.

Cela a peut-être changé par rapport aux versions précédentes de la plate-forme, mais c'est correct car cela ne protège que les API privées, donc si vous faites quelque chose qui l'exige, vous utilisez des API privées qui ne sont pas prises en charge et entraîneront des choses comme votre application rupture sur différentes versions de la plate-forme.

L'analyse de la pile que vous incluez n'est pas terminée, il n'y a donc aucun moyen de savoir ce que vous faites réellement.

21
hackbod

Le problème que vous rencontrez a été introduit dans Android 2.3 (Gingerbread). Tout code que vous possédez et qui nécessite MODIFY_PHONE_STATE fonctionnera jusqu'à (et y compris) Android 2.2, mais s'arrêtera pour Android 2.3+.

A la modification a été archivée par David Brown qui limite l'utilisation de l'autorisation MODIFY_PHONE_STATE aux applications système. Les applications système sont soit

  1. Préinstallé dans un dossier système sur la ROM
  2. Compilé par un fabricant à l'aide de son certificat de sécurité

Je suppose que vous essayez d'utiliser une API cachée comme ITelephony. J'étais - et j'ai été brûlé par ce changement. La justification de l'équipe Android est qu'il s'agissait d'une API cachée que vous n'auriez pas dû l'utiliser en premier lieu.

Cela dit, il y a eu une demande d'amélioration ouverte pour créer une API de téléphonie publique appropriée, mais Google a tué le ticket. Il apparaît que leur position est qu'ils n'ont pas l'intention de changer de direction et que ces API ne sont pas destinées à la consommation publique.

55
Skylar Sutton

Essaye ça.

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");
}
6
user1163234

J'ai la solution.

Plutôt que de remplacer l'écran des appels entrants, faites ci-dessous deux choses. qui vous permettra d'accéder au bouton d'acceptation et de refus et vous permettra également d'afficher l'écran au-dessus de votre écran d'appel entrant.

(1) Faire une classe de récepteur:

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) votre xml d'activité ressemble à:

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) Rendez la mise en page de votre activité transparente (qui viendra au-dessus de l'écran d'appel), écrivez ci-dessous le code dans le manifeste

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

(4) Dans le manifeste, ajoutez votre récepteur de diffusion large

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

(5) ajouter le code ci-dessous dans oncreate () de IncomingCallActivity

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

À votre santé!

Faites-moi savoir si vous rencontrez un problème!

5
Dhrupal