【问题标题】:Android - detect phone unlock event, not screen onAndroid - 检测手机解锁事件,而不是屏幕开启
【发布时间】:2025-12-14 16:15:03
【问题描述】:

有没有办法检测用户何时解锁手机?我知道ACTION_SCREEN_ONACTION_SCREEN_OFF,但它们似乎是在按下电源按钮时屏幕打开/关闭时触发的,但实际上不是在按下菜单按钮时手机解锁时...

我正在尝试在活动运行时检测解锁/锁定,并且我想在解锁后恢复活动。

【问题讨论】:

    标签: android


    【解决方案1】:

    这是怎么做的:

    假设您想在手机解锁时检测解锁事件并在您的活动中执行某些操作。有一个 ACTION_SCREEN_ON、ACTION_SCREEN_OFF 和 ACTION_USER_PRESENT 的广播接收器。

    在触发 ACTION_SCREEN_ON 时将调用活动的 onResume。创建一个处理程序并等待 ACTION_USER_PRESENT。当它被触发时,实现你想要的活动。

    这里归功于 CommonsWare 的回答:Android -- What happens when device is unlocked?

    【讨论】:

    • 有什么地方我可以在 c/c++ 即本机层获得回调。
    • 我想指出 BroadcastReceiver,因为这些事件只能从 Android O (API 26) 开始动态注册(通过在 Activity 中调用 registerReceiver)。在AndroidManifest.xml 中注册这些事件不再有效,因此当应用程序未运行时(之前已被 Android 杀死或强制关闭),应用程序不再能够接收这些事件(至少 ACTION_SCREEN_ONACTION_SCREEN_OFF用户)。
    【解决方案2】:

    经过一段时间的努力,我发现最好的方法是在“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
            }
        }
    }       
    

    【讨论】:

    • 您不想在 SDK 23+ 设备上检查 if(!keyguardManager.isKeyguardLocked())!isDeviceSecure() 吗?
    • 这有点错误,因为*.com/a/30053876/461982 表示您要检查isDeviceLocked 以验证实际状态,而不仅仅是在“设置”中启用了安全锁。您还可以检查 KeyguardManager 的 inKeyguardRestrictedInputMode 的 API
    • 我试过了,但它在 Chromebook 上不起作用,是否有其他适用于 Chromebook 的解决方法。
    • 我在大约六年前发布了这篇文章。
    【解决方案3】:
    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);
    

    【讨论】:

    • 我正在使用这个 cod 并且它工作正常,请检查您是否应用了任何图案/pin 锁或使用任何第三方屏幕锁定应用程序。它可能会干扰。
    【解决方案4】:

    没有测试,但尝试以下:

    • 等待ACTION_SCREEN_ON
    • (屏幕打开后)等待类别为 CATEGORY_HOME 的 ACTION_MAIN(启动主屏幕) - 这可能是手机解锁后发送的内容。

    第一步需要过滤掉常规的 HOME 按键。

    【讨论】:

    • 但这适用于所有手机吗?例如,在 myTouch 上按菜单按钮解锁手机,其他一些手机需要您在手机上滑动。那么有什么东西可以包罗万象吗?
    • 我相信是这样——为了运行主屏幕(即启动器),肯定会调用类别为 CATEGORY_HOME 的 ACTION_MAIN。但是,有很多 Android 手机,所以我不能 100% 确定。最好试一试,看看它是否适合你。
    • 我想我忘了提到我正在运行一个活动,并且在它运行时,我想锁定/解锁屏幕并在解锁后恢复活动。等待 ACTION_MAIN 和 CATEGORY_HOME 只会冻结我的解锁活动。
    • 不知道你所说的冻结是什么意思。当您锁定手机时,您的活动会暂停,解锁后会恢复 - 因此在这种特定情况下(即在您运行时锁定/解锁),您可能可以使用这些方法来检测您需要什么。
    • 来自 Google “ACTION_MAIN 类别为 CATEGORY_HOME -- 启动主屏幕。”当您解锁手机时,它不会进入主屏幕,而是会带来上次使用的应用程序(恢复)。