Android Sleep API 程式碼研究室

1. 簡介

建構項目

在本程式碼研究室中,您會建構 Android 應用程式來偵測使用者的睡眠時間。這個應用程式將:

  • 要求權限
  • 註冊 Android Sleep API
  • 擷取 API 事件並在使用者介面中顯示
  • 不再需要取消註冊

軟硬體需求

  • 最新版本的 Android Studio (Android Build Tools v21 以上版本)
  • 搭載 Android 10 (API 級別 29) 以上版本的裝置

2. 開始設定

複製範例專案存放區

為了方便您盡快上手,我們準備了新手範例專案。在終端機 / 指令列中輸入 git --version,確認您使用 git。如果尚未安裝,請按照這裡的操作說明安裝。然後執行下列指令,以複製專案。

 git clone https://github.com/googlecodelabs/android-sleep/

匯入專案

啟動 Android Studio,然後在歡迎畫面中選取「Open an existing Android Studio project」(開啟現有 Android Studio 專案),然後開啟專案目錄。

專案載入後,系統也可能會顯示快訊,通知您 Git 不會追蹤所有本機變更。您可以按一下「Ignore」(忽略) 或右上方的「X」。(系統不會將任何變更推送回 Git 存放區。)

如果在「Android」檢視畫面中,專案視窗的左上角會顯示如下的圖片。(在「Project」(專案) 檢視畫面中,您必須展開專案才能看到相同的項目)。

1401a11c10711a60.png

共有兩個資料夾圖示 (startcomplete)。每個資料夾圖示都稱為「module」(模組)。

請注意,由於 Android Studio 首次會在背景編譯專案,因此可能需要幾秒鐘的處理時間。在此期間,Android Studio 底部的狀態列會顯示旋轉圖示:

4bc64eb3b99eb0ae.png

建議您等到此動作完成後再變更程式碼。這使 Android Studio 提取所有必要的元件。

此外,如果畫面顯示「Reload for language changes to take effect?」(重新載入語言變更是否生效?) 的提示,或類似內容,請選取「Yes」(是)。

瞭解範例專案

一切準備就緒,可以新增活動辨識功能了。我們將使用 start 模組,這是本程式碼研究室的起點。換句話說,您必須在每個步驟中新增程式碼至 start

complete 模組可用於檢查你的作品,在發生問題時也可以參考。

主要元件總覽:

  • MainActivity.kt:在使用者啟動應用程式時顯示應用程式主畫面。
  • SleepReceiver.kt:從 API 擷取並儲存睡眠事件至資料庫。
  • BootReceiver.kt:在裝置開機完成時重新註冊 Sleep API,以便監聽 Sleep API 事件。

執行範例專案

執行應用程式。

  1. 將 Android 裝置連接到電腦。
  2. 在工具列中,從下拉式選取器中選取 start 設定,選取您的裝置,然後按一下旁邊的綠色三角形 (執行) 按鈕:

177045a302bf57d8.png

裝置上應會顯示下列應用程式:

30efe28b9757e1e7.png

311c83ca64556d94.png

我們實際上並未新增任何用於追蹤睡眠的程式碼,這將列於後面的章節。

我們將在下一節查看必要的程式庫和權限。

3. 查看程式庫及新增權限

查看 build.gradle 和 AndroidManifest.xml

若要在應用程式中使用 Sleep API,您必須宣告 Google 位置和活動辨識 API 的依附元件,並在應用程式資訊清單中指定 com.google.android.gms.permission.ACTIVITY_RECOGNITION 權限。

  1. start 模組的 build.gradle 檔案中,搜尋 「TODO: Review play services library required for activity recognition」(TODO:查看活動辨識所需的遊戲服務程式庫)。這個步驟沒有任何動作。只需查看我們宣告的依附元件,看起來應該像這樣:
    // TODO: Review play services library required for activity recognition.
    implementation 'com.google.android.gms:play-services-location:18.0.0'
  1. start 模組中,搜尋 AndroidManifest.xml 中的 「TODO: Add activity recognition and boot complete permissions」(TODO:新增活動辨識與啟動完整權限),並將下列程式碼加進 <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()。這個 Snackbar 說明權限的需求,並讓使用者可在系統設定中核准該權限。

start 模組中,搜尋 MainActivity.kt 中的 「TODO: Review Activity Recognition permission check」(TODO:查看活動辨識權限檢查)。此時,你會看到這個程式碼片段。

注意:這個部分沒有任何動作。

// 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」(TODO:啟用/停用睡眠追蹤功能,並視情況要求權限)。請將 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: Pending a PendingIntent for Sleep API events」(TODO:暫停 Sleep API 事件的 PendingIntent)。貼上下列程式碼片段。

// 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:要求取得 Sleep API 更新通知)。貼上下列程式碼片段。

// 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」(TODO:要求取得 Sleep API)。貼上下列程式碼片段。

// 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 回呼。您可以從 Intent 擷取 SleepSegmentEventSleepClassifyEvent 物件的清單。

讓我們新增程式碼來處理這些事件。

start 模組中,搜尋 receiver/SleepReceiver.kt 中的 「TODO: Extract sleep information from PendingIntent」(TODO:從 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)
}

這項操作會將 SleepSegmentEventSleepClassifyEvent 資料儲存至會議室資料庫。MainActivity 使用 LiveData 透過 ViewModel 存取該資料庫資訊。若要進一步瞭解這些類別如何搭配運作,請參閱設有檢視畫面程式碼研究室的聊天室

這樣就完成了!請嘗試執行應用程式。

6. 安裝應用程式並查看程式碼

使用傳輸線將裝置連結至工作站。在 Android Studio 中按一下「Run」(執行),即可在您的裝置上安裝及執行應用程式。授予活動辨識權限並輕觸「SUBSCRIBE TO SLEEP DATA」(訂閱睡眠資料) 按鈕後,第一個 SleepClassifyEvent 應該會在 10 分鐘後顯示,或 SleepSegmentEvent 應該會在 1 天內顯示。

歡迎您隨時詳閱程式碼,瞭解自己完成的部分,並進一步瞭解程式碼如何搭配運作。

查看程式碼 (選擇性)

以下查看程式碼是選擇性。其中包含 Sleep API 和資料庫實體之間的資料對應詳細資料:

  • data/db/SleepClassifyEventEntity.kt
  • data/db/SleepSegmentEventEntity.kt

參考說明文件