web-dev-qa-db-fra.com

Détecter le bouton d'alimentation appuyer longuement

J'ai lu quelques articles ici sur Stackoverflow, et je n'ai pas trouvé de bonne solution, je me demande s'il est possible de détecter quand l'utilisateur appuie longuement sur le bouton d'alimentation en essayant d'éteindre l'appareil, j'aimerais pour savoir si vous pouvez détecter cet événement, et laisser ou non afficher cette boîte de dialogue où apparaît (Redémarrer, Arrêter, etc ...)

J'ai essayé ça:

@Override
public boolean dispatchKeyEvent(KeyEvent event) {
        Toast.makeText(MainActivity.this, event.getKeyCode(), Toast.LENGTH_SHORT).show();
    return true;
}

mais il ne s'affiche pas, il devrait également fonctionner en tant que service, je veux dire que l'application peut ou non être ouverte pour afficher ce toast.

ÉDITER

Voici comment je mets le onCloseSystemDialog

//home or recent button
public void onCloseSystemDialogs(String reason) {
    if ("globalactions".equals(reason)) {
        Toast.makeText(PowerButtonService.this, "yaps", Toast.LENGTH_SHORT).show();
        Intent i= new Intent(getBaseContext(), Demo.class);
        i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        getApplication().startActivity(i);
    //} else if ("homekey".equals(reason)) {
        //home key pressed
    //} else if ("recentapss".equals(reason)) {
        // recent apps button clicked
    }
}

Cela fonctionne bien, mais uniquement lorsque l'appareil est déverrouillé, lorsque l'appareil est verrouillé n'affiche rien.

J'essaie également de comprendre comment supprimer la boîte de dialogue lorsque l'utilisateur clique sur le bouton d'alimentation, j'ai essayé ceci:

getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);

Mais si je veux le montrer à nouveau, comment puis-je le faire?

17
Skizo-ozᴉʞS

Partager ma méthode pour faire ce que vous souhaitez accomplir.

Fondamentalement, ce qu'il fait est

  1. Demander l'autorisation système pour dessiner la superposition (Ce n'est pas une autorisation normale ou vulnérable). Ce n'est pas une autorisation d'utilisateur, vous devriez donc vraiment savoir ce que vous faites en le demandant.

    public class MainActivity extends AppCompatActivity {
    
        public final static int REQUEST_CODE = 10101;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            if (checkDrawOverlayPermission()) {
                startService(new Intent(this, PowerButtonService.class));
            }
        }
    
        public boolean checkDrawOverlayPermission() {
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
                return true;
            }
            if (!Settings.canDrawOverlays(this)) {
                /** if not construct intent to request permission */
                Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
                    Uri.parse("package:" + getPackageName()));
            /** request permission via start activity for result */
                startActivityForResult(intent, REQUEST_CODE);
                return false;
            } else {
                return true;
            }
        }
    
        @Override
        @TargetApi(Build.VERSION_CODES.M)
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            if (requestCode == REQUEST_CODE) {
                if (Settings.canDrawOverlays(this)) {
                    startService(new Intent(this, PowerButtonService.class));
                }
            }
        }
    }
    
  2. Démarrage d'un service et ajout d'une vue spéciale à WindowManager

  3. En attente d'une action dans la méthode View de onCloseSystemDialogs

    public class PowerButtonService extends Service {
    
        public PowerButtonService() {
    
        }
    
        @Override
        public void onCreate() {
            super.onCreate();
            LinearLayout mLinear = new LinearLayout(getApplicationContext()) {
    
                //home or recent button
                public void onCloseSystemDialogs(String reason) {
                    if ("globalactions".equals(reason)) {
                        Log.i("Key", "Long press on power button");
                    } else if ("homekey".equals(reason)) {
                        //home key pressed
                    } else if ("recentapps".equals(reason)) {
                        // recent apps button clicked
                    }
                }
    
                @Override
                public boolean dispatchKeyEvent(KeyEvent event) {
                    if (event.getKeyCode() == KeyEvent.KEYCODE_BACK
                        || event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_UP
                        || event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_DOWN
                        || event.getKeyCode() == KeyEvent.KEYCODE_CAMERA
                        || event.getKeyCode() == KeyEvent.KEYCODE_POWER) {
                        Log.i("Key", "keycode " + event.getKeyCode());
                    }
                    return super.dispatchKeyEvent(event);
                }
            };
    
            mLinear.setFocusable(true);
    
            View mView = LayoutInflater.from(this).inflate(R.layout.service_layout, mLinear);
            WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
    
            //params
            WindowManager.LayoutParams params = new WindowManager.LayoutParams(
                100,
                100,
                WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
                WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                        | WindowManager.LayoutParams.FLAG_FULLSCREEN
                        | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
                        | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,
                PixelFormat.TRANSLUCENT);
            params.gravity = Gravity.LEFT | Gravity.CENTER_VERTICAL;
            wm.addView(mView, params);
        }
    
        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }
    }
    

