Sleep API
以下抄訳↓
- Sleep APIを活用すると、アプリでユーザーがいつ寝て、いつ起きているかを判断することができます。
- 周囲の明るさ、デバイスの動きなどに関連する情報を収集して、ユーザーが眠りに落ちて目を覚ます時間を推測します。
- 情報の更新を購読することができます。
様々な機能に組み合わせることで効力を発揮しそうなAPIですね。
実際に試してみる
下準備
1. target sdkを29以上に設定する
※29以下だと取得ができないので、minsSDKは29に設定してます
android {
compileSdkVersion 30
buildToolsVersion "30.0.3"
defaultConfig {
applicationId "xxx"
minSdkVersion 29
targetSdkVersion 30
~~~
}
~~~~
}
2. 使用するmoduleのManifestへACTIVITY_RECOGNITIONのpermissionを追加する
<uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION" />
3. 睡眠行動の更新をリクエストする
permissionのcheckを行いrequestSleepSegmentUpdates
をリクエストする
private val sleepPendingIntent: PendingIntent by lazy {
SleepDataReceiver.sleepReceiverPendingIntent(context = requireContext())
}
private val requestPermissionLauncher: ActivityResultLauncher<String> =
registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
if (isGranted) {
// granted
} else {
// not granted
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
subscribeBtn.setOnClickListener {
if (checkActivityRecognitionPermission()) {
// request
subscribeToSleepSegmentUpdates(sleepPendingIntent)
} else {
requestPermissionLauncher.launch(Manifest.permission.ACTIVITY_RECOGNITION)
}
}
}
private fun subscribeToSleepSegmentUpdates(pendingIntent: PendingIntent) {
val task = ActivityRecognition.getClient(
requireContext()).requestSleepSegmentUpdates(
pendingIntent,
SleepSegmentRequest.getDefaultSleepSegmentRequest()
)
task.addOnSuccessListener {
Log.d(TAG, "Successfully")
}
}
実際に利用してみる
1. 睡眠情報を受け取れるようにReceiverを用意
<receiver
android:name=".SleepDataReceiver"
android:enabled="true"
android:exported="true" />
class SleepDataReceiver: BroadcastReceiver() {
companion object {
private const val REQUEST_CODE = 100
fun sleepReceiverPendingIntent(context: Context): PendingIntent {
return PendingIntent.getBroadcast(
context,
REQUEST_CODE,
Intent(context, SleepDataReceiver::class.java),
PendingIntent.FLAG_CANCEL_CURRENT
)
}
}
override fun onReceive(context: Context?, intent: Intent?) {
if (SleepSegmentEvent.hasEvents(intent)) {
val sleepSegmentEvents: List<SleepSegmentEvent> =
SleepSegmentEvent.extractEvents(intent)
// コールバックを用意してSleepSegmentEventsを流す
} else if (SleepClassifyEvent.hasEvents(intent)) {
val sleepClassifyEvents: List<SleepClassifyEvent> =
SleepClassifyEvent.extractEvents(intent)
// コールバックを用意してSleepClassifyEventを流す
}
}
}
コールバックはどんな形でもOKです。
DataStore + Flow + LiveDataなどを利用しても
2. データを眺める
SleepClassifyEventとSleepSegmentEventが取得可能です。
それぞれ以下抄訳↓
-
SleepClassifyEventは睡眠の信頼度、およびデバイスの動きや周囲光レベルなどのサポートデータを含む睡眠分類イベントを表します。分類イベントは、10分ごとに定期的な間隔で報告されます。
-
SleepSegmentEventはユーザーの睡眠開始、終了時間やスリープ状態にあるかを検出した時間などを検出できます。
試しに10分間隔で受信するSleepClassifyEventのログを出してみました。
SleepClasifyのgetTimestampMillisを計測してみました
timestampMillis(UNIX time) | timestampMillis(日付表記) | confidence | light | motion | 端末操作の有無 |
---|---|---|---|---|---|
1616651011 | 2021-03-25 14:43:31 | 3 | 5 | 6 | 有 |
1616651370 | 2021-03-25 14:49:30 | 1 | 5 | 6 | 有 |
1616651858 | 2021-03-25 14:57:38 | 2 | 5 | 4 | 有 |
1616652348 | 2021-03-25 15:05:48 | 4 | 5 | 6 | 有 |
1616652836 | 2021-03-25 15:13:56 | 1 | 5 | 5 | 有 |
1616653325 | 2021-03-25 15:22:05 | 22 | 5 | 4 | 無 |
気付き
- 10分間隔はあくまでおおよそで、実際はある程度誤差がある
- confidenceは基準値低めにしておいても良さそう
- lightの精度は抜群
最後に
confidence以外の精度はかなり高い印象を受けました。
通知を不定期に送る機能と組み合わせ、ユーザーが寝ているであろう時間には送らないようにすることも可能になるかと思います。
気になる方は是非SleepSegmentEvent
も計測してみてください!