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

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

Сервис источника данных расширяет 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.

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