Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Walking with Awareness API
Search
Sponsored
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
Naoki Ishii
January 11, 2018
Technology
510
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Walking with Awareness API
Awareness APIを使ってみました。
https://developers.google.com/awareness/
Naoki Ishii
January 11, 2018
More Decks by Naoki Ishii
See All by Naoki Ishii
レンダリングしていますを改善する
iiinaiii
1
650
Other Decks in Technology
See All in Technology
enechainの内製セルフサービスプラットフォーム
hiyosi
0
160
『止めない』を設計する — 制約の中で、事業の根幹を支える判断
hiroyaterui
0
270
module Synths; end
asonas
1
130
アリアドネの糸と、20年ごとの建て替え ── 長尾真『電子図書館』を、伊勢で読み直す / Rereading Makoto Nagao’s "Electronic Library" in Ise
ykiyota
0
150
TinyGo 開発サイクルを高速化する:Go で作るエミュレータ入門
zozotech
PRO
1
620
The Agent Builder Loop from Daily Work to OSS
minorun365
PRO
3
130
あるけみー式LTスライド作成術
alchemy1115
1
180
薬剤師(ドメインエキスパート)と一緒に育てる薬局向けAIアシスタント
kakehashi
PRO
2
150
AIで実装は速くなった。なのにプロダクトは速くならない。職能の壁を越えて価値のフローを設計する
nwiizo
8
7.9k
2026-09-10 【Snowflake World Tour Tokyo 2026】dbt Core と Snowflake で実現する多層的なデータガバナンス / Multi-Layered Data Governance Powered by dbt Core and Snowflake
civitaspo
0
320
2026-09-11 【Snowflake World Tour Tokyo 2026】Snowflakeを起点に、AI Agentが自律稼働し続ける未来へ / Driving AI Agents with Snowflake
civitaspo
0
320
例外の正しい扱い方 そのエラー try-catchして大丈夫?
jinwatanabe
3
460
Featured
See All Featured
The Illustrated Guide to Node.js - THAT Conference 2024
reverentgeek
1
470
Thoughts on Productivity
jonyablonski
76
5.4k
Leveraging LLMs for student feedback in introductory data science courses - posit::conf(2025)
minecr
1
380
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
333
23k
The Director’s Chair: Orchestrating AI for Truly Effective Learning
tmiket
1
290
What’s in a name? Adding method to the madness
productmarketing
PRO
24
4.2k
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
49
3.5k
Bash Introduction
62gerente
615
220k
16th Malabo Montpellier Forum Presentation
akademiya2063
PRO
0
370
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
31
2.9k
30 Presentation Tips
portentint
PRO
1
390
コードの90%をAIが書く世界で何が待っているのか / What awaits us in a world where 90% of the code is written by AI
rkaga
63
45k
Transcript
Walking with Awareness API
自己紹介 ▣ 石井直貴 ▣ NAVITIME 2010〜 ▣ Androidアプリ開発 ▣ NAVITIME,
乗換NAVITIME
今日話すこと ▣ Awareness API概要 ▣ 既存機能を置き換えてみた ▣ まとめ
Awareness API 概要
ユーザーの周囲の状況に反応する機能 + + +
Awareness APIとは ▣ Google I/O 2016で発表 ▣ GooglePlayServices ▣ ユーザーの周囲の状況
(Context)に合わせた機能 を1つのAPIで簡単に提供で きる ▣ Contextは7種類
Contextのタイプ Time 時刻 Location 位置情報 Place Place情報、お店の種別など Activity ユーザーのアクティビティ情報( 歩いている、走っている、自
転車に乗っている等) Beacons ビーコン Headphones ヘッドホン Weather 天気
特徴 簡単 高精度 省電力
2種類のAPI Fence API ユーザーの周囲の状況に反応できるような Fenceを登録 (WeatherとPlacesはFenceを作成できない) Snapshot API 呼び出し時点での状況を取得
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)
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
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}") } }
発表以降のアップデート 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を取得可能
発表以降のアップデート 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を使う
NAVITIMEアプリ 事例
ひと駅歩こう • 混雑緩和機能の1つ • 朝、定期券区間の1駅前で降りて歩くとポイントが貯ま る
課題 機能を開始させるトリガーの処理が煩雑 ▣ 複数APIの組み合わせ □ AlarmManager, GeoFence, GoogleFit ▣ 定期実行
課題 バッテリー消費を(そんなに)意識できていない Google I/O 2016 Introducing the Awareness API, an
easy way to make your apps context aware より GeoFenceとActivityRecgnitionの組み合わせ どちらを先に起動させたほうがバッテリー消費が少 ないかは難しい問題
Awareness APIで置き換える • 7〜10時に、 • 渋谷駅周辺で、 • 歩いていること をトリガーにできれば良い。 →
TimeFence → LocationFence → DetectedActivityFence
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())
登録されている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") } }
登録されているFenceの確認 ▣ 開発用メニューに表示 ▣ 合成条件と個別の条件を表示
Awareness APIで置き換える ▣ できた ▣ 簡単 ▣ 既存と比較して精度 □ 特に問題なし
▣ 既存と比較してバッテリー消費 □ 調べきれませんでした。。
電車 → 徒歩の検知 ▣ 「ジオフェンス内で歩いていたら」 はできた ▣ 「ジオフェンス内で電車から降りて歩き 始めた」 ができるとなお良い
電車 → 徒歩の検知 ① 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になってしまう
電車 → 徒歩の検知 ② 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
電車 → 徒歩の検知 ② Awareness.getFenceClient(this) .updateFences(FenceUpdateRequest.Builder() .addFence(COMBINED_FENCE_KEY, combinedFence, AwarenessFenceReceiver.createPendingIntent(this)) .addFence(STOP_VEHICLE_FENCE_KEY,
stopVehicleFence, AwarenessFenceReceiver.createPendingIntent(this)) .build()) 2つのFenceを登録
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秒以内にそのイベントが起こっていたら、乗り物から徒歩 への遷移が起こった
電車 → 徒歩の検知 ② ▣ できた ▣ ちょっと複雑 ▣ Awareness
APIという1つのAPIで色々なContextを 取り扱えるため、試行錯誤がしやすい
まとめ ▣ 周囲の状況を複数組み合わせた処理が楽にできる ▣ 条件を変更して試行錯誤が容易 ▣ バッテリー消費の最適化もよしなにやってくれる ▣ Fence設定の確認が少ししづらい ▣
便利! ▣ 追記: □ 動作確認は実際に歩いて行いました □ AwarenessAPI自体の挙動確認は、ヘッドホンのイベントを使うと 楽です(プラグの抜き差しでイベントが発生するため)