こんにちは、 id:numanuma08 です。個人的に興味を持ったのでAndroidのActivity Recognition Transition API を使ってみました。
Activity Recognition Transition API とは
Google Play Serviceで利用可能なAPIでTransition APIとも呼ばれます。ユーザーのアクティビティを監視し、変更をトリガーにアプリケーションを呼び出します。
ユーザーがアクティビティを開始したときや終了したときに検出する | Android デベロッパー | Android Developers
Google Developers Japan: Activity Recognition Transition API による状況認識機能をすべてのデベロッパーに開放
ActivityRecognitionClient | Google Play services | Google Developers
スマートフォンの電池使用量を最小限にしつつ、複数のセンサーを組み合わせてユーザーの行動を検知できます。日本語で書かれたAPIガイドやCodelabもあるのでとりあえず使って見る環境はありますが、アプリに組み込むとなると色々気にしたほうが良い部分もあったので紹介します。
とりあえず使ってみる
とりあえず使ってみるにはAPIガイドを読みつつCodelabを実践するといいです。
ユーザーがアクティビティを開始したときや終了したときに検出する | Android デベロッパー | Android Developers
Activity Recognition Transition API Codelab | Android Developers
気をつけたほうがいいこと
Permissionについて
APIガイドではAndroidManifestに定義するPermissionがcom.google.android.gms.permission.ACTIVITY_RECOGNITION
のみですが実際にはSDK 29以上ではandroid.permission.ACTIVITY_RECOGNITION
の定義も必要です。android.permission.ACTIVITY_RECOGNITION
はRuntime PermissionなのでAPI呼び出し前にcheckSelfPermission
やrequestPermission
が必須です。この辺りの詳しい情報はGoogle Fitに関するドキュメント内にありました。
Android の権限 | Google Fit | Google Developers
ActivityTransitionResult内のデータについて
Transition APIの結果はIntentで通知されるため、Intentをハンドルできるコンポーネントでデータ取得を行います。一般に、BroadcastReceiverやServiceが利用されると思います。Intent内のデータに含まれるActivityTransitionResult
は検知されたActivityを配列transitionEvents
に格納しています。
私は最初、アクティビティの検知結果がなぜ配列になるのか理解できませんでした。APIガイドには次のように説明があります。
イベントは時系列順に並べられます。たとえば、アプリが IN_VEHICLE アクティビティ タイプを対象に ACTIVITY_TRANSITION_ENTER 遷移と ACTIVITY_TRANSITION_EXIT 遷移に関するリクエストを行っていた場合、ユーザーが自動車の運転を開始したときに ActivityTransitionEvent オブジェクトを受け取り、ユーザーが他のアクティビティに遷移したときにもう 1 つオブジェクトを受け取ります。
この文章を読んでも理解できなかったのですが、実際にAPIを使ってみるとわかりました。例えば、IN_VEHICLE
のACTIVITY_TRANSITION_ENTER
とACTIVITY_TRANSITION_EXIT
そしてWALING
のACTIVITY_TRANSITION_ENTER
とACTIVITY_TRANSITION_EXIT
をリクエストしていると次のように呼び出しが発生します。
- ユーザーが歩き始める → transitionType: WALKING, activityType: ACTIVITY_TRANSITION_ENTER
- ユーザーが歩くのをやめる → transitionType: WALKING, activityType: ACTIVITY_TRANSITION_EXIT
- ユーザーが運転を開始する → transitionType: IN_VEHICLE, activityType: ACTIVITY_TRANSITION_ENTER
- ユーザーが運転をやめて歩きだす → [transitionType: IN_VEHICLE, activityType: ACTIVITY_TRANSITION_EXIT, transitionType: WALKING, activityType: ACTIVITY_TRANSITION_ENTER]
「運転をやめて歩く」のように短い時間で発生するイベントに対しては1つのActivityTransitionResult
内に複数のActivityTransitionEvent
が含まれるようです。
イベントが検知されるまでのタイムラグについて
ユーザーがアクティビティを開始・終了してもすぐに検知イベントは発生しません。むしろ、ラグがあることで運転中の信号待ちなどをトリガーに運転終了の誤検知を防いでいるようです。体感ですが、歩きや走りの場合は開始終了がそれぞれ1分くらい遅れます。運転の場合は運転開始から1分くらい、運転終了から3分くらいしてから通知が得られました。
具体的にどれくらい遅延が発生したのかは、ActivityTransitionEvent.getElapsedRealTimeNanos
を読み取ると実際にイベントが発生したエポックタイムが取得できるようなので、この数値と通知が来た時の時間を比較したらわかるかもしれません。
デバッグ方法
Transition APIはデバッグ・テスト方法がありません。内部的には加速度センサーやジャイロセンサーを利用しているのでエミュレーターや実機を振るとカジュアルに試すことが可能です。2018年のDroidkaigiで@kakka_blog さんがセンサーの値を保存しておいてデバッグで利用する方法を紹介されていました。
20180209 DroidKaigi2018 ActivityRecognition simulation - Speaker Deck
具体的な実装方法を紹介されたブログ記事もありました。
ActivityRecognition と加速度センサーのエミュレート – ギャップロ
この辺りの手法を利用すると良いでしょう。
バックグラウンドからの起動
Codelabでは動的BroadcastReceiverでアクティビティ遷移イベントをキャッチしていましたが実際にはアプリのプロセスが終了している状態でも静的BroadcastReceiverやServiceを使ってアクティビティ遷移イベントをキャッチ可能です。イベントはシステムが発行しているので、AndroidManifestでexported=false
を宣言して問題ありません。
また、アクティビティ遷移イベントの検知を使ってフォアグラウンドサービスの起動も可能です。Sdk 32から制約が厳しくなりましたがアクティビティ遷移イベントの検知はフォアグラウンドサービスを起動可能な例外的な状況として定義されています。
フォアグラウンド サービスの起動に関する制限 | Android 12 | Android Developers
終わりに
実際に製品に組み込んで運用した経験はないのですが、私が今の段階で調査したActivity Transition APIの情報は以上です。APIが提供してくれる機能は面白く、Google Mapsのタイムライン機能はたぶんこのAPIを内部的に利用していると思います。一方で、実際に使ってみないとわからない細かい不思議なポイントもいくつかありました。もし、Activity Transition APIを使ってアプリ開発で調査している人がいましたら参考にしてください。