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

Walking with Awareness API

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
Avatar for Naoki Ishii Naoki Ishii
January 11, 2018

Walking with Awareness API

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

Avatar for Naoki Ishii

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自体の挙動確認は、ヘッドホンのイベントを使うと 楽です(プラグの抜き差しでイベントが発生するため)