簡體   English   中英

檢測電源鍵長按

[英]Detect power button long press

我一直在 Stackoverflow 上閱讀一些帖子,但沒有找到好的解決方案,我想知道是否可以檢測到用戶在嘗試關閉設備時長按電源按鈕的時間,我想知道您是否可以檢測到該事件,並讓或不顯示出現的對話框(重新啟動、關閉等...)

我試過這個:

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

但它沒有出現,它也應該作為一項服務工作,我的意思是可以或不可以打開該應用程序來顯示該祝酒詞。

編輯

這就是我放置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
    }
}

它工作正常,但只有在設備解鎖時,設備被鎖定時才顯示任何內容。

我還試圖弄清楚當用戶單擊電源按鈕時如何刪除對話框我試過這個:

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

但是如果我想再次顯示它,我該怎么做呢?

分享我的方法來做你想要實現的目標。

基本上,它的作用是

  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 ("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 final WindowManager.LayoutParams params; if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { params = new WindowManager.LayoutParams( 100, 100, WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY, WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT); } else { params = new WindowManager.LayoutParams( 100, 100, WindowManager.LayoutParams.TYPE_PHONE, 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; } }

清單:

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

服務布局:

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

我看到很多答案都試圖連接到電源按鈕。 但是,監聽關閉事件不是更容易嗎? 我不確定這是否符合您的需要,但似乎是這樣。

只需將廣播接收器注冊到以下操作

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

不要忘記添加以下權限:

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

對於長按......請試試這個......

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

Long Press Button of power show toast for test...

在此處輸入圖片說明

這個簡單的解決方案有效:

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

如果要停止系統彈出窗口,請使用以下答案之一中指定的onWindowFocusChanged方法。

輸出將顯示帶有“Clicked:26”的吐司,如下所示。 在此處輸入圖片說明

用這個去

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

當您想捕獲該事件時,請執行此操作

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

它可以用廣播接收器來完成。 看到這個答案

試試這個:

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

R. Zagórski 上面使用的方法在很長一段時間內對我來說效果很好,但是從 Android 9 的某些版本開始, onCloseSystemDialogs方法停止接收“全局操作”。

作為一種解決方法,我的應用程序已經在使用輔助功能。 從 AccessibilityService 內部,您可以在 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

    }
        ....

請注意,如果我將注釋“TRIGGER YOUR CODE HERE”放在此處,我實際上只是調用了以前在onCloseSystemDialogs 中的相同代碼。

請注意,到目前為止,這僅在運行最新 Android 的 Pixel 2 上進行了測試。 我沒有任何其他手機運行足夠新的版本,因此無法測試該解決方案是否在手機上足夠通用。

從 Skizo-ozᴉʞS 問題,據我了解,您實際上想要阻止電源按鈕的行為,但這是無法做到的。 就像按下主頁按鈕一樣,無法阻止 Android 中的某些事件,以避免人們擁有無法退出的應用程序。

您可以通過覆蓋 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);
    }

據我所知,我們不能在外部活動(例如后台服務)中執行此操作

接受的答案在 Android Oreo 之前都可以完美運行,但在 Android P 中不行。要使其在 android P 中運行,您需要使用 Accessibility 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() {

    }
}

由於您不能使用 startService() 方法來啟動輔助功能服務,

所以這里是如何啟用它。

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

試試這個:

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

在 Manifest 中添加:

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

如果您聽的是屏幕睡眠或喚醒,那么此代碼適合您

public class MyBroadCastReciever extends BroadcastReceiver {

@Override
public void onReceive(Context context, Intent intent) {
    if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
        //Take count of the screen off position
    } else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
        //Take count of the screen on position
    }
}
}

在清單中添加:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM