ottoとActivityRecognition
ottoな勉強をするにあたってそういう要件が必要にならないと例にならない気がしたので、ActivityRecognitionを使って行動認識をActivityへottoを使って通知する仕組み的な事やってみた
記事下部に参考を書くと分かりづらいので以下を参考にした
参考1: Google I/O 2013 で発表された行動認識(Activity Recognition)を使ってみる (※この例だとBroadcastReceiverで受け取ってる)
参考2: Recognizing the User's Current Activity
ottoに関しては公式なドキュメント辺りを参照
プロジェクトの準備
ActivityRecognitionはGoogle Play Serviceなライブラリプロジェクトに含まれているのでAndroid Package Managerを使ってEclipseにプロジェクトをインポートする。で端末が古いのでGoogle Play Serviceのfroyoサポート辺りを使った。何やら最近のGoogle Play Serviceでは
<application>
<meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
</application>
的な所が必要らしい。どうやらバージョンチェックをしているんだろうとは思うのだけど。それはおいといて
あとはottoのライブラリはダウンロードしてくるかビルドするかのどっちかをやってアプリプロジェクトのlibsに入れておけば良い
AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="sample.test"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="8" android:targetSdkVersion="17" />
<uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".RecognitionIntentService" android:exported="false" />
</application>
</manifest>
RecognitionIntentService.java
package sample.test;
import com.google.android.gms.location.ActivityRecognitionResult;
import com.google.android.gms.location.DetectedActivity;
import android.app.IntentService;
import android.content.Intent;
import android.util.Log;
public class RecognitionIntentService extends IntentService {
private static final String TAG = RecognitionIntentService.class.getName();
public RecognitionIntentService() {
super("RecognitionIntentService");
}
@Override
protected void onHandleIntent(Intent intent) {
Log.v(TAG, "onHandleIntent");
if (!ActivityRecognitionResult.hasResult(intent))
return;
ActivityRecognitionResult result = ActivityRecognitionResult.extractResult(intent);
DetectedActivity mostProbableActiity = result.getMostProbableActivity();
// Activityで@Subscribeしているイベントバスにプッシュ
BusProvider.getInstance().post(
new RecognitionEvent(getTypeName(mostProbableActiity.getType()))
);
}
private String getTypeName(int type) {
switch (type) {
case DetectedActivity.IN_VEHICLE:
return "in_vehicle";
case DetectedActivity.ON_BICYCLE:
return "on_bicycle";
case DetectedActivity.ON_FOOT:
return "on_foot";
case DetectedActivity.STILL:
return "still";
case DetectedActivity.UNKNOWN:
return "unknown";
case DetectedActivity.TILTING:
return "tilting";
}
return "unknown";
}
}
DetectedActivity#getTypeの返り値は公式リファレンスのSummaryセクションを参考に
BusProvider.java
package sample.test;
import com.squareup.otto.Bus;
import com.squareup.otto.ThreadEnforcer;
public class BusProvider {
// ThreadEnforcer.ANYにしないとIntentServiceとかみたいなメインスレッドkらでは無い場合だとエラーになる
private static Bus bus = new Bus(ThreadEnforcer.ANY);
private BusProvider() {
}
public static Bus getInstance() {
return bus;
}
}
MainActivity.java
package sample.test;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesClient.ConnectionCallbacks;
import com.google.android.gms.common.GooglePlayServicesClient.OnConnectionFailedListener;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.location.ActivityRecognitionClient;
import com.squareup.otto.Subscribe;
public class MainActivity extends Activity
implements ConnectionCallbacks, OnConnectionFailedListener {
private static final String TAG = MainActivity.class.getName();
ActivityRecognitionClient mActivityRecognitionClient;
PendingIntent mPendingIntent;
@Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
BusProvider.getInstance().register(this);
mActivityRecognitionClient = new ActivityRecognitionClient(
this,
this, // ConnectionCallbacks
this // OnConnectionFailedListener
);
mActivityRecognitionClient.connect();
}
@Override
protected void onPause() {
super.onPause();
Log.v(TAG, "onPause");
onDisconnected();
}
@Override
public void onConnected(Bundle connectionHint) {
Log.v(TAG, "onConnected");
mPendingIntent = PendingIntent.getService(
this,
0,
new Intent(this, RecognitionIntentService.class),
PendingIntent.FLAG_UPDATE_CURRENT
);
mActivityRecognitionClient.requestActivityUpdates(3000, mPendingIntent);
}
@Override
public void onDisconnected() {
Log.v(TAG, "onDisconnected");
if (mActivityRecognitionClient != null) {
mActivityRecognitionClient.removeActivityUpdates(mPendingIntent);
mActivityRecognitionClient.disconnect();
mActivityRecognitionClient = null;
}
}
@Override
public void onConnectionFailed(ConnectionResult result) {
Log.v(TAG, "onConnectionFailed");
}
@Subscribe
public void onRecognitionEvent(RecognitionEvent event) {
Log.v(TAG, "onRecognitionEvent");
Log.v(TAG, "eventName: " + event.getEventName());
}
}
ざっくり書いてるけど、開始したらまずBusをregister。それをする事でpostされたイベントを@Subscribeアノテーションなメソッドを受け取れる的な感じかと。ようはAcitvityRecognitionでアップデート通知されたらRecognitionIntentService#onHandleIntentが発生して、その結果がBusを通じてActivityにイベントがpushされる
んまぁんな感じでottoとActivityRecognitionの適当にやってみた