Skip to content

Commit afe04dd

Browse files
Snippets for /training/wearables/tiles/dynamic (#695)
1 parent c3472d3 commit afe04dd

File tree

2 files changed

+114
-0
lines changed

2 files changed

+114
-0
lines changed

wear/src/main/AndroidManifest.xml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,21 @@
345345
<!-- [END android_wear_complication_intent_filter] -->
346346
</activity>
347347

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

350365
</manifest>

wear/src/main/java/com/example/wear/snippets/m3/tile/Tile.kt

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,29 @@
1717
package com.example.wear.snippets.m3.tile
1818

1919
import android.content.Context
20+
import androidx.wear.protolayout.LayoutElementBuilders
21+
import androidx.wear.protolayout.LayoutElementBuilders.Column
2022
import androidx.wear.protolayout.ResourceBuilders.Resources
23+
import androidx.wear.protolayout.StateBuilders
2124
import androidx.wear.protolayout.TimelineBuilders.Timeline
25+
import androidx.wear.protolayout.expression.DynamicBuilders
26+
import androidx.wear.protolayout.expression.dynamicDataMapOf
27+
import androidx.wear.protolayout.expression.intAppDataKey
28+
import androidx.wear.protolayout.expression.mapTo
29+
import androidx.wear.protolayout.expression.stringAppDataKey
2230
import androidx.wear.protolayout.material3.MaterialScope
2331
import androidx.wear.protolayout.material3.Typography.BODY_LARGE
32+
import androidx.wear.protolayout.material3.Typography.BODY_MEDIUM
2433
import androidx.wear.protolayout.material3.button
2534
import androidx.wear.protolayout.material3.buttonGroup
2635
import androidx.wear.protolayout.material3.materialScope
2736
import androidx.wear.protolayout.material3.primaryLayout
2837
import androidx.wear.protolayout.material3.text
38+
import androidx.wear.protolayout.material3.textButton
2939
import androidx.wear.protolayout.modifiers.clickable
40+
import androidx.wear.protolayout.modifiers.loadAction
41+
import androidx.wear.protolayout.types.asLayoutConstraint
42+
import androidx.wear.protolayout.types.asLayoutString
3043
import androidx.wear.protolayout.types.layoutString
3144
import androidx.wear.tiles.RequestBuilders
3245
import androidx.wear.tiles.RequestBuilders.ResourcesRequest
@@ -37,6 +50,7 @@ import androidx.wear.tiles.tooling.preview.TilePreviewData
3750
import androidx.wear.tiles.tooling.preview.TilePreviewHelper
3851
import androidx.wear.tooling.preview.devices.WearDevices
3952
import com.google.common.util.concurrent.Futures
53+
import com.google.common.util.concurrent.ListenableFuture
4054

4155
private const val RESOURCES_VERSION = "1"
4256

@@ -139,3 +153,88 @@ fun smallPreview(context: Context) = TilePreviewData {
139153
.build()
140154
}
141155
// [END android_wear_tile_preview]
156+
157+
class StateTile : TileService() {
158+
// [START android_wear_tile_dynamic_ontilerequest]
159+
override fun onTileRequest(
160+
requestParams: RequestBuilders.TileRequest
161+
): ListenableFuture<Tile?> {
162+
// If the tile hasn't had any state set yet, use the default values
163+
val state =
164+
if (requestParams.currentState.keyToValueMapping.isNotEmpty())
165+
requestParams.currentState
166+
else
167+
StateBuilders.State.Builder()
168+
.setStateMap(
169+
dynamicDataMapOf(
170+
KEY_WATER_INTAKE mapTo 200,
171+
KEY_NOTE mapTo "Good"
172+
)
173+
)
174+
.build()
175+
176+
return Futures.immediateFuture(
177+
Tile.Builder()
178+
// Set resources, timeline, and other tile properties.
179+
// [START_EXCLUDE silent]
180+
.setTileTimeline(
181+
Timeline.fromLayoutElement(
182+
materialScope(this, requestParams.deviceConfiguration) {
183+
tileLayout()
184+
}
185+
)
186+
)
187+
// [END_EXCLUDE]
188+
.setState(state)
189+
.build()
190+
)
191+
}
192+
// [END android_wear_tile_dynamic_ontilerequest]
193+
194+
fun MaterialScope.tileLayout(): LayoutElementBuilders.LayoutElement {
195+
return primaryLayout(
196+
mainSlot = {
197+
// [START android_wear_tile_dynamic_showdata]
198+
val waterIntakeValue =
199+
DynamicBuilders.DynamicInt32.from(KEY_WATER_INTAKE)
200+
// [END android_wear_tile_dynamic_showdata]
201+
.format()
202+
.asLayoutString("0", "000".asLayoutConstraint())
203+
val noteValue =
204+
DynamicBuilders.DynamicString.from(KEY_NOTE)
205+
.asLayoutString(
206+
"",
207+
"Note about day".asLayoutConstraint()
208+
)
209+
210+
// [START android_wear_tile_dynamic_loadaction]
211+
val loadAction =
212+
loadAction(
213+
dynamicDataMapOf(
214+
KEY_WATER_INTAKE mapTo 400,
215+
KEY_NOTE mapTo "Outstanding"
216+
)
217+
)
218+
// [END android_wear_tile_dynamic_loadaction]
219+
220+
Column.Builder()
221+
.addContent(text(waterIntakeValue, typography = BODY_LARGE))
222+
.addContent(text(noteValue, typography = BODY_MEDIUM))
223+
.addContent(
224+
textButton(
225+
onClick = clickable(loadAction),
226+
labelContent = { text("Load".layoutString) }
227+
)
228+
)
229+
.build()
230+
}
231+
)
232+
}
233+
234+
// [START android_wear_tile_dynamic_companion]
235+
companion object {
236+
val KEY_WATER_INTAKE = intAppDataKey("key_water_intake")
237+
val KEY_NOTE = stringAppDataKey("key_note")
238+
}
239+
// [END android_wear_tile_dynamic_companion]
240+
}

0 commit comments

Comments
 (0)