なんとなく実装できたぽいのでエントリ書くなど
某所向けのサンプルついでに以下な機能が両方入ってるパケジ書いちゃえ、と云々してるのですが、最初のハードルを越えれたっぽいので纏めを作成してみます。
今回実装した (できた) 機能ですが
- PreferenceActivity から kickoff されたサービスが shake を検知して Screen On する
というものです。PreferenceActivity から Service を起動するあたりは略します (サンプル作成 (2)にエントリ投入)。ちなみに現時点の実装で完璧、という位に試験ができている訳でもありませんので、そのあたりもご承知頂ければ幸いです。
最初に
センサの挙動によって shake を検知したら云々な機能を盛り込みました。とりあえず onCreate で以下。代入先は属性です。
mySensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
SensorManager 取得しておいて onStart と onDestroy で SensorEventListener の登録および登録の解除をしております。定義が以下。
private final SensorEventListener mySensorEventListener = new SensorEventListener() { @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { // TODO Auto-generated method stub } @Override public void onSensorChanged(SensorEvent event) { updateAccelParameters(event.values[0], event.values[1], event.values[2]); if ((!shakeInitiated) && isAccelerationChanged()) { shakeInitiated = true; } else if ((shakeInitiated) && isAccelerationChanged()) { executeShakeAction(); } else if ((shakeInitiated) && (!isAccelerationChanged())) { shakeInitiated = false; } } };
onSensorChanged メソドの中身はとりあえずスルーで。
登録なコードが以下です。
mySensorManager.registerListener(mySensorEventListener, mySensorManager .getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_NORMAL);
逆に登録解除なコードが以下。
mySensorManager.unregisterListener(mySensorEventListener);
これら、それぞれ登録済みかどうかのフラグを持たせてリスナとして登録済みかどうかを判断した後に、ということをしているようですが、意味があるのかどうなのか。
纏め作っててだんだん無意味な気がしてきつつあったりしてます (ぇ
これでセンサのリスンができるようになったんですが、加速度センサ云々については こちら から実装を頂戴しております。ので引用略。別途内容については精査して纏めを、と思ってますので今はご容赦下さいまし。
PowerManager 云々
shake 検知ができるようになったらば、次はそれをトリガに wakelock を云々したいのですが、ここでも色々微妙なクセがあるようです。
- PowerManager.wakeLock なオブジェクトを onCreate で取得して使い回すことができない
- それどころか Accelerometer なソレも Screen off/on な契機で取得が必要らしい
とりあえず Screen off な broadcast intent を捕まえるよう、手を入れました。receiver の定義が以下。
public BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // Check action just to be on the safe side. if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) { Log.v("shake mediator screen off","trying re-registration"); stopWatch(); startWatch(); } } };
ACTION_SCREEN_OFF な broadcast intent であれば手続きを呼び出してます。これについては別途で。そしてこの receiver を onCreate で登録してます。
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF); registerReceiver(mReceiver, filter);
onDestroy で登録解除も必要。
unregisterReceiver(mReceiver);
で、{stop,start]Watch メソドで何をしてるかというと
- PowerManager.WakeLock オブジェクトの面倒
- センサ関連の register, unregister
となります。以下、stopWatch メソドの現状。
private void stopWatch(){ mySensorManager.unregisterListener(mySensorEventListener); mWakelock = null; }
そして以下が startWatch メソドの現状です。
private void startWatch(){ mySensorManager.registerListener(mySensorEventListener, mySensorManager .getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_NORMAL); mWakelock = mPowerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE, TAG); }
これらですが、一式 github に登録してます。以下から確認可能。
仮登録版です。
もうひとつ
結局それでも Screen on にならず、試しに PowerManager.WakeLock#release を呼び出さない形にしたら Screen on になるようになりました。現状はこの影響を実機で使いつつ確認している状況です。
長く sleep してると動作が微妙です (復帰に時間がかかるなど)。
あと、shaked って Toast が出てくるのがアレです (を
追記
備忘まで。
職場からの帰り道に動作確認がてら使っていたのですが、shake に反応しなくなります。これってもしかすると SCREEN_ON_ACTION な intent があったらその間は off とけば良かったりするな、とか思ってたら当り前に存在している模様。
あと shake 判定も相当アレな気がしてきています。