45

アプリケーションの説明: アプリケーションは、特定のクライアント向けの安全プログラムとして意図されています (一般に展開されることはありません)。アプリケーションが一定時間動きを検出しなかった場合、アプリケーションはアラームを鳴らし、バックグラウンドにある場合やデバイスがスリープ状態の場合はフォアグラウンドに移動する必要があります。

問題: デバイスがスリープ状態でロックされている場合、デバイスを起動してロックを解除する必要があります。ここ SO やその他の場所で見つかったさまざまな手法を使用して、デバイスを (部分的に) スリープ解除してロック解除することができましたが、これは、デバイスがコンピューターに物理的に接続されている場合にのみ適切に動作します。デバイスがプラグを抜いたまま放置されていて、ウェイクアンロックをテストしても何も起こりません。デバイスはスリープ状態のままで、アプリケーションは何もしていないようです (アラームなし)。

PowerManager と KeyguardManager の使用に関するこの投稿と、ウィンドウ フラグの使用に関するこの投稿を使用しました。

デバイスをウェイクアップするために現在使用されているコードは次のとおりです。

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の質問のコメントと投稿から、PowerManager/KeyguardManagerコードがうまくいくはずだったようです。繰り返しますが、前に述べたように、デバイスが USB 経由で開発マシンに接続されている間は技術的に機能しますが、デバイスが分離されている間はまったく何もしません。

また、これは私たちの最初の Android アプリケーションであるため、私たちがやろうとしていることから完全に外れている可能性があることを十分に認識しています。どんな提案でも大歓迎です。

要するに、上記のコードを考えると、デバイスがプラグインされているかどうかに基づいて動作が大きく異なるのはなぜでしょうか? また、デバイスをウェイクアップしてロックを解除するには、何を変更すればよいのでしょうか? よろしくお願いいたします。

4

1 に答える 1

60

問題を解決しました。デバイスが USB 経由で接続されたときに異なる動作が観察された理由は、デバイスの CPU がスリープ状態にならなかったためです。これは、デバッグ モード設定の結果であるか、CPU スリープの省電力機能が無関係であるため、コンピュータに接続したときの動作の単純な結果であると思います。明らかに、デバイスが接続されていない場合、CPU は喜んで仮眠を取り、アプリケーションがランダムに実行されていることを観察しましたが (アプリケーションはランダムな時間にウェイクアップします)、タイミングは一貫していません。さらに、これは、発生した少数の CPU サイクルが控えめに割り当てられているためであり、アプリケーションには「ランダムな」時間に非常に少数のサイクルが与えられるためだと思います。

したがって、私たちの解決策は、デバイスがバックグラウンドになったときに部分的な wake lock を取得し (これはメソッドで行われます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();
}
于 2013-02-07T17:24:03.347 に答える