How to hook into the Power button in Android?

后端 未结 9 1537
挽巷
挽巷 2020-11-22 10:34

On an Android device, where the only buttons are the volume buttons and a power button, I want to make the app react to presses on the power button (long and short). How is

相关标签:
9条回答
  • 2020-11-22 11:00

    The existing answers don't completely answer the question and leave out enough details that they won't work without more investigation. I'll share what I've learned solving this.

    First you need to add the following permission to your manifest file:

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

    To handle short and long presses add the following overrides to your activity class:

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_POWER) {
            // Do something here...
            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) {
            // Do something here...
            return true;
        }
        return super.onKeyLongPress(keyCode, event);
    }
    

    Note: It is worth noting that onKeyDown() will fire multiple times before onKeyLongPress does so you may want to trigger on onKeyUp() instead or other logic to prevent acting upon a series of onKeyDown() calls when the user is really holding it down.

    I think this next part is for Cyanogenmod only. If the PREVENT_POWER_KEY constant is undefined then you should not need it.

    To start intercepting the power key you need to set the following flag from your activity:

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

    To stop intercepting the power key (allowing standard functionality):

    getWindow().clearFlags(WindowManager.LayoutParams.PREVENT_POWER_KEY);
    

    You can switch back and forth between the two modes repeatedly in your program if you wish.

    0 讨论(0)
  • 2020-11-22 11:00

    you have to use this:

    BroadcastReceiver screenoff = new BroadcastReceiver() {
    
    public static final String Screenoff = "android.intent.action.SCREEN_OFF";
    
    @Override
    public void onReceive(Context context, Intent intent) {
            if (!intent.getAction().equals(Screenoff)) return;
            //put code to handle power press here
            return;
    
    }};
    
    0 讨论(0)
  • 2020-11-22 11:08

    You could overwrite the public boolean onKeyDown(int keyCode, KeyEvent event) and public boolean onKeyUp(int keyCode, KeyEvent event) functions in your Activity class and test if keyCode is equal to KeyEvent.KEYCODE_POWER.

    I haven't tested this, but I would assume the system treats this like it does the Home key in that you cannot stop the system from receiving the key event, you can only observe that it occurs. To test this, try returning True from the above functions and see if this catches the key event.

    0 讨论(0)
  • 2020-11-22 11:09

    As mentioned here https://stackoverflow.com/a/15828592/1065357

    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
        if(!hasFocus) {
           Intent closeDialog = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
            sendBroadcast(closeDialog);
        }
    }
    
    0 讨论(0)
  • 2020-11-22 11:09

    Sharing a method to listen for Power button long press. Works with API 23+ permissions:

    1. Asking for system permission to draw overlay (This is not a normal or vulnerable permission). This is not a user permission, so You should really know, what you are doing, by asking for it.

      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. Starting a service and adds a special view to WindowManager

    3. Waiting for an action inside View's onCloseSystemDialogs method.

      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 ("recentapss".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;
          }
      }
      

    Manifest:

    <?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>
    
    0 讨论(0)
  • 2020-11-22 11:16

    Use Broadcast receiver for power button (Screen On/Off)event

    here is solution: create broadcast receiver class

    public class CallBroadCastReciever extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
    
            if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
                //The screen off position
                Toast.makeText(context,"Screen is off",Toast.LENGTH_LONG).show();
            }
            else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
                //The screen on position
         Toast.makeText(context,"Screen is on",Toast.LENGTH_LONG).show();
            }
        }}
    

    then follow below steps: 1. Initialize receiver in activity

    CallBroadCastReciever broadcastReceiver = new CallBroadCastReciever();
    

    2.Declare receiver in manifest file in tag

     <receiver android:name="com.android.CallBroadCastReciever">
    <intent-filter>
        <action android:name="android.intent.action.SCREEN_OFF"/>
        <action android:name="android.intent.action.SCREEN_ON"/>
    </intent-filter>
    </receiver>
    

    3.For send action and data from activity to receiver put below code in onCreate() or onStrat() method

    IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
    
    if (broadcastReceiver != null) {
        registerReceiver(broadcastReceiver, intentFilter);
    }}
    

    4.Don't forget to unregister receiver in onDestory() method

     protected void onDestroy() {
            super.onDestroy();
     if (broadcastReceiver != null) {
                    unregisterReceiver(broadcastReceiver);
                 } }
    
    0 讨论(0)
提交回复
热议问题