Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Walking with Awareness API

Naoki Ishii
January 11, 2018

Walking with Awareness API

Awareness APIを使ってみました。
https://developers.google.com/awareness/

Naoki Ishii

January 11, 2018
Tweet

More Decks by Naoki Ishii

Other Decks in Technology

Transcript

  1. Awareness APIとは ▣ Google I/O 2016で発表 ▣ GooglePlayServices ▣ ユーザーの周囲の状況

    (Context)に合わせた機能 を1つのAPIで簡単に提供で きる ▣ Contextは7種類
  2. Fence API - 登録 val duringWalkFence: AwarenessFence = DetectedActivityFence.during(DetectedActivityFence.ON_FOOT) val

    headphoneFence: AwarenessFence = HeadphoneFence.during(HeadphoneState.PLUGGED_IN) Awareness.getFenceClient(this) .updateFences( FenceUpdateRequest.Builder() .addFence(COMBINED_FENCE_KEY, combinedFence, FenceReceiver.createPendingIntent(this)) .build()) .addOnSuccessListener { Log.d(TAG, "Fence was successfully registered.") } .addOnFailureListener { Log.d(TAG, "Fence could not be registered.") } val combinedFence: AwarenessFence = AwarenessFence.and(duringWalkFence, headphoneFence)
  3. Fence API - Receiver override fun onReceive(context: Context?, intent: Intent?)

    { val fenceState = FenceState.extract(intent) if (fenceState.fenceKey == COMBINED_FENCE_KEY && fenceState.currentState == FenceState.TRUE) { // Walking with headphone showNotification(context) } } FenceState = TRUE, FALSE, UNKNOWN FenceStateに変更があった時に broadcast通知がくる (Fence条件を満たした時だけではない ) 初回登録時 : UNKNOWN → FALSE or TRUE 条件を満たした時 : FALSE → TRUE 条件を満たさなくなった時 : TRUE → FALSE
  4. Snapshot API Awareness.getSnapshotClient(this).weather .addOnSuccessListener { weatherResponse -> Log.d(TAG, "current weather

    is ${weatherResponse.weather}") } Awareness.getSnapshotClient(this).places .addOnSuccessListener { placesResponse -> placesResponse.placeLikelihoods.forEach { Log.d(TAG, "place found : ${it.place.name}") } }
  5. 発表以降のアップデート 2017/2 version10.2, 11.0 Timeのアップデート • Time Instant(時間の瞬間)の追加 ◦ Sunrise,

    Sunset ◦ Fence API, aroundTimeInstantでFenceを登録可能 • Time Interval(時間の間隔)にsemantic timeの追加 ◦ 時間帯 : MORNING, AFTERNOON, NIGHT.. ◦ 曜日: WEEKDAY, WEEKEND, HOLIDAY ◦ Fence API, inTimeIntervalでFenceを登録可能 ◦ Snapshot API, getTimeIntervalsで今のIntervalを取得可能
  6. 発表以降のアップデート 2017/2 version11.4.0〜 ▣ Google Api Clientの使用方法変更 □ GoogleApiClient経由でのGooglePlayサービス接続の手 動管理が不要に

    ・参考 : 新しい Location API で負荷を軽減   https://developers-jp.googleblog.com/2017/07/reduce-friction-with-new-location-apis.html ▣ FenceApi/SnapshotApiがdeprecatedに ▣ FenceClient/SnapshotClientを使う
  7. 課題 バッテリー消費を(そんなに)意識できていない Google I/O 2016 Introducing the Awareness API, an

    easy way to make your apps context aware より GeoFenceとActivityRecgnitionの組み合わせ どちらを先に起動させたほうがバッテリー消費が少 ないかは難しい問題
  8. AwarenessAPIを使った実装 val morningFence: AwarenessFence = TimeFence.inDailyInterval(TimeZone.getDefault(), TimeUnit.HOURS.toMillis(7), TimeUnit.HOURS.toMillis(10)) val stationFence:

    AwarenessFence = LocationFence.`in`(station.lat, station.lon, config.geoFenceRadius.toDouble(), 0L) val duringWalkFence: AwarenessFence = DetectedActivityFence.during(DetectedActivityFence.ON_FOOT) val combinedFence: AwarenessFence = AwarenessFence.and(morningFence, stationFence, duringWalkFence) Awareness.getFenceClient(this) .updateFences(FenceUpdateRequest.Builder() .addFence(COMBINED_FENCE_KEY, combinedFence, AwarenessCombinedReceiver.createPendingIntent(this)) .build())
  9. 登録されているFenceの確認 ▣ adbコマンドで確認できない ▣ FenceClient.queryFences ▣ FenceKeyとFenceStateを取得できる (Fence毎の具体的な設定は取得できない) Awareness.getFenceClient(this) .queryFences(FenceQueryRequest.all())

    .addOnSuccessListener { queryResponse -> queryResponse.fenceStateMap.fenceKeys.forEach { fenceKey -> val state = queryResponse.fenceStateMap.getFenceState(fenceKey) Log.d(TAG, "fenceKey/state = $fenceKey/$state") } }
  10. Awareness APIで置き換える ▣ できた ▣ 簡単 ▣ 既存と比較して精度 □ 特に問題なし

    ▣ 既存と比較してバッテリー消費 □ 調べきれませんでした。。
  11. 電車 → 徒歩の検知 ① val morningFence: AwarenessFence = TimeFence.inDailyInterval(TimeZone.getDefault(), TimeUnit.HOURS.toMillis(7),

    TimeUnit.HOURS.toMillis(10)) val stationFence: AwarenessFence = LocationFence.`in`(station.lat, station.lon, config.geoFenceRadius.toDouble(), 0L) val stopVehicleFence: AwarenessFence = DetectedActivityFence.stopping(DetectedActivityFence.IN_VEHICLE) val startWalkingFence: AwarenessFence = DetectedActivityFence.starting(DetectedActivityFence.ON_FOOT) val combinedFence: AwarenessFence = AwarenessFence.and(morningFence, stationFence, stopVehicleFence, startWalkingFence) 失敗 DetectedActivityFence.stopping/startingは瞬間的なイベントのため、 すぐにFALSEになってしまう
  12. 電車 → 徒歩の検知 ② val morningFence: AwarenessFence = TimeFence.inDailyInterval(TimeZone.getDefault(), TimeUnit.HOURS.toMillis(7),

    TimeUnit.HOURS.toMillis(23)) val stationFence: AwarenessFence = LocationFence.`in`(station.lat, station.lon, config.geoFenceRadius.toDouble(), 0L) val duringWalkingFence: AwarenessFence = DetectedActivityFence.during(DetectedActivityFence.ON_FOOT) val combinedFence: AwarenessFence = AwarenessFence.and(morningFence, stationFence, duringWalkingFence) val stopVehicleFence: AwarenessFence = DetectedActivityFence.stopping(DetectedActivityFence.IN_VEHICLE) 朝、駅周辺、歩いていたら の合成Fence 乗り物から降りた のFence
  13. override fun onReceive(context: Context?, intent: Intent?) { val fenceState =

    FenceState.extract(intent) if (fenceState.fenceKey == AwarenessOneWalkService.COMBINED_FENCE_KEY && fenceState.currentState == FenceState.TRUE) { Awareness.getFenceClient(context).queryFences( FenceQueryRequest.forFences(AwarenessOneWalkService.STOP_VEHICLE_FENCE_KEY)) .addOnSuccessListener { fenceQueryResponse -> val stopVehicleState = fenceQueryResponse.fenceStateMap .getFenceState(AwarenessOneWalkService.STOP_VEHICLE_FENCE_KEY) val diffSeconds = TimeUnit.MILLISECONDS.toSeconds( System.currentTimeMillis() - stopVehicleState.lastFenceUpdateTimeMillis) if (stopVehicleState.currentState == FenceState.FALSE && stopVehicleState.previousState == FenceState.TRUE && diffSeconds <= 60) { // train to walk } } } } 「朝、駅周辺、歩いている」という通知を受けたあとに、 「乗り物から降りた」という Fenceの状態を取ってきて、 60秒以内にそのイベントが起こっていたら、乗り物から徒歩 への遷移が起こった
  14. 電車 → 徒歩の検知 ② ▣ できた ▣ ちょっと複雑 ▣ Awareness

    APIという1つのAPIで色々なContextを 取り扱えるため、試行錯誤がしやすい
  15. まとめ ▣ 周囲の状況を複数組み合わせた処理が楽にできる ▣ 条件を変更して試行錯誤が容易 ▣ バッテリー消費の最適化もよしなにやってくれる ▣ Fence設定の確認が少ししづらい ▣

    便利! ▣ 追記: □ 動作確認は実際に歩いて行いました □ AwarenessAPI自体の挙動確認は、ヘッドホンのイベントを使うと 楽です(プラグの抜き差しでイベントが発生するため)