Ongoing Activity API を使用して、新しい方法で Wear OS ユーザーにアピールする

cb2a383284f10acd.gif

上のアニメーション(進行中のアクティビティのデモ)をご覧ください。注: アニメーション GIF は一度しか再生されません。アニメーションを見逃した場合は、ページを再読み込みしてください。

ウォッチフェイスにアニメーション アイコン(タイマー)が表示され、ユーザーがアイコンをタップすると、アプリが起動し、タイマーが作動します。

進行中のアクティビティは Wear OS の新機能です。進行中の通知を Wear OS のユーザー インターフェースの他のサーフェスに表示できるので、ユーザーは長時間のアクティビティにより集中できるようになります。

進行中の通知は通常、ユーザーが操作に集中しているバックグラウンド タスク(音楽の再生など)や、なんらかの方法で待機しながらデバイスを占有するバックグラウンド タスク(ファイルのダウンロード、同期、アクティブなネットワーク接続など)の通知として使用されます。

たとえば、Wear OS ユーザーがタイマーアプリを使ってイベントの時間を計測した後、そのアプリから離れて他のタスク(天気情報の表示、ワークアウトの開始など)を開始できます。

ユーザーがタイマーアプリから離れると、アプリは通常、一部のバックグラウンド処理(サービス、アラーム マネージャーなど)に関連付けられた進行中の通知に移行して、引き続きタイマーの残り時間をユーザーに知らせるようにします。

ユーザーは通知で更新情報を確認できるほか、通知の操作も行えます。

ただし、通知を表示するには、ウォッチフェイスの下にある通知トレイをスワイプして、対応する通知を見つける必要があります。これは他のサーフェスほど便利ではありません。

Ongoing Activity API を使用すると、アプリがユーザーの操作を妨げることなく、簡単にアクセスできる Wear OS の複数の新しいサーフェスに情報を表示できます。

タイマーアプリの場合、情報はタップ可能なアイコン(スクリーンショットの下部にあるアクティビティ インジケーター)として、ユーザーのウォッチフェイスに表示されます。

1fc8f1c0d0b5776d.png

タイマーアプリは、進行中のアクティビティを一覧表示するグローバル アプリ ランチャーの [履歴] セクションにも表示されます。

92926c4d6dc3aad5.png

グローバル ランチャー

この機能は、最大 10 行のコードを追加するだけで簡単に利用できます。

学習内容

  • 進行中のアクティビティを作成し、カスタマイズする
  • 進行中のアクティビティ進行中の通知に関連付ける
  • デバイスまたはエミュレータで進行中のアクティビティをテストする
  • 進行中のアクティビティにインタラクションを追加する(タップ)

作成するアプリの概要

既存の歩行記録トラッキング アプリをカスタムの進行中のアクティビティで拡張し、アクティブな歩行記録のウォーキング ポイントを、メインのウォッチフェイスとアプリランチャーの [履歴] セクションに表示します。

前提条件

このステップでは、環境を設定してスターター プロジェクトをダウンロードします。

必要なもの

  • Wear OS エミュレータのデベロッパー プレビューを含む Android Studio(Arctic Fox)の最新のベータ版ビルド
  • Wear OS エミュレータ(API レベル 30 以上)
  • 進行中のアクティビティは API レベル 30 以上でのみ利用できます。
  • エミュレータを初めてお使いになる場合は、こちらで設定方法をご確認ください。

コードをダウンロードする

git がインストールされている場合は、以下のコマンドをそのまま実行してこのリポジトリからコードのクローンを作成できます。git がインストールされているかどうかを確認するには、ターミナルまたはコマンドラインで「git --version」と入力し、正しく実行されることを確認します。

git clone https://github.com/googlecodelabs/ongoing-activity.git
cd ongoing-activity

git がない場合は、次のボタンをクリックして、この Codelab のすべてのコードをダウンロードできます。

ZIP をダウンロード

どちらのモジュールも、Android Studio のツールバーで実行構成を変更することでいつでも実行できます。

8a2e49d6d6d2609d.png

Android Studio でプロジェクトを開く

  1. [Welcome to Android Studio] ウィンドウで、1f5145c42df4129a.png [Open an Existing Project] を選択します。
  2. [Download Location] フォルダを選択します。
  3. Android Studio にプロジェクトがインポートされたら、Wear OS エミュレータまたは物理デバイスで start モジュールと finished モジュールを実行できるかどうかをテストします。
  4. start モジュールは次のスクリーンショットのようになります。すべての作業をこのモジュールで行います。

