向复杂功能提供数据

数据提供程序应用会通过提供包含文本、字符串、图片和数字的字段,向表盘复杂功能提供信息。

数据提供程序服务扩展了 ComplicationProviderService,可直接将有用的信息提供给表盘。

创建数据提供程序项目

在 Android Studio 中为您的数据提供程序应用创建项目

  1. 依次点击 File > New > New project。
  2. Create Android Project 窗口中,接受默认值,然后点击 Next。
  3. Target Android Devices 窗口中,仅选择 Wear 选项,然后在 SDK 版本列表中选择最新的可用版本。点击 Next
  4. Add an Activity to Wear 窗口中,选择 Add No Activity,然后点击 Finish。

    Android Studio 会使用 app 模块为您的数据提供程序创建项目。如需详细了解 Android Studio 中的项目,请参阅创建项目

  5. 通过创建扩展 BroadcastReceiver 的新类来开始创建您的数据提供程序应用。该类的作用是监听来自 Wear OS 系统的复杂功能更新请求。此外,您还需创建一个扩展 ComplicationProviderService 的新类,以便实际根据相应复杂功能的请求提供数据。如需了解详情,请参阅以下内容:

    注意:为数据提供程序添加 Activity 是可选操作。举例来说,您可能希望添加仅在用户点按某个复杂功能时才会启动的 Activity。

实现更新请求的方法

当 Wear OS 系统需要复杂功能数据时,它会向您的数据提供程序发送更新请求。这些请求会被您的 BroadcastReceiver 接收。为了响应更新请求,您的数据提供程序必须实现 ComplicationProviderService 类的 onComplicationUpdate() 方法。Wear OS 系统会在需要提供程序提供数据时调用此方法,即当使用您的提供程序的复杂功能变为活动状态时,或者在一段固定时间结束后。ComplicationManager 对象会作为参数传递给 onComplicationUpdate 方法,该对象可用于将数据发回给系统。

注意:当您的数据提供程序应用提供数据时,表盘会接收您发送的原始值,以便能够绘制出这些信息。

以下代码段展示了 onComplicationUpdate 方法的实现示例:

Kotlin

    override fun onComplicationUpdate(
        complicationId: Int, dataType: Int, complicationManager: ComplicationManager) {

        Log.d(TAG, "onComplicationUpdate() id: $complicationId")

        // Used to create a unique key to use with SharedPreferences for this complication.
        val thisProvider = ComponentName(this, javaClass)

        // Retrieves your data, in this case, we grab an incrementing number from SharedPrefs.
        val preferences = getSharedPreferences(ComplicationTapBroadcastReceiver.COMPLICATION_PROVIDER_PREFERENCES_FILE_KEY, 0)

        val number = preferences.getInt(
                ComplicationTapBroadcastReceiver.getPreferenceKey(
                        thisProvider, complicationId),
                        0)
        val numberText = String.format(Locale.getDefault(), "%d!", number)

        var complicationData: ComplicationData? = null

        when (dataType) {
            ComplicationData.TYPE_SHORT_TEXT -> complicationData = ComplicationData.Builder(ComplicationData.TYPE_SHORT_TEXT)
                    .setShortText(ComplicationText.plainText(numberText))
                    .build()
            else -> if (Log.isLoggable(TAG, Log.WARN)) {
                        Log.w(TAG, "Unexpected complication type $dataType")
                    }
        }

        if (complicationData != null) {
            complicationManager.updateComplicationData(complicationId, complicationData)
        } else {
            // If no data is sent, we still need to inform the ComplicationManager, so
            // the update job can finish and the wake lock isn't held any longer.
            complicationManager.noUpdateRequired(complicationId)
        }
    }
    

Java

    @Override
    public void onComplicationUpdate(
           int complicationId, int dataType, ComplicationManager complicationManager) {

       Log.d(TAG, "onComplicationUpdate() id: " + complicationId);

       // Used to create a unique key to use with SharedPreferences for this complication.
       ComponentName thisProvider = new ComponentName(this, getClass());

       // Retrieves your data, in this case, we grab an incrementing number from SharedPrefs.
       SharedPreferences preferences =
         getSharedPreferences( ComplicationTapBroadcastReceiver.COMPLICATION_PROVIDER_PREFERENCES_FILE_KEY, 0);

       int number =
               preferences.getInt(
                       ComplicationTapBroadcastReceiver.getPreferenceKey(
                               thisProvider, complicationId),
                       0);
       String numberText = String.format(Locale.getDefault(), "%d!", number);

       ComplicationData complicationData = null;

       switch (dataType) {
           case ComplicationData.TYPE_SHORT_TEXT:
               complicationData =
                       new ComplicationData.Builder(ComplicationData.TYPE_SHORT_TEXT)
                               .setShortText(ComplicationText.plainText(numberText))
                               .build();
               break;
           default:
               if (Log.isLoggable(TAG, Log.WARN)) {
                   Log.w(TAG, "Unexpected complication type " + dataType);
               }
       }

       if (complicationData != null) {
           complicationManager.updateComplicationData(complicationId, complicationData);

       } else {
           // If no data is sent, we still need to inform the ComplicationManager, so
           // the update job can finish and the wake lock isn't held any longer.
           complicationManager.noUpdateRequired(complicationId);
       }
    }
    

清单声明和权限

数据提供程序应用必须在其应用清单中包含特定的声明,才能被 Android 系统视为数据提供程序。本部分介绍了数据提供程序应用的必要设置。在应用清单中,声明相应服务并添加更新请求操作 Intent 过滤器。清单中还必须添加 BIND_COMPLICATION_PROVIDER 权限来确保只有 Wear OS 系统可以绑定到提供程序服务,以此来保护该服务。

此外,您必须在服务元素中添加一个 android:icon 属性。提供的图标应该是纯白色的图标。建议您使用矢量可绘制资源作为图标。图标应代表提供程序,并显示在提供程序选择器中。

示例如下:

    <service
        android:name=".provider.IncrementingNumberComplicationProviderService"
        android:icon="@drawable/icn_complications"
        android:label="@string/complications_provider_incrementing_number"
        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>
    </service>
    

指定元数据元素

在您的清单文件中,添加元数据来指定支持的类型、更新周期和配置操作,如以下示例中所示:

    <meta-data
        android:name="android.support.wearable.complications.SUPPORTED_TYPES"
        android:value="RANGED_VALUE,SHORT_TEXT,LONG_TEXT" />

    <meta-data
        android:name="android.support.wearable.complications.UPDATE_PERIOD_SECONDS"
        android:value="300" />
    

当您的复杂功能数据提供程序处于活动状态时,UPDATE_PERIOD_SECONDS 会指定您希望系统检查数据更新的频率。如果复杂功能中显示的信息不需要定期更新(例如当您使用推送更新时),请将该值设为 0

如果您未将 UPDATE_PERIOD_SECONDS 设为 0,则必须至少设为 300(5 分钟),这是系统为了节省设备电池电量而执行的最短更新周期。此外,请注意,当设备处于微光模式或未佩戴时,更新请求的频率可能会降低。

如需详细了解如何发送更新,请参阅 Wear API 参考文档中所列的 ComplicationProviderService 类的键。

添加配置 Activity

如果需要,提供程序可以包含配置 Activity,该 Activity 会在用户选择数据提供程序时显示给用户。要包含配置 Activity,请在清单中的提供程序服务声明中添加一个具有以下键的元数据项:

    <meta-data
        android:name="android.support.wearable.complications.PROVIDER_CONFIG_ACTION"
        android:value="PROVIDER_CONFIG_ACTION"/>
    

其中的“value”可以是您选择的操作。

然后,创建包含该操作的 Intent 过滤器的配置 Activity。配置 Activity 必须与提供程序位于同一个软件包中。配置 Activity 必须返回 RESULT_OKRESULT_CANCELED,以告知系统是否应设置提供程序。

提供程序指定的安全表盘

提供程序可以将某些表盘指定为“安全”,以便接收其数据。这仅在以下情况下适用:即当表盘尝试将该提供程序作为默认提供程序(参见下文)且该提供程序信任该表盘应用时。

为了声明表盘是安全的,提供程序需要添加具有 android.support.wearable.complications.SAFE_WATCH_FACES 键的元数据。元数据值应为逗号分隔的列表(不含空格)。列表中的条目可以是 WatchFaceServices 的组件名(假设调用了 ComponentName.flattenToString()),也可以是应用的软件包名(在这种情况下,指定应用中的每个表盘都被认为是安全的)。例如:

    <meta-data
           android:name="android.support.wearable.complications.SAFE_WATCH_FACES"
           android:value="
              com.app.watchface/com.app.watchface.MyWatchFaceService,
              com.anotherapp.anotherwatchface/com.something.WatchFaceService,
              com.something.text"/>
    

提供安全的防烙印图像

在容易出现烙印的屏幕上,应避免在微光模式下使用纯色块。如果您的图标或图片包含纯色块,您还应提供安全的防烙印版本。

当您使用 ComplicationData.Builder#setIcon 提供图标时,请使用 ComplicationData.Builder#setBurnInProtectionIcon 添加安全的防烙印版本。

当您使用 ComplicationData.Builder#setSmallImage 提供图片时,请使用 ComplicationData.Builder#setBurnInProtectionSmallImage 添加安全的防烙印版本。

使用推送更新

除了在应用清单中为复杂功能指定非零的常量更新间隔,您还可以使用 ProviderUpdateRequester 实例来动态请求更新。要请求更新复杂功能的用户可见内容,请调用 onComplicationUpdate()

注意:为了节省设备的电池电量,您的 ProviderUpdateRequester 实例调用 onComplicationUpdate() 的平均频率不应超过 5 分钟一次。

提供具有时效性的值

一些复杂功能需要显示与当前时间相关的值,例如当前日期、距离下次会议召开还剩下的时间或另一个时区的时间。

请不要为了确保这些值是最新的,就每秒或每分钟都要更新一次复杂功能;一项复杂功能不会需要如此频繁地更新。请使用具有时效性的文本来指定与当前日期或时间相关的值。您可以使用 ComplicationText 类中的 builder 来创建此类具有时效性的值。