Manifeste:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:Android="http://schemas.Android.com/apk/res/Android"
          package="powerbuttonpress">

    <uses-permission Android:name="Android.permission.SYSTEM_ALERT_WINDOW"/>

    <application
        Android:allowBackup="true"
        Android:icon="@mipmap/ic_launcher"
        Android:label="@string/app_name"
        Android:supportsRtl="true"
        Android:theme="@style/AppTheme">
        <activity Android:name=".MainActivity">
            <intent-filter>
                <action Android:name="Android.intent.action.MAIN"/>
                <category Android:name="Android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>

        <service
            Android:name=".PowerButtonService"
            Android:enabled="true"
            Android:exported="true">
        </service>

    </application>

</manifest>

service_layout:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:orientation="vertical">

</LinearLayout>
17
R. Zagórski

Je vois de nombreuses réponses essayant de se connecter au bouton d'alimentation. Cependant, ne serait-il pas plus facile d'écouter l'événement d'arrêt? Je ne sais pas si cela correspond à vos besoins, mais cela semble être le cas.

Enregistrez simplement un Broadcastreceiver à ce qui suit action (s) :

<receiver Android:name=".ShutdownReceiver">
    <intent-filter>
        <action Android:name="Android.intent.action.ACTION_SHUTDOWN" />
        <action Android:name="Android.intent.action.QUICKBOOT_POWEROFF" />
    </intent-filter>
</receiver>

N'oubliez pas d'ajouter l'autorisation suivante:

<uses-permission Android:name="Android.permission.DEVICE_POWER" />

6
Robin Dijkhof

Cette solution simple fonctionne:

    @Override
public boolean dispatchKeyEvent(KeyEvent event) {
    int keyPressed = event.getKeyCode();
    if(keyPressed==KeyEvent.KEYCODE_POWER){
        Log.d("###","Power button long click");
        Toast.makeText(MainActivity.this, "Clicked: "+keyPressed, Toast.LENGTH_SHORT).show();
        return true;}
    else
        return super.dispatchKeyEvent(event);
}

Si vous souhaitez arrêter la fenêtre contextuelle du système , utilisez la méthode onWindowFocusChanged spécifiée dans l'une des réponses ci-dessous.

La sortie montrera le toast avec "Clicked: 26" comme joint ci-dessous . enter image description here

5
DsD

Allez avec ça

<uses-permission Android:name="Android.permission.PREVENT_POWER_KEY" />

Et quand vous voulez capturer cet événement, faites ceci

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_POWER) {
        // this is method which detect press even of button
        event.startTracking(); // Needed to track long presses
        return true;
    }
    return super.onKeyDown(keyCode, event);
}

@Override
public boolean onKeyLongPress(int keyCode, KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_POWER) {
        // Here we can detect long press of power button
        return true;
    }
    return super.onKeyLongPress(keyCode, event);
}

Cela peut être fait avec un récepteur de diffusion. voir cette réponse

5
TapanHP

Essaye ça :

@Override
public boolean dispatchKeyEvent(KeyEvent event) {
    if (event.getKeyCode() == KeyEvent.KEYCODE_POWER) {
        Intent i = new Intent(this, ActivitySetupMenu.class);
        startActivity(i);
        return true;
    }

    return super.dispatchKeyEvent(event);
}
3
mrid

Pour un appui long .... Veuillez essayer ceci ...

import Android.app.Activity;
import Android.content.Intent;
import Android.os.Bundle;
import Android.view.KeyEvent;
import Android.view.WindowManager;
import Android.widget.Toast;

import Java.util.ArrayList;
import Java.util.Arrays;
import Java.util.List;

public class demo extends Activity {


    private final List<Integer> blockedKeys = new ArrayList<>(Arrays.asList(KeyEvent.KEYCODE_VOLUME_DOWN, KeyEvent.KEYCODE_VOLUME_UP, KeyEvent.KEYCODE_POWER));


    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
        setContentView(R.layout.demo);


    }

    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
        if (!hasFocus) {
            // Close every kind of system dialog
            Intent closeDialog = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
            sendBroadcast(closeDialog);
            Toast.makeText(demo.this, "Your LongPress Power Button", Toast.LENGTH_SHORT).show();
        }
    }

    @Override
    public void onBackPressed() {
        // nothing to do here
        // … really
    }

    @Override
    public boolean dispatchKeyEvent(KeyEvent event) {
        if (blockedKeys.contains(event.getKeyCode())) {


            return true;
        } else {

            return super.dispatchKeyEvent(event);
        }
    }
}

