安卓 - 检测手机解锁事件,而非屏幕开启

65

有没有一种方法可以检测用户何时解锁手机?我知道关于 ACTION_SCREEN_ONACTION_SCREEN_OFF,但这些似乎只会在按下电源按钮开/关屏幕时触发,而不是在按下菜单按钮解锁时触发...

我正在尝试在活动运行时检测解锁/锁定状态,并且我希望在解锁后恢复该活动。

4个回答

66

以下是操作步骤:

假设你想在你的Activity中检测手机解锁事件并采取相应措施。你需要为ACTION_SCREEN_ON、ACTION_SCREEN_OFF和ACTION_USER_PRESENT注册一个Broadcast Receiver。

当ACTION_SCREEN_ON被触发时,将会调用Activity的onResume方法。创建一个Handler并等待ACTION_USER_PRESENT被触发,当它被触发时,实现你想要的Activity行为。

感谢CommonsWare在这里的回答:Android – What happens when device is unlocked?


1
有没有什么方法可以在C/C++中获得回调,即在本地层? - CoDe
2
我想指出,从Android O(API 26)开始,这些事件的BroadcastReceiver只能通过动态注册(通过在Activity内调用registerReceiver)进行。在AndroidManifest.xml中注册这些事件不再起作用,因此应用程序无法在未运行时(已被Android杀死或用户强制关闭)接收这些事件(至少是ACTION_SCREEN_ONACTION_SCREEN_OFF)。 - ahasbini
ACTION_USER_PRESENT 并不总是被调用。使用它并不安全。 - Michał Dobi Dobrzański

29

在经过一段时间的尝试后,我发现最好的方法是在"android.intent.action.USER_PRESENT"动作上注册一个BroadcastReceiver。

"广播动作:当设备唤醒后用户出现时发送(例如,当键盘锁消失时)"

为了区分用户在未锁定时打开屏幕和实际解锁时的情况,请使用KeyguardManager检查安全设置。

代码示例:

将以下内容添加到您的活动中:

registerReceiver(new PhoneUnlockedReceiver(), new IntentFilter("android.intent.action.USER_PRESENT"));

然后使用这个类:

public class PhoneUnlockedReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {

        KeyguardManager keyguardManager = (KeyguardManager)context.getSystemService(Context.KEYGUARD_SERVICE);
        if (keyguardManager.isKeyguardSecure()) {
            //phone was unlocked, do stuff here
        }
    }
}       

1
你不想在SDK 23+设备上检查if(!keyguardManager.isKeyguardLocked())!isDeviceSecure()吗? - Patrick
这里有一点不对,根据 https://dev59.com/_l0a5IYBdhLWcg3wsKi2#30053876 的说法,你需要检查 isDeviceLocked 来验证实际状态,而不仅仅是在设置中启用了安全锁。你还可以检查 KeyguardManager 的 inKeyguardRestrictedInputMode,适用于 API < 22。 - Abandoned Cart
1
我尝试了这个方法,但在Chromebook上无法运行,是否有其他解决方案可供选择? - Nikhil
我大约六年前发布了这个。 - Doron Manor

9
public class PhoneUnlockedReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals(Intent.ACTION_USER_PRESENT)){
            Log.d(TAG, "Phone unlocked");
        }else if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)){
            Log.d(TAG, "Phone locked");
        }
    }
}

通过这个语句注册接收器

receiver = new PhoneUnlockedReceiver();
        IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_USER_PRESENT);
        filter.addAction(Intent.ACTION_SCREEN_OFF);
        registerReceiver(receiver, filter);

我正在使用这段代码,它运行良好,请检查是否应用了任何图案/密码锁或使用了任何第三方屏幕锁定应用程序。它可能会干扰。 - Karan Nagpal

1

没有测试过,但可以尝试以下步骤:

  • 等待 ACTION_SCREEN_ON 事件。
  • (在屏幕点亮后) 等待带有 CATEGORY_HOME 类别的 ACTION_MAIN 事件 (这将启动主屏幕) - 这可能是手机解锁后发送的事件。

第一步是为了过滤掉普通 HOME 键的按下事件。


但这样做适用于所有手机吗?例如,在我的myTouch上,按下菜单按钮可以解锁手机,而其他一些手机则需要在屏幕上滑动。那么有没有什么方法可以通用呢? - Chris
我相信 - 使用类别CATEGORY_HOME的ACTION_MAIN肯定会被调用以运行主屏幕(即启动器)。然而,有许多Android手机,所以我无法100%确定。最好尝试一下,看看是否适用于您。 - adamk
我想我忘了提到我正在运行一个活动,而在它运行时,我想锁定/解锁屏幕并在解锁后恢复活动。等待ACTION_MAIN和CATEGORY_HOME只会在解锁时冻结我的活动。 - Chris
不确定您所说的“冻结”是什么意思。当您锁定手机时,您的活动会暂停,解锁后会恢复 - 因此在这种特定情况下(即在运行时锁定/解锁),您可以使用这些方法来检测您需要的内容。 - adamk
2
从Google "ACTION_MAIN with category CATEGORY_HOME -- Launch the home screen." 当您解锁手机时,它不会进入主屏幕,而是会带出上次使用的应用程序(恢复)。 - greenoldman
@adamk 但是,当手机打开时,可能会打开另一个应用程序。所以,这种方法可能行不通。 - Sambhav Khandelwal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接