a3817357e22438af.png

ウォーキングのワークアウトを開始してアプリを試してみます。3 秒ごとにポイントを獲得できていることがわかります(アプリでは疑似データが使用されるため、実際に歩行する必要はありません)。

アプリをスワイプして消去します。ウォッチフェイスをナビゲーション トレイに移動すると、進行中の通知が表示され、ウォーキング ポイントが引き続きトラッキングされます。

進行中の通知をタップすると次のような画像が表示されます。

990814a9f59a510a.png

ac59318b7243c403.png

歩行はいつでもやめられます。

この Codelab の最後に、同じウォーキング情報が、ウォッチフェイスとグローバル アプリ ランチャーの [履歴] セクションに表示されます。

アプリがウォッチフェイスに表示されます(下部にあるアクティビティ インジケーターをご覧ください)。

61112a8afe935eb5.png

アプリがアプリ ランチャーの [履歴] セクションに表示されます。

717a9825221a8f86.png

start コードを確認する

start モジュール内の内容は以下のとおりです。

  • build.gradle: 基本的なアプリ構成が含まれています。これには進行中のアクティビティを作成するために必要な依存関係が含まれます。
  • manifest > AndroidManifest.xml: このアプリを Wear OS アプリとしてマークするために必要なパーツが含まれています。
  • java > ... > data > WalkingWorkoutsRepository.kt: ウォーキング ポイントとウォーキング ワークアウトのステータスを保存する WalkingWorkoutsDataStore.kt クラスにリンクしています。この Codelab ではこれらのクラスを確認する必要はないので、詳細は気にしないでください。
  • java > ... > MainApplication.kt: リポジトリのシングルトンを作成します。この Codelab ではこれらのクラスを確認する必要はないので、詳細は気にしないでください。
  • java > ... > ForegroundOnlyWalkingWorkoutService.kt: ウォーキング ワークアウトの開始と停止を行うコードが含まれています。ワークアウトがアクティブな状態でユーザーがアプリから離れると、ワークアウトがアクティビティからアンバインドされます。そして、進行中の通知が開始され、(疑似データを使って)ワークアウト ポイントの情報を引き続きユーザーに知らせます。進行中のアクティビティのコードを追加するのはここです(通知のコードの近く)。
  • java > ... > MainActivity.kt: ユーザーがウォーキング ワークアウトを開始 / 停止するための UI が含まれています。アクティビティは、上記のサービスにバインドして、すべてのワークアウト タスクを処理できるようにします。
  • java > ... > MainViewModel.kt: MainActivity.kt で UI 以外のコードを処理するシンプルな ViewModel です。この Codelab ではこれらのクラスを確認する必要はないので、詳細は気にしないでください。

アプリはすでに、ウォーキング ワークアウト アプリとして機能しています。

前のステップで説明したとおり、アプリを起動してウォーキング ワークアウトを開始 / 停止できます。ワークアウトがアクティブになると、時間の経過とともにウォーキング ポイントが発生します。

新しいウォーキングが開始されると、ポイントはリセットされます。

ワークアウトがアクティブな間にアプリを離れる場合は、下にスワイプすることで進行中の通知が表示され、進行状況の更新を引き続き確認できます。

この通知で、ワークアウトを停止するかアプリを開くことができます。

通常は、独自のアルゴリズムを使用して、位置情報とセンサーデータからウォーキング ポイントを計算します。ここでは簡単にするために疑似データを使用しています。

仕組み

MainActivity がユーザー インターフェースを作成し、ViewModel に接続して、ワークアウトのステータスやウォーキング ポイントを更新し、サービスにバインドします。

ワークアウトを開始または停止すると、MainActivity はサービス内の開始または停止の役割を担うメソッドを呼び出し、ワークアウトをトラッキングする負荷の高い処理を担当します。

ユーザーがアプリから離れると、MainActivity はサービスからアンバインドのみを行います。

複雑な処理の大半は ForegroundOnlyWalkingWorkoutService で発生します。このクラスは、ワークアウトを開始 / 停止し、ステータスやウォーキング ポイントの変更をリポジトリに保存します。

また、セッション中にユーザーが MainActivity から離れると、サービスはフォアグラウンド サービスに移行し、進行中の通知に関連付けられます。

