起きろ!…起きろってば!(深い眠りに入ったアプリを叩き起こす)

カメラに、タイマーとSMS着信で撮影する機能をつけてみた。

SMS着信からの撮影は問題なかったが、意外にも、タイマーでの撮影がうまくかない。deep sleep に入ったときに反応しなくなってしまう。

まずは、セルフタイマーカメラで使用したCountDownTimerを使用してみた。Debugしているとき、つまりUSBでPCと接続しているときはほぼ正常に動いていたが、PCから離して単体で動かすと、長い時間動かしているうちにタイマーが反応しなくなってしまう。イベントはキューにたまってるようで、デバイスに触ったり、なにかのタイミングで急に動き出すが、たまっていた分を一度に実行しようとしてプログラムは落ちてしまう。

なにか別の手段を考えないといけない。deep sleep で検索して、まずは以下を参照。

http://developer.android.com/reference/android/os/SystemClock.html

ACTION_TIME_TICK を listen する方法かあるようだ。Receiver を使うので SMS の受信の仕組みと同じ。SMS の受信はスリープ時でも動いているので、これなら大丈夫かと思ったが、試してみたらだめだった。SMS の Receiver と同じように PackageManager.setComponentEnabledSetting() で Receiver を DONT_KILL_APP に設定してもだめだった。

スリープから覚めた途端にキューにたまった分を実行し始めるので。もしかするとタイマーは動いているが、その先の処理がとまっているだけかもしれない、と考え、タイマー処理で PowerManager で WakeLock してみる。しかしだめだった。起動から終了まで PowerManager で WakeLock をかけたままにする方法もあるが、これでは、スリープに入るのを防ぐことはできるが、これではバッテリーが持たないろう。タイマーで動作させる意味が無い。

もう一度 SystemClock の説明を読み返してみると、AlermManager なら deep sleep でも動作すると書いてある。なるほど、確かにアラームはスリープ状態でも決まった時間に動作する。これならきっと大丈夫だ。

        AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
        Intent intent = new Intent(this, <起動させたいComponentのClass>);
        PendingIntent pi = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
        am.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + <間隔(ミリ秒)>, <間隔(ミリ秒)>, pi);

AlarmManager.setInexactRepeating() の2番目の引数は、最初に起動する時刻を指定するが、最初の引数で指定した方法で指定しなければならない。この例だと elapsedRealtime を使って指定する。 Time.toMills() で得られる値とは異なる。また、あとでキャンセルするためには、指定した PendingIntent の参照が必要。

この方法で、deep sleep に入ったときでも起動できるようになった。

これで、タイマーまたはSMSを受信したタイミングで、カメラで画像を撮影し、Picasa へのアップロードを行うアプリができた。(→ダウンロード

コメントを残す

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください