diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index cff01387c..77f80c6d1 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -69,6 +69,7 @@ tiles = "1.5.0" tracing = "1.3.0" validatorPush = "1.0.0-alpha06" version-catalog-update = "1.0.0" +watchfaceComplicationsDataSourceKtx = "1.2.1" wear = "1.3.0" wearComposeFoundation = "1.5.0-rc02" wearComposeMaterial = "1.5.0-rc02" @@ -151,6 +152,7 @@ androidx-tiles-testing = { module = "androidx.wear.tiles:tiles-testing", version androidx-tiles-tooling = { module = "androidx.wear.tiles:tiles-tooling", version.ref = "tiles" } androidx-tiles-tooling-preview = { module = "androidx.wear.tiles:tiles-tooling-preview", version.ref = "tiles" } androidx-tracing = { module = "androidx.tracing:tracing", version.ref = "tracing" } +androidx-watchface-complications-data-source-ktx = { module = "androidx.wear.watchface:watchface-complications-data-source-ktx", version.ref = "watchfaceComplicationsDataSourceKtx" } androidx-wear = { module = "androidx.wear:wear", version.ref = "wear" } androidx-wear-ongoing = { module = "androidx.wear:wear-ongoing", version.ref = "wearOngoing" } androidx-wear-tooling-preview = { module = "androidx.wear:wear-tooling-preview", version.ref = "wearToolingPreview" } diff --git a/settings.gradle.kts b/settings.gradle.kts index eb485975e..316110b4e 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -7,6 +7,9 @@ pluginManagement { mavenCentral() } } +plugins { + id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0" +} dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { diff --git a/wear/build.gradle.kts b/wear/build.gradle.kts index eb7c66445..d88421c1e 100644 --- a/wear/build.gradle.kts +++ b/wear/build.gradle.kts @@ -85,6 +85,8 @@ dependencies { implementation(libs.horologist.compose.layout) implementation(libs.horologist.compose.material) implementation(libs.androidx.material.icons.core) + implementation(libs.androidx.watchface.complications.data.source.ktx) + androidTestImplementation(libs.androidx.compose.ui.test.junit4) debugImplementation(libs.androidx.compose.ui.tooling) debugImplementation(libs.androidx.compose.ui.tooling.preview) diff --git a/wear/src/main/AndroidManifest.xml b/wear/src/main/AndroidManifest.xml index e72edbe49..8aebe45b5 100644 --- a/wear/src/main/AndroidManifest.xml +++ b/wear/src/main/AndroidManifest.xml @@ -201,6 +201,46 @@ android:value="For Ongoing Activity"/> + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/wear/src/main/java/com/example/wear/snippets/complication/MyComplicationDataSourceService.kt b/wear/src/main/java/com/example/wear/snippets/complication/MyComplicationDataSourceService.kt new file mode 100644 index 000000000..ce08ea6ff --- /dev/null +++ b/wear/src/main/java/com/example/wear/snippets/complication/MyComplicationDataSourceService.kt @@ -0,0 +1,50 @@ +/* + * Copyright 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.wear.snippets.complication + +import androidx.wear.watchface.complications.data.ComplicationData +import androidx.wear.watchface.complications.data.ComplicationType +import androidx.wear.watchface.complications.data.PlainComplicationText +import androidx.wear.watchface.complications.data.ShortTextComplicationData +import androidx.wear.watchface.complications.datasource.ComplicationRequest +import androidx.wear.watchface.complications.datasource.SuspendingComplicationDataSourceService + +// [START android_wear_complication] +class MyComplicationDataSourceService : SuspendingComplicationDataSourceService() { + override suspend fun onComplicationRequest(request: ComplicationRequest): ComplicationData? { + // Retrieve latest info for inclusion in the data + val text = getLatestData() + return shortTextComplicationData(text) + } + + override fun getPreviewData(type: ComplicationType): ComplicationData? { + return shortTextComplicationData("Event 1") + } + + private fun shortTextComplicationData(text: String) = + ShortTextComplicationData.Builder( + text = PlainComplicationText.Builder(text).build(), + contentDescription = PlainComplicationText.Builder(text).build() + ) + // Add further optional details here such as icon, tap action, title etc + .build() + + // [START_EXCLUDE] + private fun getLatestData() = "Test" + // [END_EXCLUDE] +} +// [END android_wear_complication] diff --git a/wear/src/main/java/com/example/wear/snippets/complication/MyTimelineComplicationDataSourceService.kt b/wear/src/main/java/com/example/wear/snippets/complication/MyTimelineComplicationDataSourceService.kt new file mode 100644 index 000000000..00b6daea3 --- /dev/null +++ b/wear/src/main/java/com/example/wear/snippets/complication/MyTimelineComplicationDataSourceService.kt @@ -0,0 +1,83 @@ +/* + * Copyright 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.wear.snippets.complication + +import androidx.wear.watchface.complications.data.ComplicationData +import androidx.wear.watchface.complications.data.ComplicationType +import androidx.wear.watchface.complications.data.NoDataComplicationData +import androidx.wear.watchface.complications.data.PlainComplicationText +import androidx.wear.watchface.complications.data.ShortTextComplicationData +import androidx.wear.watchface.complications.datasource.ComplicationDataTimeline +import androidx.wear.watchface.complications.datasource.ComplicationRequest +import androidx.wear.watchface.complications.datasource.SuspendingTimelineComplicationDataSourceService +import androidx.wear.watchface.complications.datasource.TimeInterval +import androidx.wear.watchface.complications.datasource.TimelineEntry +import java.time.Instant +import java.time.temporal.ChronoUnit + +data class CalendarEntry( + val start: Instant, + val end: Instant, + val name: String +) + +// [START android_wear_timeline_complication] +class MyTimelineComplicationDataSourceService : SuspendingTimelineComplicationDataSourceService() { + override suspend fun onComplicationRequest(request: ComplicationRequest): ComplicationDataTimeline? { + if (request.complicationType != ComplicationType.SHORT_TEXT) { + return ComplicationDataTimeline( + defaultComplicationData = NoDataComplicationData(), + timelineEntries = emptyList() + ) + } + // Retrieve list of events from your own datasource / database. + val events = getCalendarEvents() + return ComplicationDataTimeline( + defaultComplicationData = shortTextComplicationData("No event"), + timelineEntries = events.map { + TimelineEntry( + validity = TimeInterval(it.start, it.end), + complicationData = shortTextComplicationData(it.name) + ) + } + ) + } + + override fun getPreviewData(type: ComplicationType): ComplicationData? { + return shortTextComplicationData("Event 1") + } + + private fun shortTextComplicationData(text: String) = + ShortTextComplicationData.Builder( + text = PlainComplicationText.Builder(text).build(), + contentDescription = PlainComplicationText.Builder(text).build() + ) + // Add further optional details here such as icon, tap action, title etc + .build() + + // [START_EXCLUDE] + private fun getCalendarEvents(): List { + val now = Instant.now() + return listOf( + CalendarEntry(now, now.plus(1, ChronoUnit.HOURS), "Event 1"), + CalendarEntry(now.plus(2, ChronoUnit.HOURS), now.plus(3, ChronoUnit.HOURS), "Event 2"), + CalendarEntry(now.plus(4, ChronoUnit.HOURS), now.plus(5, ChronoUnit.HOURS), "Event 3"), + ) + } + // [END_EXCLUDE] +} +// [END android_wear_timeline_complication] diff --git a/wear/src/main/res/drawable/complication_icon.xml b/wear/src/main/res/drawable/complication_icon.xml new file mode 100644 index 000000000..1793d6ba5 --- /dev/null +++ b/wear/src/main/res/drawable/complication_icon.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/wear/src/main/res/values/strings.xml b/wear/src/main/res/values/strings.xml index 90f5cb258..ccf86dbde 100644 --- a/wear/src/main/res/values/strings.xml +++ b/wear/src/main/res/values/strings.xml @@ -6,4 +6,6 @@ Message Detail Hello Tile Hello Tile Description + My Complication + My Timeline Complication \ No newline at end of file