Предоставление данных для дополнений

Источники данных дополнений предоставляют информацию для дополнений циферблата, передавая текст, изображения и числа, которые могут быть отображены на циферблате.

Сервис источников данных расширяет возможности SuspendingComplicationDataSourceService, чтобы передавать полезную информацию прямо на циферблат.

Начало работы

Добавьте в модуль приложения следующую зависимость:

dependencies {
  implementiation("androidx.wear.watchface:watchface-complications-data-source-ktx:1.2.1")
}

Как создать сервис источника данных

Когда системе Wear OS требуются данные для виджета, она отправляет запросы на обновление в источник данных. Чтобы отвечать на запросы об обновлении, в источнике данных должен быть реализован метод onComplicationRequest() класса SuspendingComplicationDataSourceService.

Система Wear OS вызывает метод onComplicationRequest(), когда ей нужны данные из вашего источника, например когда становится активным элемент, использующий ваш источник данных, или когда проходит определенный период времени.

Примечание. Когда источник данных предоставляет информацию, циферблат получает необработанные значения. Циферблат отвечает за форматирование данных для отображения.

Ниже приведен пример реализации фрагмента кода:

class MyComplicationDataSourceService : SuspendingComplicationDataSourceService() {
    override suspend fun onComplicationRequest(request: ComplicationRequest): ComplicationData? {
        // Retrieve the 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, and title.
            .build()

    // ...
}

Декларации и разрешения в манифесте

Чтобы система Android распознавала источник данных, в манифесте приложения должны быть определенные декларации. В этом разделе описаны обязательные настройки источников данных.

В манифесте приложения объявите сервис и добавьте фильтр интентов для действия запроса на обновление. Манифест также должен защищать сервис, добавляя разрешение BIND_COMPLICATION_PROVIDER, чтобы только система Wear OS могла подключаться к сервисам поставщика.

Также добавьте атрибут android:icon в элемент service, чтобы указать одноцветный белый значок. Для значков рекомендуем использовать векторную графику. Значок источника данных показывается в меню выбора виджетов.

Рассмотрим пример.

<service
    android:name=".snippets.complication.MyComplicationDataSourceService"
    android:exported="true"
    android:label="@string/my_complication_service_label"
    android:icon="@drawable/complication_icon"
    android:permission="com.google.android.wearable.permission.BIND_COMPLICATION_PROVIDER">
    <intent-filter>
        <action android:name="android.support.wearable.complications.ACTION_COMPLICATION_UPDATE_REQUEST" />
    </intent-filter>

    <!-- Supported types should be comma-separated, for example: "SHORT_TEXT,SMALL_IMAGE" -->
    <meta-data
        android:name="android.support.wearable.complications.SUPPORTED_TYPES"
        android:value="SHORT_TEXT" />
    <meta-data
        android:name="android.support.wearable.complications.UPDATE_PERIOD_SECONDS"
        android:value="300" />

    <!-- Optionally, specify a configuration activity, where the user can configure your complication. -->
    <meta-data
        android:name="android.support.wearable.complications.PROVIDER_CONFIG_ACTION"
        android:value="MY_CONFIG_ACTION" />

</service>

Элементы метаданных

В файле манифеста обратите внимание на следующие элементы метаданных:

