1. はじめに
作成するアプリの概要
この Codelab では、ユーザーの睡眠時間を検出する Android アプリを作成します。アプリは次のことを行います。
- 権限をリクエストする
- Android Sleep API に登録する
- API イベントを取得して UI に表示する
- 不要になったら登録を解除する
必要なもの
- 最新バージョンの Android Studio と Android Build Tools v21 以降
- Android 10 以降(API レベル 29 以上)を搭載しているデバイス
2. 設定方法
スターター プロジェクト リポジトリのクローンを作成する
できるだけすぐに開始できるように、たたき台として利用できるスターター プロジェクトを用意しています。ターミナル / コマンドラインで「git --version
」と入力し、git がインストールされているかどうかを確認します。インストールされていない場合は、こちらの手順に沿ってインストールします。その後、以下のコマンドを実行するだけで、プロジェクトのクローンを作成できます。
git clone https://github.com/android/codelab-android-sleep/
プロジェクトをインポートする
Android Studio を起動し、ウェルカム画面で [Open an existing Android Studio project] を選択してプロジェクト ディレクトリを開きます。
プロジェクトが読み込まれた後、ローカルで行った変更の一部が Git によりトラッキングされていないことを示すアラートが表示される場合もあります。その場合は、[Ignore] または右上の [X] をクリックします(変更を Git リポジトリにプッシュバックすることはありません)。
[Android] ビューの場合は、プロジェクト ウィンドウの左上に次のような画像が表示されます([Project] ビューの場合は、プロジェクトを展開すると同じ画像が表示されます)。
2 つのフォルダ アイコン(start
と complete
)があり、それぞれを「モジュール」と呼びます。
初めてバックグラウンドでプロジェクトをコンパイルする場合、数秒かかる場合があります。その間、Android Studio の下部にあるステータスバーにスピナーが表示されます。
コンパイルが完了するまで、コードを変更しないことをおすすめします。このコンパイルで、必要なすべてのコンポーネントを Android Studio に取り込むことができます。
また、「Reload for language changes to take effect?」のようなメッセージが表示された場合は、[Yes] を選択します。
スターター プロジェクトを理解する
これで、操作の認識を追加する準備が整いました。この Codelab のベースとして、ここでは start
モジュールを使用します。つまり、各ステップで start
にコードを追加していきます。
complete
モジュールは、作業のチェックや、問題が発生した場合の参照用として使用できます。
主要コンポーネントの概要:
MainActivity.kt
: ユーザーがアプリを起動したときに、アプリのメイン画面をレンダリングします。SleepReceiver.kt
: API から睡眠イベントを抽出し、データベースに保存します。BootReceiver.kt
: デバイスの起動が完了したら Sleep API に再登録し、引き続き Sleep API イベントをリッスンします。
スターター プロジェクトを実行する
アプリを実行しましょう。
- Android デバイスをパソコンに接続します。
- ツールバーで、プルダウン メニューから
start
の構成を選択し、デバイスを選択して、その横にある緑色の三角形(Run)ボタンをクリックします。
デバイスにアプリが表示されます。
睡眠状態を記録するコードをまだ追加していませんが、これは以降のセクションで行います。
次のセクションでは、必要なライブラリと権限を確認します。
3. ライブラリを確認して権限を追加する
build.gradle と AndroidManifest.xml を確認する
アプリで Sleep API を使用するには、アプリ マニフェストで Google Location and Activity Recognition API への依存関係を宣言し、com.google.android.gms.permission.ACTIVITY_RECOGNITION
権限を指定する必要があります。
start
モジュールのbuild.gradle
ファイルで「TODO: Review play services library required for activity authentication」を検索します。このステップでは特に作業はありません。必要な依存関係が次のように宣言されていることを確認します。
// TODO: Review play services library required for activity recognition.
implementation 'com.google.android.gms:play-services-location:18.0.0'
start
モジュールのAndroidManifest.xml
で「TODO: Add activity recognition and boot complete permissions」を検索し、次のコードを<manifest>
要素に追加します。
<!-- TODO: Add activity recognition and receive boot complete permissions. -->
<!-- Required for 29+. -->
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
コードは次のようになります。
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.example.sleepcodelab">
...
<!-- TODO: Add activity recognition and receive boot complete permissions. -->
<!-- Required for 29+. -->
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
...
</manifest>
コメントに書いてあるように、API バージョン 29 の実行時の権限を追加する必要があります。
これで、アプリが睡眠の操作の認識をサポートできるようになりました。上記のコードを追加するだけで、これを実現できます。
操作の認識の権限を確認する
必要に応じて、実行時の権限を確認してリクエストする必要があります。
MainActivity.kt
で操作の認識の権限を確認します。- 権限が付与されていない場合は、
displayPermissionSettingsSnackBar()
を呼び出します。このスナックバーにより、権限が必要であることを説明し、ユーザーがシステム設定で権限を承認できるようにします。
start
モジュールの MainActivity.kt
で「TODO: Review Activity Recognition permission check」を検索します。次のコード スニペットが表示されます。
このセクションでの作業は特にありません。
// TODO: Review Activity Recognition permission checking.
private fun activityRecognitionPermissionApproved(): Boolean {
return PackageManager.PERMISSION_GRANTED == ActivityCompat.checkSelfPermission(
this,
Manifest.permission.ACTIVITY_RECOGNITION
);
}
睡眠管理を有効または無効にする
start
モジュールの MainActivity.kt
で「TODO: Enable/Disable Sleep tracking and ask for permissions if needed」を検索し、onClickRequestSleepData()
メソッドを次のコードに置き換えます。
// TODO: Enable/Disable sleep tracking and ask for permissions if needed.
fun onClickRequestSleepData(view: View) {
if (activityRecognitionPermissionApproved()) {
if (subscribedToSleepData) {
unsubscribeToSleepSegmentUpdates(applicationContext, sleepPendingIntent)
} else {
subscribeToSleepSegmentUpdates(applicationContext, sleepPendingIntent)
}
} else {
requestPermissionLauncher.launch(permission.ACTIVITY_RECOGNITION)
}
}
操作の認識の権限が承認され、ユーザーが睡眠データに登録した場合、睡眠データの更新を受信できるように登録します。それ以外の場合は、登録を解除します。
権限が承認されていない場合、スプラッシュ画面を表示して権限が必要な理由を説明し、ユーザーがそこから権限を許可できるようにします。
4. Sleep API の更新を受け取る
PendingIntent を作成する
start
モジュールの MainActivity.kt
で「TODO: Create a PendingIntent for Sleep API events」を検索し、次のスニペットを貼り付けます。
// TODO: Create a PendingIntent for Sleep API events
sleepPendingIntent =
SleepReceiver.createSleepReceiverPendingIntent(context = applicationContext)
これで、Sleep API データが利用可能になったときに通知を受け取れるようになりました。
Sleep API の更新をリクエストする
start
モジュールの MainActivity.kt
で「TODO: Request Sleep API updates」を検索し、次のスニペットを貼り付けます。
// TODO: Request Sleep API updates
val task = ActivityRecognition.getClient(context).requestSleepSegmentUpdates(
pendingIntent,
// Registers for both SleepSegmentEvent and SleepClassifyEvent data.
SleepSegmentRequest.getDefaultSleepSegmentRequest()
)
task.addOnSuccessListener {
mainViewModel.updateSubscribedToSleepData(true)
Log.d(TAG, "Successfully subscribed to sleep data.")
}
task.addOnFailureListener { exception ->
Log.d(TAG, "Exception when subscribing to sleep data: $exception")
}
Sleep API の更新への登録が成功すると、アプリは、登録した PendingIntent 内で睡眠検出通知を受け取るようになります。
起動完了時に再登録する
start
モジュールの receiver/BootReceiver.kt
で「TODO: Request Sleep API upon boot complete」を検索し、次のスニペットを貼り付けます。
// TODO: Request Sleep API upon boot complete
val subscribedToSleepData = repository.subscribedToSleepDataFlow.first()
if (subscribedToSleepData) {
subscribeToSleepSegmentUpdates(
context = context,
pendingIntent = SleepReceiver.createSleepReceiverPendingIntent(context)
)
}
このコードにより、デバイスの再起動後もアプリが Sleep API の更新を受け取れるようになります。
5. イベントを処理する
睡眠の分類または睡眠時間検出のイベントが発生すると、アプリは Intent コールバックを受け取ります。このインテントから、SleepSegmentEvent オブジェクトまたは SleepClassifyEvent オブジェクトのリストを抽出できます。
これらのイベントを処理するコードを追加しましょう。
start
モジュールの receiver/SleepReceiver.kt
で「TODO: Extract sleep information from PendingIntent」を検索し、コメントの後に次のコードを追加します。
// TODO: Extract sleep information from PendingIntent.
if (SleepSegmentEvent.hasEvents(intent)) {
val sleepSegmentEvents: List<SleepSegmentEvent> =
SleepSegmentEvent.extractEvents(intent)
addSleepSegmentEventsToDatabase(repository, sleepSegmentEvents)
} else if (SleepClassifyEvent.hasEvents(intent)) {
val sleepClassifyEvents: List<SleepClassifyEvent> =
SleepClassifyEvent.extractEvents(intent)
addSleepClassifyEventsToDatabase(repository, sleepClassifyEvents)
}
これにより、SleepSegmentEvent
または SleepClassifyEvent
のデータが Room データベースに保存されます。MainActivity は、LiveData を使用して ViewModel 経由でそのデータベース情報にアクセスします。これらのクラスがどのように連携するかについて詳しくは、Room と View の Codelab をご覧ください。
これで完成です。アプリを実行してみましょう。
6. アプリをインストールしてコードを確認する
ケーブルを使用してデバイスをワークステーションに接続します。Android Studio で [Run] をクリックして、デバイスにアプリをインストールして実行します。操作の認識の権限を付与して、[SUBSCRIBE TO SLEEP DATA] ボタンをタップすると、最初の SleepClassifyEvent が約 10 分後に表示されます。SleepSegmentEvent は 1 日以内に表示されます。
コードの全体を読み、この Codelab で加えた変更を振り返ることで、コードがどのように動作するかを理解しやすくなります。
コードレビュー(省略可)
次のコードレビューは省略可能です。これらのコードレビューにより、Sleep API とデータベース エンティティ間のデータ マッピングに関する詳細を把握できます。
data/db/SleepClassifyEventEntity.kt
data/db/SleepSegmentEventEntity.kt