進行中の通知は、ワークアウトをトラッキングする作業を続け、フォアグラウンド サービスとして上記のサービスに関連付けられます。

すべての処理を詳しく理解しなくても問題ありません。このアプリが、すでに構築された通知機能を備えたアプリであると理解することが重要です。この通知を拡張して、進行中のアクティビティがより多くのサーフェスで表示されるようにすることが目的です。

その通知のコードは ForegroundOnlyWalkingWorkoutService にあり、ここでこのコードラボのすべての作業を行います。

依存関係を確認する

このステップではコーディングは行いません。代わりに、進行中のアクティビティの依存関係を確認します。

start モジュールの app/build.gradle ファイルを開き、「TODO: Review dependencies for Ongoing Activity」を検索します。

次のようになっているはずです。

ステップ 1

    // TODO: Review dependencies for Ongoing Activity.
    implementation "androidx.wear:wear-ongoing:1.0.0-alpha05"
    // Includes LocusIdCompat and new Notification categories for Ongoing Activity.
    implementation "androidx.core:core:1.5.0-rc01"

1 つ目の依存関係は Wear OS Ongoing Activity API を使用するために必要です。

2 つ目の依存関係は、通知 API の最新機能を取り入れて、進行中のアクティビティと組み合わせて使用する各機能をサポートするためのものです。次の 2 つの機能は進行中の通知に適用できるため、進行中のアクティビティにも適用できます。

  • Category - Android は、システム全体を対象とする事前定義済みのカテゴリを使用して、ユーザーがサイレント モードを有効にしているときに特定の通知でユーザーの操作に割り込むかどうかを決定します。Category により、ウォッチフェイスでの進行中のアクティビティの優先度が決まります。Wear をサポートする新しいカテゴリが最近追加されました。
  • LocusId - Locus は、Android 10(API レベル 29)で導入された新しいコンセプトです。コンテンツ キャプチャ、ショートカット通知など、異なるサブシステム間の状態を Android システムが関連付けられるようにします。ランチャーが複数ある場合は、locus ID を使用して、進行中のアクティビティを特定の動的 Shortcut に関連付けることで、アプリ ランチャーの [履歴] セクションに適切に表示できます。

進行中の通知のコードを確認する

このステップでは、コーディングは行いません。通知のコードの確認のみを行います。

start モジュールの ForegroundOnlyWalkingWorkoutService.kt ファイルを開き、「TODO: Review Notification builder code」を検索します。

次のようになっているはずです。

ステップ 2

// TODO: Review Notification builder code.
val notificationBuilder = notificationCompatBuilder
    .setStyle(bigTextStyle)
    .setContentTitle(titleText)
    .setContentText(mainText)
    .setSmallIcon(R.mipmap.ic_launcher)
    .setDefaults(NotificationCompat.DEFAULT_ALL)
    // Makes Notification an Ongoing Notification (a Notification with a background task).
    .setOngoing(true)
    // Android uses some pre-defined system-wide categories to determine whether to
    // disturb the user with a given notification when the user has enabled Do Not Disturb
    // mode. The Category determines the priority of the Ongoing Activity and new
    // categories were added recently to support Wear
    .setCategory(NotificationCompat.CATEGORY_WORKOUT)
    .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
    .addAction(
        R.drawable.ic_walk, getString(R.string.launch_activity),
        activityPendingIntent
    )
    .addAction(
        R.drawable.ic_cancel,
        getString(R.string.stop_walking_workout_notification_text),
        servicePendingIntent
    )

// TODO: Create an Ongoing Activity.
// SKIP TODO FOR REVIEW STEP

return notificationBuilder.build()

上記のコードを確認し、コメントを読みます(後半の TODO のセクションは後で説明します)。

この各コードの上に、このビルダーに必要なすべての項目を設定する通知のコードが多数あります。

ただし、この Codelab では、通知ビルダー内の setOngoing() 呼び出しと setCategory() に注目します。

Category を使用することで、Wear OS がウォッチフェイスの通知の優先度を決定できます。

setOngoing() 呼び出しにより、通知が進行中の通知になります。つまり、ユーザーがその時点で操作しているバックグラウンド タスク(ウォーキング ワークアウトのトラッキングなど)を示す通知になります。