  • android:name="android.support.wearable.complications.SUPPORTED_TYPES": Указывает типы данных для виджетов, которые поддерживает источник данных.
  • android:name="android.support.wearable.complications.UPDATE_PERIOD_SECONDS": Указывает, как часто система должна проверять наличие обновлений данных.

Когда источник данных для дополнения активен, UPDATE_PERIOD_SECONDS указывает, как часто система должна проверять наличие обновлений данных. Если информация в дополнении не должна обновляться регулярно, например при использовании push-уведомлений, задайте значение 0.

Если вы не зададите для параметра UPDATE_PERIOD_SECONDS значение 0, вам нужно будет указать значение не менее 300 (5 минут). Это минимальный период обновления, который система применяет для экономии заряда батареи устройства. Кроме того, помните, что запросы на обновление поступают реже, когда устройство находится в спящем режиме или не надето.

Как добавить действие конфигурации

При необходимости источник данных может включать действие по настройке, которое показывается пользователю, когда он выбирает этот источник в окне выбора дополнений. Например, источник данных для мировых часов может иметь конфигурацию, позволяющую пользователю выбрать город или часовой пояс.

В примере манифеста есть элемент meta-data с ключом PROVIDER_CONFIG_ACTION. Значение этого элемента – действие, которое используется для запуска действия конфигурации.

Создайте действие конфигурации и добавьте фильтр интентов, который соответствует действию в файле манифеста.

<intent-filter>
    <action android:name="MY_CONFIG_ACTION" />
    <category android:name="android.support.wearable.complications.category.PROVIDER_CONFIG" />
    <category android:name="android.intent.category.DEFAULT" />
</intent-filter>

Чтобы получить информацию о слоте, который настраивает действие, можно использовать намерение в методе onCreate():

// Keys defined on ComplicationDataSourceService
val id = intent.getIntExtra(EXTRA_CONFIG_COMPLICATION_ID, -1)
val type = intent.getIntExtra(EXTRA_CONFIG_COMPLICATION_TYPE, -1)
val source = intent.getStringExtra(EXTRA_CONFIG_DATA_SOURCE_COMPONENT)

Действие конфигурации должно находиться в том же пакете, что и поставщик. Действие конфигурации должно возвращать RESULT_OK или RESULT_CANCELED, чтобы сообщить системе, следует ли задавать источник данных:

setResult(RESULT_OK) // Or RESULT_CANCELED to cancel configuration
finish()

Используйте push-уведомления

Вместо того чтобы указывать интервал обновления в манифесте приложения, вы можете использовать экземпляр ComplicationDataSourceUpdateRequester, чтобы запускать обновления динамически. Чтобы запросить обновление, вызовите метод requestUpdate().

Внимание! Чтобы не разряжать батарею устройства, не вызывайте функцию requestUpdate() из экземпляра ComplicationDataSourceUpdateRequester чаще, чем в среднем раз в пять минут.

Как указывать значения, зависящие от времени

Некоторые виджеты должны показывать значение, связанное с текущим временем. Например, можно узнать текущую дату, время до следующей встречи или время в другом часовом поясе.

Не обновляйте данные в виджете каждую секунду или минуту, чтобы они были актуальными. Вместо этого укажите значения относительно текущей даты или времени, используя текст, зависящий от времени. Чтобы создать значения, зависящие от времени, используйте следующие классы:

Данные хронологии.

Для источников данных дополнений, которые предоставляют последовательность значений в заданное время, используйте SuspendingTimelineComplicationDataSourceService.

Примером может служить источник данных "Следующее событие" из приложения календаря. Вместо того чтобы системе приходилось регулярно опрашивать источник данных о следующем событии, источник данных может предоставить временную шкалу событий один раз, а затем инициировать обновления, если календарь изменится. Это снижает нагрузку на систему и позволяет своевременно показывать правильное событие в дополнении:

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()

    // ...
}

Поведение SuspendingTimelineComplicationDataSourceService следующее:

  • Когда текущее время попадает в диапазон времени начала и окончания записи на временной шкале, циферблат использует это значение.
  • Если текущее время не соответствует ни одному из значений временной шкалы, используется значение по умолчанию. Например, в приложении "Календарь" это может быть "Нет мероприятия".
  • Если текущее время попадает в несколько событий, используется самое короткое из них.

Как передавать динамические значения

В Wear OS 4 некоторые виджеты могут показывать значения, которые обновляются чаще, чем раньше, поскольку платформа получает их напрямую. Чтобы добавить эту функцию в дополнения, используйте поля ComplicationData, которые принимают динамические значения. Платформа часто оценивает и обновляет эти значения, и для этого не требуется, чтобы поставщик дополнений был запущен.

Примеры полей: GoalProgressComplicationData – поле динамического значения и DynamicComplicationText, которое можно использовать в любом поле ComplicationText. Эти динамические значения основаны на библиотеке androidx.wear.protolayout.expression.

В некоторых случаях платформа не может оценить динамические значения:

  • Динамическое значение иногда недоступно. Например, это происходит, когда устройство снято с запястья. В таких случаях платформа использует значение из поля резервного значения для аннулирования динамического значения в .NoDataComplicationData
  • Динамическое значение недоступно. Это происходит на устройстве с более ранней версией Wear OS 4. В этом случае платформа использует резервное поле, например getFallbackValue().