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

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

データ プロバイダ サービスは 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 を拡張する新しいクラスを作成します。詳しくは次の記事をご覧ください。

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

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

追加機能のデータが必要な場合、アップデート リクエストが 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 システムがデータ プロバイダ アプリをデータ プロバイダとして扱えるようにするには、アプリ マニフェストに固有の宣言を含める必要があります。このセクションでは、データ プロバイダ アプリに必要な設定について説明します。アプリのマニフェストでサービスを宣言し、アップデート リクエストのアクション インテント フィルタを追加します。Wear OS システムだけがプロバイダ サービスにバインドできるように、マニフェストで BIND_COMPLICATION_PROVIDER 権限を追加してサービスを保護する必要もあります。

さらに、サービス要素には 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 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 というキーを持つメタデータを追加します。このメタデータの値は、カンマ区切りのリストである必要があります(空白は無視されます)。リスト内のエントリは、コンポーネント名(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 クラスのビルダーを使用して、時間に依存する値を作成できます。