web-dev-qa-db-fra.com

Android - Réveillez et déverrouillez l'appareil

Description de l'application: L'application est conçue comme un programme de sécurité pour un client spécifique (ne doit pas être déployée publiquement). Lorsque l'application n'a pas détecté de mouvement pendant une certaine période de temps, l'application doit déclencher une alarme et se mettre au premier plan si elle est en arrière-plan ou si l'appareil est endormi.

Le problème: Dans le cas où l'appareil est endormi et verrouillé, nous devons nous réveiller et déverrouiller l'appareil. En utilisant diverses techniques trouvées ici sur SO et d'autres endroits, nous avons pu (partiellement) réveiller et déverrouiller l'appareil, mais cela se comporte SEULEMENT correctement lorsque l'appareil est physiquement connecté à un ordinateur) Si l'appareil est assis seul débranché et que nous testons le déverrouillage par réveil, rien ne se passe; l'appareil semble rester endormi et l'application semble ne rien faire du tout (pas d'alarme).

J'ai utilisé ce post sur l'utilisation de PowerManager et KeyguardManager , et ce post utilisant des drapeaux de fenêtre.

Voici le code actuellement utilisé pour réveiller l'appareil:

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

D'après les commentaires et les messages sur certaines des autres SO questions que j'ai vues/utilisées, il semble que le code PowerManager/KeyguardManager aurait dû faire l'affaire. Encore une fois, comme je l'ai déjà dit, il fonctionne techniquement lorsque l'appareil est branché via USB à la machine de développement, mais ne fait absolument rien lorsque l'appareil est séparé.

Notez également qu'il s'agit de notre première Android, et nous sommes donc pleinement conscients que nous pourrions être complètement hors de ce que nous essayons de faire. Toutes les suggestions sont les bienvenues.

Donc, en bref, compte tenu du code ci-dessus, pourquoi l'appareil se comporte-t-il si différemment selon qu'il est branché et que devons-nous changer pour réveiller et déverrouiller l'appareil comme décrit? Merci d'avance pour votre aide!

45
Paul Richter

J'ai résolu le problème. La raison pour laquelle nous avons observé un comportement différent lorsque l'appareil était branché via USB était que le processeur de l'appareil n'allait pas dormir. Je suppose que cela est soit le résultat du paramètre de mode de débogage, soit simplement la façon dont il se comporte lorsqu'il est branché à un ordinateur, car la fonction d'économie d'énergie de la mise en veille du processeur ne serait pas pertinente. De toute évidence, lorsque l'appareil n'est pas branché, le processeur ferait une sieste avec plaisir, et bien que nous ayons observé l'application s'exécuter de manière aléatoire (elle se réveillerait à des moments aléatoires), le timing serait incohérent. Je suppose en outre que cela est dû au fait que les quelques cycles CPU qui se sont produits sont alloués avec parcimonie, et notre application se verrait attribuer très peu de cycles à des moments "aléatoires".

Notre solution consistait donc à saisir un verrou de réveil partiel lorsque le périphérique passe en arrière-plan (ce qui se fait dans la méthode onPause), et à libérer le verrou dans la méthode onResume. Cela semble empêcher le processeur de dormir. Nous continuons à utiliser le verrouillage de réveil complet et la désactivation du protège-clavier pour réveiller l'appareil lorsque nous en avons besoin. L'utilisation du verrouillage de réveil partiel semble empêcher le processeur de dormir et l'appareil semble se réveiller correctement lorsque prévu. Voici notre code mis à jour, au cas où quelqu'un rencontrerait ce problème:

// 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();
}
58
Paul Richter