Skip to content

Commit 89b0781

Browse files
Add snippets for /training/wearables/data/{sync,events} (#697)
* Add snippets for /training/wearables/data/sync * Fix file location * Snippets for /training/wearables/data/events
1 parent afe04dd commit 89b0781

File tree

3 files changed

+175
-2
lines changed

3 files changed

+175
-2
lines changed

wear/src/main/AndroidManifest.xml

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
See the License for the specific language governing permissions and
1515
limitations under the License.
1616
-->
17-
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
17+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
18+
xmlns:tools="http://schemas.android.com/tools">
1819

1920
<uses-permission android:name="android.permission.WAKE_LOCK" />
2021
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
@@ -360,6 +361,21 @@
360361
android:resource="@drawable/tile_preview" />
361362
</service>
362363

364+
<!-- [START android_wear_datalayerlistener_intent_filter] -->
365+
<service
366+
android:name=".snippets.datalayer.DataLayerListenerService"
367+
android:exported="true"
368+
tools:ignore="ExportedService" >
369+
<intent-filter>
370+
<action android:name="com.google.android.gms.wearable.DATA_CHANGED" />
371+
<data
372+
android:scheme="wear"
373+
android:host="*"
374+
android:path="/start-activity" />
375+
</intent-filter>
376+
</service>
377+
<!-- [END android_wear_datalayerlistener_intent_filter] -->
378+
363379
</application>
364380

365381
</manifest>
Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,16 @@
1414
* limitations under the License.
1515
*/
1616

17-
package com.example.wear.snippets.com.example.wear.snippets.datalayer
17+
package com.example.wear.snippets.datalayer
1818

19+
import android.content.Context
20+
import android.graphics.Bitmap
21+
import android.graphics.BitmapFactory
1922
import androidx.activity.ComponentActivity
23+
import com.example.wear.R
2024
import com.google.android.gms.tasks.Task
25+
import com.google.android.gms.tasks.Tasks
26+
import com.google.android.gms.wearable.Asset
2127
import com.google.android.gms.wearable.DataClient
2228
import com.google.android.gms.wearable.DataEvent
2329
import com.google.android.gms.wearable.DataEventBuffer
@@ -26,6 +32,8 @@ import com.google.android.gms.wearable.DataMapItem
2632
import com.google.android.gms.wearable.PutDataMapRequest
2733
import com.google.android.gms.wearable.PutDataRequest
2834
import com.google.android.gms.wearable.Wearable
35+
import java.io.ByteArrayOutputStream
36+
import java.io.InputStream
2937

3038
class DataLayerActivity : ComponentActivity(), DataClient.OnDataChangedListener {
3139
private val dataClient by lazy { Wearable.getDataClient(this) }
@@ -80,3 +88,68 @@ class DataLayerActivity : ComponentActivity(), DataClient.OnDataChangedListener
8088
private const val COUNT_KEY = "com.example.key.count"
8189
}
8290
}
91+
92+
// [START android_wear_sync_createasset]
93+
private fun createAssetFromBitmap(bitmap: Bitmap): Asset =
94+
ByteArrayOutputStream().let { byteStream ->
95+
bitmap.compress(Bitmap.CompressFormat.PNG, 100, byteStream)
96+
Asset.createFromBytes(byteStream.toByteArray())
97+
}
98+
// [END android_wear_sync_createasset]
99+
100+
// [START android_wear_datalayer_imageputdata]
101+
private fun Context.sendImagePutDataRequest(): Task<DataItem> {
102+
103+
val asset: Asset = createAssetFromBitmap(BitmapFactory.decodeResource(resources, R.drawable.ic_walk))
104+
val request: PutDataRequest = PutDataRequest.create("/image").apply {
105+
putAsset("profileImage", asset)
106+
}
107+
val putTask: Task<DataItem> = Wearable.getDataClient(this).putDataItem(request)
108+
109+
return putTask
110+
}
111+
// [END android_wear_datalayer_imageputdata]
112+
113+
// [START android_wear_datalayer_imageputdatamap]
114+
private fun Context.sendImagePutDataMapRequest(): Task<DataItem> {
115+
116+
val asset: Asset = createAssetFromBitmap(BitmapFactory.decodeResource(resources, R.drawable.ic_walk))
117+
val request: PutDataRequest = PutDataMapRequest.create("/image").run {
118+
dataMap.putAsset("profileImage", asset)
119+
asPutDataRequest()
120+
}
121+
val putTask: Task<DataItem> = Wearable.getDataClient(this).putDataItem(request)
122+
123+
return putTask
124+
}
125+
// [END android_wear_datalayer_imageputdatamap]
126+
127+
class DataLayerActivity2 : ComponentActivity(), DataClient.OnDataChangedListener {
128+
// [START android_wear_datalayer_ondatachanged_assetextract]
129+
override fun onDataChanged(dataEvents: DataEventBuffer) {
130+
dataEvents
131+
.filter { it.type == DataEvent.TYPE_CHANGED && it.dataItem.uri.path == "/image" }
132+
.forEach { event ->
133+
val bitmap: Bitmap? = DataMapItem.fromDataItem(event.dataItem)
134+
.dataMap.getAsset("profileImage")
135+
?.let { asset -> loadBitmapFromAsset(asset) }
136+
// Do something with the bitmap
137+
}
138+
}
139+
140+
fun loadBitmapFromAsset(asset: Asset): Bitmap? {
141+
// Convert asset into a file descriptor and block until it's ready
142+
val assetInputStream: InputStream? =
143+
Tasks.await(Wearable.getDataClient(this).getFdForAsset(asset))
144+
?.inputStream
145+
146+
return assetInputStream?.let { inputStream ->
147+
// Decode the stream into a bitmap
148+
BitmapFactory.decodeStream(inputStream)
149+
} ?: run {
150+
// Requested an unknown asset
151+
null
152+
}
153+
}
154+
// [END android_wear_datalayer_ondatachanged_assetextract]
155+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/*
2+
* Copyright 2025 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.example.wear.snippets.datalayer
18+
19+
import android.app.Activity
20+
import android.util.Log
21+
import com.google.android.gms.wearable.DataClient
22+
import com.google.android.gms.wearable.DataEvent
23+
import com.google.android.gms.wearable.DataEventBuffer
24+
import com.google.android.gms.wearable.Wearable
25+
import com.google.android.gms.wearable.WearableListenerService
26+
27+
private const val TAG = "DataLayerSample"
28+
private const val START_ACTIVITY_PATH = "/start-activity"
29+
private const val DATA_ITEM_RECEIVED_PATH = "/data-item-received"
30+
31+
// [START android_wear_datalayer_datalayerlistenerservice]
32+
class DataLayerListenerService : WearableListenerService() {
33+
34+
override fun onDataChanged(dataEvents: DataEventBuffer) {
35+
if (Log.isLoggable(TAG, Log.DEBUG)) {
36+
Log.d(TAG, "onDataChanged: $dataEvents")
37+
}
38+
39+
// Loop through the events and send a message
40+
// to the node that created the data item.
41+
dataEvents
42+
.map { it.dataItem.uri }
43+
.forEach { uri ->
44+
// Get the node ID from the host value of the URI.
45+
val nodeId: String = uri.host!!
46+
// Set the data of the message to be the bytes of the URI.
47+
val payload: ByteArray = uri.toString().toByteArray()
48+
49+
// Send the RPC.
50+
Wearable.getMessageClient(this)
51+
.sendMessage(
52+
nodeId,
53+
DATA_ITEM_RECEIVED_PATH,
54+
payload
55+
)
56+
}
57+
}
58+
}
59+
// [END android_wear_datalayer_datalayerlistenerservice]
60+
61+
// [START android_wear_datalayer_ondatachangedlisteneer]
62+
class MainActivity : Activity(), DataClient.OnDataChangedListener {
63+
64+
public override fun onResume() {
65+
super.onResume()
66+
Wearable.getDataClient(this).addListener(this)
67+
}
68+
69+
override fun onPause() {
70+
super.onPause()
71+
Wearable.getDataClient(this).removeListener(this)
72+
}
73+
74+
override fun onDataChanged(dataEvents: DataEventBuffer) {
75+
dataEvents.forEach { event ->
76+
if (event.type == DataEvent.TYPE_DELETED) {
77+
Log.d(TAG, "DataItem deleted: " + event.dataItem.uri)
78+
} else if (event.type == DataEvent.TYPE_CHANGED) {
79+
Log.d(TAG, "DataItem changed: " + event.dataItem.uri)
80+
}
81+
}
82+
}
83+
}
84+
// [END android_wear_datalayer_ondatachangedlisteneer]

0 commit comments

Comments
 (0)