この通知は、ユーザーがウォーキング ワークアウトを行いながら、MainActivity から離れたときに作成されます。

進行中のアクティビティを作成する

進行中のアクティビティは、進行中の通知に関連付けられている必要があります。進行中の通知を作成できたので、次は進行中のアクティビティを作成しましょう。

TODO: Add Ongoing Activity variable」を検索し、「// SKIP TODO FOR REVIEW STEP」という行を次のコードで置き換えます。

ステップ 4

        // TODO: Create an Ongoing Activity.
        val ongoingActivityStatus = Status.Builder()
            // Sets the text used across various surfaces.
            .addTemplate(mainText)
            .build()

        val ongoingActivity =
            OngoingActivity.Builder(applicationContext, NOTIFICATION_ID, notificationBuilder)
                // Sets icon that will appear on the watch face in active mode. If it isn't set,
                // the watch face will use the static icon in active mode.
                // Supported animated icon types: AVD and AnimationDrawable.
                .setAnimatedIcon(R.drawable.animated_walk)
                // Sets the icon that will appear on the watch face in ambient mode.
                // Falls back to Notification's smallIcon if not set. If neither is set,
                // an Exception is thrown.
                .setStaticIcon(R.drawable.ic_walk)
                // Sets the tap/touch event, so users can re-enter your app from the
                // other surfaces.
                // Falls back to Notification's contentIntent if not set. If neither is set,
                // an Exception is thrown.
                .setTouchIntent(activityPendingIntent)
                // In our case, sets the text used for the Ongoing Activity (more options are
                // available for timers and stop watches).
                .setStatus(ongoingActivityStatus)
                .build()

        // Applies any Ongoing Activity updates to the notification builder.
        // This method should always be called right before you build your notification,
        // since an Ongoing Activity doesn't hold references to the context.
        ongoingActivity.apply(applicationContext)

進行中のアクティビティを作成する前に、まず進行中のアクティビティの Status を作成します。ここでは、さまざまな Wear OS サーフェスに表示されるテキストを設定します。

Status.Builder.addTemplate() を使用してテキストを設定し、通知に使用したのと同じメインテキストにします。

テキストの外観(色、太字など)はカスタマイズできますが、この Codolab ではシンプルなテキストのままで使用します。詳しくは、進行中のアクティビティに関するガイドをご覧ください。

次に、OngoingActivity を作成します。コンテキスト、通知 ID、このコード上に作成した通知ビルダーを、OngoingActivity.Builder() のコンストラクタに渡します。

通知 ID と NotificationCompat.Builder インスタンスは、OngoingActivity を進行中の通知に関連付けるうえで重要です。

まず、アニメーション アイコン(アクティブ モードのウォッチフェイス用)、静的なアイコン(常に画面表示モードのウォッチフェイス用)を設定します。

次に、タッチイベントを設定し、最後に先ほど作成した Status オブジェクトを使用してテキストを設定してから、.build() を使用してステートメントを終了します。

OngoingActivity ユーザー インターフェースは、アイコンと Status のテキストを使用して提供されます。タッチイベントを使用すると、ユーザーは、ウォッチフェイスまたはグローバル アプリ ランチャーの [履歴] セクションでアプリをタップして操作に戻れます。

最後に、進行中のアクティビティで apply() を呼び出し、コンテキストを渡します。これは、進行中のアクティビティへの変更を通知ビルダーに適用する最後のステップです。

これで完了です。

通知で notificationManager.notify(NOTIFICATION_ID, notification) が呼び出されると、新しいサーフェスに表示されるようになりました。

新しい Wear OS エミュレータまたはデバイス上でアプリを実行します。

アプリでウォーキングを開始し、スワイプしてアプリを終了します。

ウォッチフェイスには、次のような小さな人が歩いているアイコン(アニメーション)が表示されます。

61112a8afe935eb5.png

アイコンをタップするとアプリに戻ります。

アプリをもう一度終了し、次に Wear OS デバイスでアプリ ランチャー ボタンをタップします。

次のようになります。

717a9825221a8f86.png

[履歴] セクションでウォーキング アプリをクリックすると、再びアプリを開始できます。

これで完成です。Wear OS での進行中のアクティビティの作成方法を学習しました。

進行中のアクティビティは、Wear の新しいサーフェスをユーザーにアピールする優れた方法です。

次のステップ

Wear OS の他の Codelab をご確認ください。

参考資料