ウォッチフェイスの追加機能へのデータの公開

データ プロバイダ アプリは、ウォッチフェイスの追加機能(以下、「追加機能」と表記)に情報を表示して、テキスト、文字列、イメージ、数値といった項目を提供します。

データ プロバイダ サービスは ComplicationProviderService を拡張したものであり、有益な情報をユーザーのウォッチフェイスに直接提供します。

データ プロバイダ プロジェクトを作成する

Android Studio でデータ プロバイダ アプリのプロジェクトを作成するには、次の手順を行います。

  1. [File] > [New] > [New project] をクリックします。
  2. [Project Template] ウィンドウで [Wear OS] タブをクリックし、[No Activity] を選択して [Next] をクリックします。
  3. [Configure Your Project] ウィンドウでプロジェクトに名前を付け、標準のプロジェクト情報を入力して、[Finish] をクリックします。
  4. Android Studio でプロジェクトを作成するには、データ プロバイダ用のアプリ モジュールを使用します。Android Studio のプロジェクトについて詳しくは、プロジェクトの作成をご覧ください。
  5. BroadcastReceiver を拡張する新しいクラスを作成して、データ プロバイダ アプリを開始します。クラスの目的は、Wear OS システムからの追加機能アップデート リクエストをリッスンすることです。また、適切な追加機能によるリクエストに応じてデータを提供する目的で、ComplicationProviderService を拡張する新しいクラスを作成します。詳しくは次の記事をご覧ください。

    注: データ プロバイダのアクティビティの追加は任意です。たとえば、ユーザーが追加機能をタップしたときにのみ起動するアクティビティを追加できます。

アップデート リクエスト用のメソッドを実装する

追加機能のデータが必要な場合、アップデート リクエストが Wear OS システムによってデータ プロバイダに送信されます。リクエストは BroadcastReceiver で受信します。システムからのアップデート リクエストに応答するために、データ プロバイダは ComplicationProviderService クラスの onComplicationUpdate() メソッドを実装する必要があります。

Wear OS システムは、プロバイダからデータが必要になった場合、たとえばプロバイダを使用している追加機能がアクティブになったとき、または一定の時間が経過したときに、onComplicationUpdate() を呼び出します。システムは 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, grabs 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, grabs 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 システムがデータ プロバイダ アプリをデータ プロバイダとして扱えるようにするには、アプリ マニフェストに固有の宣言を含める必要があります。このセクションでは、データ プロバイダ アプリに必要な設定について説明します。

アプリのマニフェストでサービスを宣言し、アップデート リクエストのアクション インテント フィルタを追加します。Wear OS システムだけがプロバイダ サービスにバインドできるように、マニフェストで BIND_COMPLICATION_PROVIDER 権限を追加してサービスを保護する必要もあります。

さらに、service 要素に、単色の白いアイコンを提供する 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_SECONDS0 に設定しない場合は、300(5 分)以上の値を使用する必要があります。デバイスの電池を長持ちさせるため、この値がシステムで定められた最短のアップデート周期となります。また、デバイスが「常に画面表示」モードである場合や、デバイスを着用していない場合は、アップデート リクエストの頻度が低くなることにご注意ください。

アップデートの送信について詳しくは、Wear OS API リファレンスComplicationProviderService クラスに記載されているキーをご覧ください。

構成アクティビティの追加

必要に応じて、ユーザーがデータ プロバイダを選択したときに表示される構成アクティビティをプロバイダに含めることができます。構成アクティビティを含めるには、次のキーを持つメタデータ項目をマニフェストのプロバイダ サービス宣言に追加します。

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

この値には、任意のアクションを設定できます。

次に、インテント フィルタに対象のアクションを指定した構成アクティビティを作成します。構成アクティビティは、プロバイダと同じパッケージに格納する必要があります。また、プロバイダを設定すべきかどうかをシステムに伝えるために、RESULT_OKRESULT_CANCELED を返す必要があります。

プロバイダ固有の安全なウォッチフェイス

プロバイダは、「安全」に自分のデータを受信できるウォッチフェイスを指定できます。これは、ウォッチフェイスがデフォルトとして特定のプロバイダを使用することを試み、プロバイダがそのウォッチフェイス アプリを信頼している場合にのみ使用されます。

ウォッチフェイスが安全であると宣言するには、プロバイダに android.support.wearable.complications.SAFE_WATCH_FACES というキーを持つメタデータを追加します。メタデータ値には、WatchFaceService コンポーネント名(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 を使用して焼き付き防止版を追加します。

プッシュ アップデートを使用する

アプリのマニフェストで、追加機能に対してゼロ以外のアップデート周期定数を指定する代わりに、ComplicationDataSourceUpdateRequester インスタンスを使用してアップデートを動的にリクエストできます。追加機能の、ユーザーに表示されるコンテンツに対するアップデートをリクエストするには、requestUpdate() を呼び出します。

注意: デバイスの電池を長持ちさせるため、ComplicationDataSourceUpdateRequester のインスタンスから requestUpdate() を呼び出す周期は平均 5 分よりも短くしないでください。

動的な値を指定する

Wear OS 4 以降、ウォッチフェイスの追加機能では、プラットフォームで直接利用可能な値に基づいて、より頻繁に更新される値が表示されることがあります。ウォッチフェイスの追加機能にこの機能を提供するには、動的な値を受け入れる ComplicationData フィールドを使用します。プラットフォームは、追加機能プロバイダを実行しなくても、これらの値を頻繁に評価して更新します。

フィールドの例には、 GoalProgressComplicationData の動的値フィールドと、任意の ComplicationText フィールドで使用できる DynamicComplicationText があります。これらの動的な値は androidx.wear.protolayout.expression ライブラリに基づいています。

次のような状況では、プラットフォームは動的な値を評価できません。

時間に依存する値を指定する

追加機能の中には、現在時刻に関連する値を表示するものがあります。現在の日付、次の打ち合わせまでの時間、別のタイムゾーンでの時刻などが該当します。

値を最新の状態に保つため、追加機能を 1 秒または 1 分ごとに更新しないでください。代わりに、時間依存テキストを使用して現在の日付や時間に対する相対値を指定します。ComplicationText クラスのビルダーを使用して、時間に依存する値を作成できます。

ウォッチフェイスの追加機能の更新頻度

ウォッチフェイスの追加機能は頻繁に更新することをおすすめします。ただし、頻繁に更新すると、デバイスのバッテリー駆動時間に影響することがあります。特権的な ComplicationRequest API を使用すると、特定のウォッチフェイスの追加機能の更新頻度を上げることができます。ただし、この API を使用するには、スマートウォッチ メーカーによる許可が必要です。各スマートウォッチ メーカーは、どのウォッチフェイスの追加機能を通常よりも頻繁に更新するかを決定します。