Appuyez longuement sur le bouton Toast Power Show pour le test ...

enter image description here

3
Arjun saini

La méthode utilisée ci-dessus par R. Zagórski a très bien fonctionné pour moi pendant longtemps, mais à partir d'une révision de Android 9 la méthode onCloseSystemDialogs a cessé de recevoir "globalactions".

Pour contourner ce problème, mon application utilise déjà l'accessibilité. Depuis l'intérieur du service d'accessibilité, vous pouvez ajouter ce code dans onAccessibilityEvent

@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
    Log.i(TAG,"Accessibilityevent");
    if (event == null || event.getPackageName()==null||event.getClassName()==null)
        return;


    if (event.getClassName().toString().contains("globalactions")){
        //TRIGGER YOUR CODE HERE

    }
        ....

Notez que si j'ai mis le commentaire "DÉCLENCHEZ VOTRE CODE ICI", j'appelle en fait le même code qui était auparavant dans onCloseSystemDialogs.

Notez que jusqu'à présent, cela n'a été testé que pour fonctionner sur un Pixel 2 fonctionnant sous Android. Je n'ai pas d'autre téléphone exécutant une version suffisamment récente, je ne peux donc pas tester si la solution est suffisamment générique sur tous les téléphones.

3

De la question Skizo-ozᴉʞS, ce que je comprends, vous voulez réellement empêcher le comportement du bouton d'alimentation et cela ne peut pas être fait. tout comme le bouton d'accueil a appuyé sur certains événements dans Android ne peut pas être empêché pour éviter que les gens aient des applications qu'ils ne peuvent pas quitter.

2
Mahesh Chakkarwar

Vous pouvez intercepter l'événement du bouton d'alimentation en remplaçant la méthode onKeyDown

@Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (event.getKeyCode() == KeyEvent.KEYCODE_POWER) {
            Log.e("key","long");
            /*//disable the system dialog
            Intent closeDialog = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
            sendBroadcast(closeDialog);*/
            Toast.makeText(getApplicationContext(),"Power",Toast.LENGTH_SHORT).show();
        }
        return super.onKeyDown(keyCode, event);
    }

Comme je le sais, nous ne pouvons pas faire cette activité extérieure (comme un service d'arrière-plan)

1
Jinesh Francis

La réponse acceptée fonctionne parfaitement jusqu'à Android Oreo mais pas dans Android P. Pour le faire fonctionner dans Android P you ') ll faut utiliser le service d'accessibilité

Classe de service

import Android.accessibilityservice.AccessibilityService;
import Android.util.Log;
import Android.view.accessibility.AccessibilityEvent;

import com.bm.yucasa.Utils.LocationSetup;

import static com.bm.yucasa.controller.AppController.TAG;

public class PowerServiceTwo extends AccessibilityService {
    @Override
    public void onAccessibilityEvent(AccessibilityEvent event) {
        Log.i(TAG,"Accessibilityevent");
        if (event == null || event.getPackageName()==null||event.getClassName()==null)
            return;


        if (event.getClassName().toString().contains("globalactions")){
            LocationSetup locationSetup = 
LocationSetup.getInstance(PowerServiceTwo.this);
            if (locationSetup.isConnected) {
                locationSetup.startOnDemandLocationUpdates(false, "0");
            } else {

                //Toast.makeText(getApplicationContext(), "please check gps", Toast.LENGTH_SHORT).show();
            }

        }
    }

    @Override
    public void onInterrupt() {

    }
}

Comme vous ne pouvez pas utiliser la méthode startService () pour démarrer un service d'accessibilité,

Voici donc comment vous pouvez l'activer.

Intent openSettings = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
openSettings.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(openSettings);
1
Jaswant Singh

Essaye ça :

 @Override
   public boolean onKeyLongPress( int keyCode, KeyEvent event ) {
     if( keyCode == KeyEvent.KEYCODE_POWER ) {
       //Handle what you want in long press.

       return true;
     }
     return super.onKeyLongPress( keyCode, event );
   }

Ajoutez ceci dans le manifeste:

 <uses-permission Android:name="Android.permission.DEVICE_POWER" />
 <uses-permission Android:name="Android.permission.PREVENT_POWER_KEY" />
0
Dipali s.