【问题标题】:Android - Wake Up and Unlock DeviceAndroid - 唤醒和解锁设备
【发布时间】:2015-10-22 18:21:01
【问题描述】:

应用说明: 该应用程序旨在作为特定客户的安全程序(不公开部署)。当应用程序在一段时间内没有检测到移动时,如果应用程序处于后台或设备处于睡眠状态,则应用程序应发出警报并将自身置于前台。

问题: 如果设备处于睡眠状态并被锁定,我们需要唤醒并解锁设备。使用在 SO 和其他地方发现的各种技术,我们已经能够(部分)唤醒和解锁设备,但是只有在设备物理插入计算机时才能正常运行。如果设备自己拔掉插头,我们测试唤醒解锁,什么都不会发生;设备似乎保持睡眠状态,而应用程序似乎什么都不做(没有警报)。

我用过this post about using PowerManager and KeyguardManagerthis post using window flags.

这是目前用于唤醒设备的代码:

public void wakeDevice() {
    PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
    wakeLock = powerManager.newWakeLock((PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP), "TAG");
    wakeLock.acquire();

    KeyguardManager keyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
    KeyguardLock keyguardLock = keyguardManager.newKeyguardLock("TAG");
    keyguardLock.disableKeyguard();
    runOnUiThread(new Runnable(){
        public void run(){
            getWindow().addFlags(
                      WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
                    | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
                    | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
                    | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);                
        }
    });
}

从我看到/使用的其他一些 SO 问题的 cmets 和帖子来看,似乎 PowerManager / KeyguardManager 代码应该可以解决问题。同样,正如我之前所说,当设备通过 USB 插入开发机器时,它在技术上确实有效,但在设备分离时绝对没有任何作用。

另外请注意,这是我们的第一个 Android 应用程序,因此我们充分意识到我们可能完全偏离了我们正在尝试做的事情。欢迎提出任何建议。

简而言之,鉴于上面的代码,为什么设备的行为会根据它是否插入而如此不同,我们应该改变什么来唤醒和解锁设备?提前感谢您的帮助!

【问题讨论】:

    标签: android android-wake-lock keyguard


    【解决方案1】:

    我解决了这个问题。当设备通过 USB 插入时,我们观察到不同行为的原因是设备的 CPU 不会进入睡眠状态。我认为这要么是调试模式设置的结果,要么只是它在插入计算机时的行为方式,因为 CPU 睡眠的省电功能无关紧要。显然,当设备没有插入时,CPU 会愉快地小睡一会儿,虽然我们确实观察到应用程序随机运行(它会随机唤醒自己),但时间会不一致。我进一步假设这是因为很少分配发生的 CPU 周期,并且我们的应用程序将在“随机”时间获得很少的周期。

    所以我们的解决方案是在设备进入后台时获取部分唤醒锁(在onPause 方法中完成),并在onResume 方法中释放锁。这似乎可以防止 CPU 休眠。我们会在需要时继续使用完全唤醒锁和键盘保护禁用来唤醒设备。使用部分唤醒锁似乎可以防止 CPU 进入睡眠状态,并且设备确实可以按预期正确唤醒。这是我们更新的代码,以防万一有人遇到这个问题:

    // Called from onCreate
    protected void createWakeLocks(){
        PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
        fullWakeLock = powerManager.newWakeLock((PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP), "Loneworker - FULL WAKE LOCK");
        partialWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Loneworker - PARTIAL WAKE LOCK");
    }
    
    // Called implicitly when device is about to sleep or application is backgrounded
    protected void onPause(){
        super.onPause();
        partialWakeLock.acquire();
    }
    
    // Called implicitly when device is about to wake up or foregrounded
    protected void onResume(){
        super.onResume();
        if(fullWakeLock.isHeld()){
            fullWakeLock.release();
        }
        if(partialWakeLock.isHeld()){
            partialWakeLock.release();
        }
    }
    
    // Called whenever we need to wake up the device
    public void wakeDevice() {
        fullWakeLock.acquire();
    
        KeyguardManager keyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
        KeyguardLock keyguardLock = keyguardManager.newKeyguardLock("TAG");
        keyguardLock.disableKeyguard();
    }
    

    【讨论】:

    • 你需要在 onPause() 方法的顶部添加一个 super.onPause() 调用吗?排除此内容时发生崩溃。
    • Teeg 不确定谁对你投了反对票,但肯定不是我……昨晚在我的 Light Alarm 应用程序上实现了这一点,今天早上它奏效了——一切正常。非常感谢您提供此解决方案!问答 +1。
    • @CharlieSeligman 很酷的人,非常感谢。没想到是你,但不知道是谁或为什么。我很高兴它也对你有用。也很高兴我不是世界上唯一一个在这个问题上苦苦挣扎的人。
    • 遇到了类似的问题,谢谢。
    • 太棒了,经过这么长时间的搜索,点击并尝试我终于找到了完美的解决方案,为你干杯
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-16
    • 1970-01-01
    • 1970-01-01
    • 2020-08-02
    • 1970-01-01
    • 2020-01-14
    相关资源
    最近更新 更多