Skip to content

Commit 16b6967

Browse files
Merge branch 'main' into ea_profilingmanager_v2_docs_snippets
2 parents a4309ce + a015aef commit 16b6967

File tree

6 files changed

+566
-1
lines changed

6 files changed

+566
-1
lines changed

wear/src/main/AndroidManifest.xml

Lines changed: 32 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"/>
@@ -345,6 +346,36 @@
345346
<!-- [END android_wear_complication_intent_filter] -->
346347
</activity>
347348

349+
<service
350+
android:name=".snippets.m3.tile.StateTile"
351+
android:label="@string/tile_label"
352+
android:description="@string/tile_description"
353+
android:icon="@mipmap/ic_launcher"
354+
android:exported="true"
355+
android:permission="com.google.android.wearable.permission.BIND_TILE_PROVIDER">
356+
<intent-filter>
357+
<action android:name="androidx.wear.tiles.action.BIND_TILE_PROVIDER" />
358+
</intent-filter>
359+
360+
<meta-data android:name="androidx.wear.tiles.PREVIEW"
361+
android:resource="@drawable/tile_preview" />
362+
</service>
363+
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+
348379
</application>
349380

350381
</manifest>
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
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.content.Context
20+
import android.graphics.Bitmap
21+
import android.graphics.BitmapFactory
22+
import androidx.activity.ComponentActivity
23+
import com.example.wear.R
24+
import com.google.android.gms.tasks.Task
25+
import com.google.android.gms.tasks.Tasks
26+
import com.google.android.gms.wearable.Asset
27+
import com.google.android.gms.wearable.DataClient
28+
import com.google.android.gms.wearable.DataEvent
29+
import com.google.android.gms.wearable.DataEventBuffer
30+
import com.google.android.gms.wearable.DataItem
31+
import com.google.android.gms.wearable.DataMapItem
32+
import com.google.android.gms.wearable.PutDataMapRequest
33+
import com.google.android.gms.wearable.PutDataRequest
34+
import com.google.android.gms.wearable.Wearable
35+
import java.io.ByteArrayOutputStream
36+
import java.io.InputStream
37+
38+
class DataLayerActivity : ComponentActivity(), DataClient.OnDataChangedListener {
39+
private val dataClient by lazy { Wearable.getDataClient(this) }
40+
private val messageClient by lazy { Wearable.getMessageClient(this) }
41+
private val capabilityClient by lazy { Wearable.getCapabilityClient(this) }
42+
43+
private var count = 0
44+
45+
override fun onResume() {
46+
super.onResume()
47+
Wearable.getDataClient(this).addListener(this)
48+
}
49+
50+
override fun onPause() {
51+
super.onPause()
52+
Wearable.getDataClient(this).removeListener(this)
53+
}
54+
55+
// [START android_wear_datalayer_increasecounter]
56+
private fun increaseCounter() {
57+
val putDataReq: PutDataRequest = PutDataMapRequest.create("/count").run {
58+
dataMap.putInt(COUNT_KEY, count++)
59+
asPutDataRequest()
60+
}
61+
val putDataTask: Task<DataItem> = dataClient.putDataItem(putDataReq)
62+
}
63+
// [END android_wear_datalayer_increasecounter]
64+
65+
// [START android_wear_datalayer_ondatachangedlistener]
66+
override fun onDataChanged(dataEvents: DataEventBuffer) {
67+
68+
dataEvents.forEach { event ->
69+
// DataItem changed
70+
if (event.type == DataEvent.TYPE_CHANGED) {
71+
event.dataItem.also { item ->
72+
if (item.uri.path?.compareTo("/count") == 0) {
73+
DataMapItem.fromDataItem(item).dataMap.apply {
74+
updateCount(getInt(COUNT_KEY))
75+
}
76+
}
77+
}
78+
} else if (event.type == DataEvent.TYPE_DELETED) {
79+
// DataItem deleted
80+
}
81+
}
82+
}
83+
// [END android_wear_datalayer_ondatachangedlistener]
84+
85+
private fun updateCount(int: Int) {
86+
}
87+
companion object {
88+
private const val COUNT_KEY = "com.example.key.count"
89+
}
90+
}
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)