如何连接到 Android 中的电源按钮?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3703071/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 11:27:04  来源:igfitidea点击:

How to hook into the Power button in Android?

android

提问by Lars D

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 this done?

在 Android 设备上,唯一的按钮是音量按钮和电源按钮,我想让应用程序对按下电源按钮(长和短)做出反应。这是怎么做的?

采纳答案by Lars D

Solution:

解决方案:

@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);
}

回答by JT.

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.

注意:值得注意的是 onKeyDown() 将在 onKeyLongPress 之前触发多次,因此您可能希望触发 onKeyUp() 或其他逻辑,以防止在用户真正按住它时对一系列 onKeyDown() 调用进行操作.

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

我认为下一部分仅适用于 Cyanogenmod。如果PREVENT_POWER_KEY常量未定义,则您不需要它。

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.

如果您愿意,您可以在程序中重复在两种模式之间来回切换。

回答by R. Zagórski

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

分享一个方法来听长按电源按钮。适用于 API 23+ 权限:

  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 onCloseSystemDialogsmethod.

    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;
        }
    }
    
  1. 请求系统权限以绘制叠加层(这不是正常或易受攻击的权限)。这不是用户许可,因此您应该通过询问来真正了解自己在做什么。

    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. 启动服务并添加特殊视图 WindowManager

  3. 等待ViewonCloseSystemDialogs方法中的操作。

    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>

回答by Cristian

On you activity add:

在您的活动中添加:

public boolean onKeyDown(int keyCode, KeyEvent event) {
    if (event.getKeyCode() == KeyEvent.KEYCODE_POWER) {
        // do what you want with the power button
        return true;
    }
    return super.onKeyDown(keyCode, event);
}

Though... this kind of keys are somehow special... not sure if it can give problems to you.

虽然......这种钥匙在某种程度上很特别......不确定它是否会给你带来问题。

回答by ZeeShaN AbbAs

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

正如这里提到的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);
    }
}

回答by Aaron C

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 keyCodeis equal to KeyEvent.KEYCODE_POWER.

您可以覆盖Activity 类中的public boolean onKeyDown(int keyCode, KeyEvent event)public boolean onKeyUp(int keyCode, KeyEvent event)函数并测试是否keyCode等于KeyEvent.KEYCODE_POWER

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

我没有测试过这个,但我认为系统会像对待Home关键一样对待这个,因为你不能阻止系统接收关键事件,你只能观察它发生。要对此进行测试,请尝试True从上述函数返回并查看是否捕获了关键事件。

回答by Hossein

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;

}};

回答by Abhinav Gupta

For all android versions use this code.

对于所有 android 版本,请使用此代码。

I tried R. Zagórski's answer, but I am not able to run this code on Pie. However, I have updated their code in my answer.

我尝试了R. Zagórski的答案,但我无法在 Pie 上运行此代码。但是,我在答案中更新了他们的代码。

PowerButtonService:

电源按钮服务:

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");
                    Intent intent = new Intent(Intent.ACTION_CALL);
                    intent.setData(Uri.parse("tel:" + "9690008019"));
                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    intent.addFlags(Intent.FLAG_FROM_BACKGROUND);
                    startActivity(intent);
                } 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);

      **// here I done with EDIT** 

        int LAYOUT_FLAG;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            LAYOUT_FLAG = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
        } else {
            LAYOUT_FLAG = WindowManager.LayoutParams.TYPE_PHONE;
        }
        View mView = LayoutInflater.from(this).inflate(R.layout.service_layout, mLinear);
        WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);

        //params
        WindowManager.LayoutParams params = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.WRAP_CONTENT,
                LAYOUT_FLAG,
                WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
                PixelFormat.TRANSLUCENT);
        params.gravity = Gravity.LEFT | Gravity.CENTER_VERTICAL;
        wm.addView(mView, params);
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

and service_layout:

和服务布局:

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


</LinearLayout>

回答by civani mahida

Use Broadcast receiverfor 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

然后按照以下步骤操作: 1. 在活动中初始化接收器

CallBroadCastReciever broadcastReceiver = new CallBroadCastReciever();

2.Declare receiver in manifest file in tag

2.在清单文件中的标签中声明接收者

 <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

3.为了将动作和数据从活动发送到接收器,将下面的代码放在 onCreate() 或 onStrat() 方法中

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

4.不要忘记在 onDestory() 方法中注销接收者

 protected void onDestroy() {
        super.onDestroy();
 if (broadcastReceiver != null) {
                unregisterReceiver(broadcastReceiver);
             } }