### Install Splash Screen in Starting Activity Source: https://developer.android.com/training/wearables/apps/splash-screen In your starting activity (e.g., SplashScreenActivity.kt), call installSplashScreen() before super.onCreate() to set up the splash screen. ```kotlin class SplashScreenActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { installSplashScreen() super.onCreate(savedInstanceState) setContent { WearApp() } } } ``` -------------------------------- ### Enable Setup Wizard on Emulator Source: https://developer.android.com/training/wearables/apps/test-bluetooth-audio Use this command-line option to enable the setup wizard when launching an emulator, which is necessary for certain Bluetooth configurations. ```bash -append-userspace-opt androidboot.setupwizard_mode=REQUIRED ``` -------------------------------- ### Configure and Start a Workout Source: https://developer.android.com/training/wearables/health-services/active Sets up an exercise configuration including data types, goals (one-time and milestone), and GPS settings, then starts the workout asynchronously. ```kotlin const val CALORIES_THRESHOLD = 250.0 const val DISTANCE_THRESHOLD = 1_000.0 // meters suspend fun startExercise() { // Types for which we want to receive metrics. val dataTypes = setOf( DataType.HEART_RATE_BPM, DataType.CALORIES_TOTAL, DataType.DISTANCE ) // Create a one-time goal. val calorieGoal = ExerciseGoal.createOneTimeGoal( DataTypeCondition( dataType = DataType.CALORIES_TOTAL, threshold = CALORIES_THRESHOLD, comparisonType = ComparisonType.GREATER_THAN_OR_EQUAL ) ) // Create a milestone goal. To make a milestone for every kilometer, set the initial // threshold to 1km and the period to 1km. val distanceGoal = ExerciseGoal.createMilestone( condition = DataTypeCondition( dataType = DataType.DISTANCE_TOTAL, threshold = DISTANCE_THRESHOLD, comparisonType = ComparisonType.GREATER_THAN_OR_EQUAL ), period = DISTANCE_THRESHOLD ) val config = ExerciseConfig( exerciseType = ExerciseType.RUNNING, dataTypes = dataTypes, isAutoPauseAndResumeEnabled = false, isGpsEnabled = true, exerciseGoals = mutableListOf>(calorieGoal, distanceGoal) ) exerciseClient.startExerciseAsync(config).await() } ``` -------------------------------- ### Start a Workout with Goals Source: https://developer.android.com/training/wearables/health-services/active-data Configures and starts a running workout, setting a one-time calorie goal and a recurring distance milestone. Requires `ExerciseConfig` setup with desired data types and goals. ```kotlin const val CALORIES_THRESHOLD = 250.0 const val DISTANCE_THRESHOLD = 1_000.0 // meters suspend fun startExercise() { // Types for which we want to receive metrics. val dataTypes = setOf( DataType.HEART_RATE_BPM, DataType.CALORIES_TOTAL, DataType.DISTANCE ) // Create a one-time goal. val calorieGoal = ExerciseGoal.createOneTimeGoal( DataTypeCondition( dataType = DataType.CALORIES_TOTAL, threshold = CALORIES_THRESHOLD, comparisonType = ComparisonType.GREATER_THAN_OR_EQUAL ) ) // Create a milestone goal. To make a milestone for every kilometer, set the initial // threshold to 1km and the period to 1km. val distanceGoal = ExerciseGoal.createMilestone( condition = DataTypeCondition( dataType = DataType.DISTANCE_TOTAL, threshold = DISTANCE_THRESHOLD, comparisonType = ComparisonType.GREATER_THAN_OR_EQUAL ), period = DISTANCE_THRESHOLD ) val config = ExerciseConfig( exerciseType = ExerciseType.RUNNING, dataTypes = dataTypes, isAutoPauseAndResumeEnabled = false, isGpsEnabled = true, exerciseGoals = mutableListOf>(calorieGoal, distanceGoal) ) exerciseClient.startExerciseAsync(config).await() } ``` -------------------------------- ### Build and Install Bumble Source: https://developer.android.com/training/wearables/apps/test-bluetooth-audio Navigate to the Bumble directory and install its modules using pip. This prepares the Bumble project for use. ```bash cd bumble && python3 -m pip install "." ``` -------------------------------- ### Start ConfirmationActivity with Success Animation Source: https://developer.android.com/training/wearables/views/confirm Initiate the ConfirmationActivity to display a success animation after a user action. Include a message to be shown below the icon. This example uses Kotlin. ```kotlin val intent = Intent(this, ConfirmationActivity::class.java).apply { putExtra(ConfirmationActivity.EXTRA_ANIMATION_TYPE, ConfirmationActivity.SUCCESS_ANIMATION) putExtra(ConfirmationActivity.EXTRA_MESSAGE, getString(R.string.msg_sent)) } startActivity(intent) ``` -------------------------------- ### Navigation 2 NavHost Example Source: https://developer.android.com/training/wearables/compose/migrate-to-navigation3 Illustrates the structure of a Navigation 2 NavHost with composable destinations. ```kotlin SwipeDismissableNavHost(navController = navController, startDestination = "menu") { composable("menu") { GreetingScreen( onShowList = { navController.navigate("list") } ) } composable("list") { ListScreen() } } ``` -------------------------------- ### Example: Setting Default System Provider for Step Count Source: https://developer.android.com/training/wearables/wff/complication/default-provider-policy Configures the complication to use the system's step count as a fallback if no other providers are available. This example uses the STEP_COUNT system data source and assumes it provides SHORT_TEXT. ```XML ``` -------------------------------- ### Basic Activity Setup with WearableRecyclerView (Java) Source: https://developer.android.com/training/wearables/apps/lists This Java code demonstrates the basic setup for an Activity that uses a WearableRecyclerView. It shows how to set the content view to the layout containing the RecyclerView. ```Java public class MainActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } ... } ``` -------------------------------- ### Basic Activity Setup with WearableRecyclerView (Kotlin) Source: https://developer.android.com/training/wearables/apps/lists This Kotlin code demonstrates the basic setup for an Activity that uses a WearableRecyclerView. It shows how to set the content view to the layout containing the RecyclerView. ```Kotlin class MainActivity : Activity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) } ... } ``` -------------------------------- ### Navigation 3 NavDisplay Example Source: https://developer.android.com/training/wearables/compose/migrate-to-navigation3 Shows the equivalent Navigation 3 implementation using NavDisplay and the entryProvider DSL. ```kotlin NavDisplay( backStack = backStack, sceneStrategies = listOf(strategy), entryProvider = entryProvider { entry { GreetingScreen( onShowList = { backStack.add(MigrationScreen.List) } ) } entry { ListScreen() } } ) ``` -------------------------------- ### Build and Install Debug APK Source: https://developer.android.com/training/wearables/widgets/get_started Use Gradle to build and install the debug version of your application onto a connected device or emulator. ```bash ./gradlew :app:installDebug ``` -------------------------------- ### List Installed Watch Faces Source: https://developer.android.com/training/wearables/watch-face-push/wear-os-app Use listWatchFaces() to retrieve details about installed watch faces and the remaining available slots. ```kotlin val response = watchFacePushManager.listWatchFaces() val installedList = response.installedWatchFaceDetails installedList.forEach { Log.i(TAG, "Installed watchface: ${it.packageName}") } val remainingSlots = response.remainingSlotCount Log.i(TAG, "Remaining slots: $remainingSlots") ``` -------------------------------- ### Create Layout with Builder Pattern Source: https://developer.android.com/training/wearables/tiles/versioning This example shows how to construct a primary layout with a column of text elements using the traditional builder pattern. ```kotlin primaryLayout( mainSlot = { Column.Builder() .setWidth(expand()) .setHeight(expand()) .addContent(text("A".layoutString)) .addContent(text("B".layoutString)) .addContent(text("C".layoutString)) .build() } ) Versioning.kt ``` -------------------------------- ### Example Redirect URLs for Authorization Response Source: https://developer.android.com/training/wearables/apps/auth-wear These are example redirect URLs that the OAuth 2.0 server might use to send the authorization response back to the Wear OS app. ```text https://wear.googleapis.com/3p_auth/com.your.package.name?code=xyz https://wear.googleapis-cn.com/3p_auth/com.your.package.name?code=xyz ``` -------------------------------- ### Start Synthetic Walking Exercise Source: https://developer.android.com/training/wearables/health-services/synthetic-data Initiate a synthetic walking exercise to generate realistic step count, heart rate, and GPS data. ```bash # start the "walking" synthetic exercise $ adb shell am broadcast \ -a "whs.synthetic.user.START_WALKING" \ com.google.android.wearable.healthservices ``` -------------------------------- ### Time Text Formatting Examples Source: https://developer.android.com/training/wearables/wff/clock/time-text Illustrates different format strings for displaying the time in various ways, such as 12:34:56 PM. ```string hh:mm:ss ``` ```string h:mm ``` ```string hh_10 ``` ```string hh_1 ``` ```string m ``` ```string mm_10 ``` ```string mm_1 ``` ```string ss ``` ```string ss_10 ``` ```string ss_1 ``` -------------------------------- ### Add a Watch Face Source: https://developer.android.com/training/wearables/watch-face-push/wear-os-app Use addWatchFace() to install a new watch face if slots are available. Handle potential AddWatchFaceException. ```kotlin try { // Supply the validation token along with the watch face package data itself. val slot = watchFacePushManager.addWatchFace(parcelFileDescriptor, token) Log.i(TAG, "${slot.packageName} (${slot.versionCode}) added in slot ${slot.slotId}") } catch (e: WatchFacePushManager.AddWatchFaceException) { Log.e(TAG, "Something went wrong installing the watch face", e) } ``` -------------------------------- ### Ternary Operation Example Source: https://developer.android.com/training/wearables/wff/common/attributes/arithmetic-expression Demonstrates the general format for ternary operations. Supports nested operations with parentheses. ```Watch Face Format condition ? value_if_true : value_if_false ``` -------------------------------- ### Implement SwipeDismissableNavHost Source: https://developer.android.com/training/wearables/compose/navigation Use `SwipeDismissableNavHost` as the navigation host, providing the `navController` and the starting destination. This composable handles navigation between different screens. ```kotlin val navController = rememberSwipeDismissableNavController() SwipeDismissableNavHost( navController = navController, startDestination = "message_list" ) { // TODO: build navigation graph } ``` -------------------------------- ### Lottie Animation Tile Service Source: https://developer.android.com/training/wearables/tiles/animations Implement a TileService to display Lottie animations. This example shows how to set up the layout and resource mapping for a Lottie animation. ```kotlin class LottieAnimation : TileService() { val lottieResourceId = "lottie_animation" override fun onTileRequest(requestParams: RequestBuilders.TileRequest): ListenableFuture { val layout = LayoutElementBuilders.Image.Builder() .setWidth(dp(150f)) .setHeight(dp(150f)) .setResourceId(lottieResourceId) .build() return Futures.immediateFuture( Tile.Builder() .setResourcesVersion(RESOURCES_VERSION) .setTileTimeline(Timeline.fromLayoutElement(layout)) .build() ) } override fun onTileResourcesRequest( requestParams: ResourcesRequest ): ListenableFuture { val lottieImage = ResourceBuilders.ImageResource.Builder() .setAndroidLottieResourceByResId( ResourceBuilders.AndroidLottieResourceByResId.Builder(R.raw.lottie) .setStartTrigger(createOnVisibleTrigger()) .build() ) .build() return Futures.immediateFuture( Resources.Builder() .setVersion(requestParams.version) .addIdToImageMapping(lottieResourceId, lottieImage) .build() ) } } Animations.kt ``` -------------------------------- ### Setup NavDisplay and Back Stack with Swipe-to-Dismiss Strategy Source: https://developer.android.com/training/wearables/compose/navigation3 Initialize the back stack and Wear OS scene strategy, then integrate them with NavDisplay. Map NavKeys to Composables using entryProvider. ```Kotlin // 1. Create the persistent back stack starting at the Home screen val backStack = rememberNavBackStack(Screen.Home) // 2. Initialize the Wear OS swipe-to-dismiss strategy val strategy = rememberSwipeDismissableSceneStrategy() // 3. Render the NavDisplay NavDisplay( backStack = backStack, sceneStrategies = listOf(strategy), entryProvider = entryProvider { // 4. Map keys to Composables entry { HomeScreen( onNavigateToDetails = { id -> backStack.add(Screen.Details(id)) } ) } entry { key -> DetailsScreen( itemId = key.itemId, onBack = { backStack.removeAt(backStack.lastIndex) } ) } } ) Navigation.kt ``` -------------------------------- ### Variant with Animation Timing Source: https://developer.android.com/training/wearables/wff/common/variant/variant Example of using the Variant element to animate attribute changes with specified start offset and duration for transitions between display modes. ```xml ``` -------------------------------- ### Run A2DP Sink Example to File Source: https://developer.android.com/training/wearables/apps/test-bluetooth-audio Launch the emulated Bluetooth speaker and redirect audio output to a file named 'output.sbc'. This is useful for capturing and analyzing audio streams. ```bash python3 examples/run_a2dp_sink.py examples/a2dp_sink1.json \ android-netsim output.sbc ``` -------------------------------- ### Show Sweep Transition with Tween Animation Source: https://developer.android.com/training/wearables/tiles/animations Use tween animations to create a smooth sweep effect for elements like progress indicators. This example demonstrates animating a CircularProgressIndicator from a start to an end value over a specified duration. ```kotlin private var startValue = 15f private var endValue = 105f private val animationDurationInMillis = 2000L // 2 seconds override fun onTileRequest(requestParams: RequestBuilders.TileRequest): ListenableFuture { val circularProgressIndicator = CircularProgressIndicator.Builder() .setProgress( FloatProp.Builder(/* static value */ 0.25f) .setDynamicValue( // Or you can use some other dynamic object, for example // from the platform and then at the end of expression // add animate(). DynamicFloat.animate( startValue, endValue, AnimationSpec.Builder() .setAnimationParameters( AnimationParameters.Builder() .setDurationMillis(animationDurationInMillis) .build() ) .build(), ) ) .build() ) .build() return Futures.immediateFuture( Tile.Builder() .setResourcesVersion(RESOURCES_VERSION) .setTileTimeline(Timeline.fromLayoutElement(circularProgressIndicator)) .build() ) } Animations.kt ``` -------------------------------- ### Check if a Watch Face Package is Installed Source: https://developer.android.com/training/wearables/watch-face-push/wear-os-app A suspend function to check if a specific watch face package is currently installed. ```kotlin suspend fun isInstalled(packageName: String) = watchFacePushManager.listWatchFaces() .installedWatchFaceDetails.any { it.packageName == packageName } ``` -------------------------------- ### UserConfigurations with Flavors Source: https://developer.android.com/training/wearables/wff/user-configuration/flavor Demonstrates how to define multiple Flavors within a UserConfigurations element. This example shows how to set a default flavor and configure theme colors and complication slots for each flavor. ```XML ``` -------------------------------- ### Example Style for Minute Hand Source: https://developer.android.com/training/wearables/watch-face-designer/advanced An example of a fully formed style name for the minute hand, following the specified naming convention. ```text Bauhaus/Hands/Charcoal/Minutes ``` -------------------------------- ### Example Style for Hour Hand Source: https://developer.android.com/training/wearables/watch-face-designer/advanced An example of a fully formed style name for the hour hand, following the specified naming convention. ```text Bauhaus/Hands/Charcoal/Hours ``` -------------------------------- ### Run A2DP Sink Example to stdout Source: https://developer.android.com/training/wearables/apps/test-bluetooth-audio Launch the emulated Bluetooth speaker and direct audio output to stdout for playback via ffplay. This requires a Wear OS 4+ emulator and the Bumble project set up. ```bash python3 examples/run_a2dp_sink.py examples/a2dp_sink1.json \ android-netsim stdout | ffplay -i ``` -------------------------------- ### Launch Activity with Extras Source: https://developer.android.com/training/wearables/tiles/interactions Use `launchAction()` to open an activity directly from a tile. This example demonstrates passing string and integer extras to the target activity. The activity must be exported. ```kotlin textButton( labelContent = { text("launchAction()".layoutString, typography = BODY_LARGE) }, onClick = clickable( action = launchAction( ComponentName( "com.example.wear", "com.example.wear.snippets.m3.tile.TileActivity", ), mapOf( "name" to ActionBuilders.stringExtra("Bartholomew"), "age" to ActionBuilders.intExtra(21), ), ) ), ) Interaction.kt ``` ```kotlin override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // When this activity is launched from the tile InteractionLaunchAction, // "name" will be "Bartholomew" and "age" will be 21 val name = intent.getStringExtra("name") val age = intent.getStringExtra("age") // ... } TileActivity.kt ``` -------------------------------- ### Get DataClient Instance Source: https://developer.android.com/training/wearables/data/overview Use the Wearable class to get an instance of the DataClient for accessing the Data Layer API. This is typically done within an Activity context. ```kotlin val dataClient = Wearable.getDataClient(this) ``` -------------------------------- ### Default Watch Face Metadata Source: https://developer.android.com/training/wearables/watch-face-push/wear-os-app Configures the default watch face for installation when the marketplace app is installed. This makes the watch face available in the system picker but does not activate it. ```xml ``` -------------------------------- ### AppScaffold with SwipeDismissableNavHost Source: https://developer.android.com/training/wearables/compose/migrate-to-material3 Demonstrates setting up `AppScaffold` with a `SwipeDismissableNavHost` for screen navigation. `AppScaffold` is used at the Activity level, while `ScreenScaffold` is used for individual screens. ```kotlin AppScaffold { val navController = rememberSwipeDismissableNavController() SwipeDismissableNavHost( navController = navController, startDestination = "message_list" ) { composable("message_list") { MessageList(onMessageClick = { id -> navController.navigate("message_detail/$id") }) } composable("message_detail/{id}") { MessageDetail(id = it.arguments?.getString("id")!!) } } } // Implementation of one of the screens in the navigation @Composable fun MessageDetail(id: String) { // .. Screen level content goes here val scrollState = rememberTransformingLazyColumnState() val padding = rememberResponsiveColumnPadding( first = ColumnItemType.BodyText ) ScreenScaffold( scrollState = scrollState, contentPadding = padding ) { scaffoldPaddingValues -> // Screen content goes here // ... ``` -------------------------------- ### Implementing swipe-to-dismiss with BasicSwipeToDismissBox Source: https://developer.android.com/training/wearables/design/navigation If you are not using the navigation library, you can support the full-screen navigation gesture by using `BasicSwipeToDismissBox` directly. This allows for custom implementations outside of the navigation framework. ```kotlin BasicSwipeToDismissBox ``` -------------------------------- ### Example of edge-swiping with horizontally scrollable content Source: https://developer.android.com/training/wearables/design/navigation This example demonstrates how to handle edge-swiping when the content is horizontally scrollable, reserving 20% of the screen edge for the swipe-to-dismiss gesture. It is part of the Compose Material for Wear OS codebase. ```kotlin See this example from the Compose Material for Wear OS codebase for an example of edge-swiping when the content is horizontally scrollable. ``` -------------------------------- ### Start and Handle Speech Recognition Activity Source: https://developer.android.com/training/wearables/user-input/voice This snippet demonstrates how to launch the system's speech recognition activity and process the returned speech text. It uses Jetpack Compose and ActivityResultContracts for managing the activity result. ```kotlin var textForVoiceInput by remember { mutableStateOf("") } val voiceLauncher = rememberLauncherForActivityResult( ActivityResultContracts.StartActivityForResult() ) { activityResult -> // This is where you process the intent and extract the speech text from the intent. activityResult.data?.let { data -> val results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS) textForVoiceInput = results?.get(0) ?: "None" } } val scrollState = rememberScrollState() ScreenScaffold(scrollState = scrollState) { // rest of implementation here // ... Column( // rest of implementation here // ... // Create an intent that can start the Speech Recognizer activity val voiceIntent: Intent = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH).apply { putExtra( RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM ) putExtra( RecognizerIntent.EXTRA_PROMPT, stringResource(R.string.voice_text_entry_label) ) } // Invoke the process from a chip Chip( onClick = { voiceLauncher.launch(voiceIntent) }, label = stringResource(R.string.voice_input_label), secondaryLabel = textForVoiceInput ) } } VoiceInputScreen.kt ``` -------------------------------- ### Launch Wi-Fi Settings Activity Source: https://developer.android.com/training/wearables/data/network-communication Launches the activity for adding a Wi-Fi network when no saved network is available. Requires the CHANGE_WIFI_STATE permission. ```kotlin val networkSettingsAction = "com.google.android.clockwork.settings.connectivity.wifi.ADD_NETWORK_SETTINGS" val intent = Intent(networkSettingsAction).apply { addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) } context.startActivity(intent) ``` -------------------------------- ### M3 Layout Function Source: https://developer.android.com/training/wearables/tiles/versioning Example of a layout function in M3 using a Compose-inspired, slot-based approach. ```Kotlin fun myLayout( context: Context, deviceConfiguration: DeviceParametersBuilders.DeviceParameters, ) = materialScope(context, deviceConfiguration) { primaryLayout(mainSlot = { text("Hello, World!".layoutString) }) } Versioning.kt ``` -------------------------------- ### Start Custom Synthetic Exercise Source: https://developer.android.com/training/wearables/health-services/synthetic-data Begin a custom synthetic exercise, allowing precise control over metrics like duration, heart rate, speed, and location usage. ```bash adb shell am broadcast \ -a "whs.synthetic.user.START_EXERCISE" \ --ei exercise_options_heart_rate 90 \ --ef exercise_options_average_speed 1.2 \ --ez exercise_options_use_location true \ com.google.android.wearable.healthservices ``` -------------------------------- ### Get WatchFacePushManager Instance Source: https://developer.android.com/training/wearables/watch-face-push/wear-os-app Obtain an instance of WatchFacePushManager to interact with the Watch Face Push API. ```kotlin val watchFacePushManager = WatchFacePushManagerFactory.createWatchFacePushManager(context) ``` -------------------------------- ### WeightedStroke with Weights Attribute Example Source: https://developer.android.com/training/wearables/wff/group/part/draw/style/weighted-stroke Demonstrates the 'weights' attribute, specifying the proportion of the arc or line for each segment. ```xml weights="1.0 2.0 3.0" ``` -------------------------------- ### Show progress using arcs Source: https://developer.android.com/training/wearables/wff/memory-usage Use an Arc object with an expression to control its length for simulating progress. This example completes a progress loop every minute. ```XML ``` -------------------------------- ### M2.5 Layout Function Source: https://developer.android.com/training/wearables/tiles/versioning Example of a layout function in M2.5 using the builder pattern for UI components. ```Kotlin fun myLayout( context: Context, deviceConfiguration: DeviceParametersBuilders.DeviceParameters ) = PrimaryLayout.Builder(deviceConfiguration) .setResponsiveContentInsetEnabled(true) .setContent( Text.Builder(context, "Hello World!") .setTypography(Typography.TYPOGRAPHY_BODY1) .build() ) .build() Versioning.kt ``` -------------------------------- ### Example: Setting Primary and Secondary Providers Source: https://developer.android.com/training/wearables/wff/complication/default-provider-policy Specifies a primary and a secondary data source component for a complication, along with their respective default types. The system provider acts as a final fallback. ```XML ``` -------------------------------- ### Extract Substring Source: https://developer.android.com/training/wearables/wff/common/attributes/arithmetic-expression Extracts a substring from a given string based on start and end indices. The end index is exclusive. ```Java subText("abc def", 2, 5) ``` ```Java subText("abc def", 2, 7) ``` -------------------------------- ### Prepare Exercise Async Source: https://developer.android.com/training/wearables/health-services/active Prepares sensors for an exercise, allowing them to warm up and receive data without starting the workout timer. This is useful for sensors like GPS or heart rate. Ensure necessary permissions are granted before calling. ```kotlin val warmUpConfig = WarmUpConfig( ExerciseType.RUNNING, setOf( DataType.HEART_RATE_BPM, DataType.LOCATION ) ) // Only necessary to call prepareExerciseAsync if body sensor (API level 35 // or lower), heart rate (API level 36+), or location permissions are given. exerciseClient.prepareExerciseAsync(warmUpConfig).await() // Data and availability updates are delivered to the registered listener. ``` -------------------------------- ### WeightedStroke with Colors Attribute Example Source: https://developer.android.com/training/wearables/wff/group/part/draw/style/weighted-stroke Illustrates the use of the 'colors' attribute with a space-separated list of hex color values. ```xml colors="#FF0000 #00FF00 #0000FF" ``` -------------------------------- ### Basic Template with String and Integer Parameters Source: https://developer.android.com/training/wearables/wff/group/part/text/formatter/template This snippet demonstrates how to print a formatted string using the Template and Parameter elements, combining literal text with dynamic values like heart rate. ```xml ``` -------------------------------- ### Check Wearable Renderer Version Source: https://developer.android.com/training/wearables/widgets/get_started Use this ADB command to check the installed version of the Wearable Renderer APK on your device. ```bash adb shell dumpsys package com.google.android.wearable.protolayout.renderer | \ grep -m 1 versionName | \ awk -F= '{print $2}' ``` -------------------------------- ### Launch Bluetooth Settings Source: https://developer.android.com/training/wearables/apps/audio Launch the Bluetooth settings screen to allow users to connect a Bluetooth headset. This is recommended when no headset is detected and the app requires one. ```kotlin fun Context.launchBluetoothSettings(closeOnConnect: Boolean = true) { val intent = with(Intent(Settings.ACTION_BLUETOOTH_SETTINGS)) { addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK) putExtra("EXTRA_CONNECTION_ONLY", true) if (closeOnConnect) { putExtra("EXTRA_CLOSE_ON_CONNECT", true) } putExtra("android.bluetooth.devicepicker.extra.FILTER_TYPE", FILTER_TYPE_AUDIO) } startActivity(intent) } internal const val FILTER_TYPE_AUDIO = 1 BluetoothSettings.kt ``` -------------------------------- ### Create and Configure Notification Builder Source: https://developer.android.com/training/wearables/notifications/ongoing-activity Create a `NotificationCompat.Builder` and set it as ongoing using `setOngoing(true)`. This is essential for displaying the notification on extra surfaces like the watch face. ```kotlin val pendingIntent = PendingIntent.getActivity( this, 0, Intent(this, AlwaysOnActivity::class.java).apply { flags = Intent.FLAG_ACTIVITY_SINGLE_TOP }, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE, ) val notificationBuilder = NotificationCompat.Builder(this, CHANNEL_ID) .setContentTitle("Always On Service") .setContentText("Service is running in background") .setSmallIcon(R.drawable.animated_walk) // Category helps the system prioritize the ongoing activity .setCategory(NotificationCompat.CATEGORY_WORKOUT) .setContentIntent(pendingIntent) .setVisibility(NotificationCompat.VISIBILITY_PUBLIC) .setOngoing(true) // Important! ``` -------------------------------- ### AnimationController Source: https://developer.android.com/training/wearables/wff/group/part/animated-image/animation-controller Controls the playback of animations on the watch face. It defines when an animation starts, repeats, and how it behaves when the watch face is not visible. ```APIDOC ## AnimationController ### Description Controls the playback of animations on the watch face. It defines when an animation starts, repeats, and how it behaves when the watch face is not visible. ### Syntax ```xml ``` ### Attributes #### Required attributes * **play** (string) - Required - An event trigger type which determines when the animation plays. Possible values include: * `TAP`: The animation plays when the user taps on the element. * `ON_VISIBLE`: The animation plays when the element next becomes visible. * `ON_NEXT_SECOND`: The animation plays when the next second begins. * `ON_NEXT_MINUTE`: The animation plays when the next minute begins. * `ON_NEXT_HOUR`: The animation plays when the next hour begins. #### Optional attributes * **delayPlay** (float) - Optional - A delay in seconds before the animation plays. Defaults to 0. * **delayRepeat** (float) - Optional - A delay in seconds before an animation repeats. Defaults to 0. * **repeat** (boolean) - Optional - Whether to repeat the animation when it finishes, playing it indefinitely. Defaults to `FALSE`. * **loopCount** (integer) - Optional - How many times to repeat an animation before it stops. If `repeat` is set to `TRUE`, it takes precedence and this value is ignored. Defaults to 1. * **resumePlayBack** (boolean) - Optional - Animations pause when the watch face is not visible. If `resumePlayBack` is `TRUE`, the animation continues from the same frame that was shown when the watch face previously became not visible. If `resumePlayBack` is set to `FALSE`, the animation restarts from the beginning when the watch face becomes visible again. Defaults to `FALSE`. * **beforePlaying**, **afterPlaying** (string) - Optional - Define the state of the animation element before it can play, or after it has finished. These attributes can be set to the following values: * `DO_NOTHING`: causes no change to the rendered state of the element. * `FIRST_FRAME`: fixes the rendering of the element to the first frame of the animation. * `THUMBNAIL`: fixes the rendering of the element to the thumbnail resource provided by the animated resource. * `HIDE`: hides the animation. Both attributes default to `DO_NOTHING`. ``` -------------------------------- ### Create Widget Configuration XML Source: https://developer.android.com/training/wearables/widgets/get_started Define widget properties like description, icon, label, and supported sizes in an XML file. This snippet shows the structure for `res/xml/hello_widget_info.xml`. ```xml ``` -------------------------------- ### SweepGradient Syntax Source: https://developer.android.com/training/wearables/wff/group/part/draw/gradient/sweep-gradient Defines the structure for a SweepGradient element, including its center coordinates, start and end angles, colors, and positions. ```xml ```