Android Sleep API Tutorial: Getting Started
Learn how to use the Android Sleep API in your Kotlin apps to track when the user is asleep, awake, how long they slept, and the confidence of the results. By Roberto Orgiu.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Android Sleep API Tutorial: Getting Started
15 mins
In this tutorial, you’ll learn how to interact with the Android Sleep API and react to the stream of events sent by the system. The Android Sleep API collects information such as surrounding brightness and device movement to make assumptions about when the user is asleep or awake.
This API is handy for tracking users’ sleep patterns to help them improve their sleep habits.
While building a simple sleep tracking app, you’ll how to:
- Request Activity Recognition permissions for your app.
- Register a Sleep Receiver to filter and analyze the different events sensed by the device.
With that, it’s time to jump right in! Try not to fall asleep. ;]
Getting Started
Click
Import the starter project in Android Studio. Build and run it. You’ll see a classic sample screen:
You won’t interact with the UI much in this tutorial, so building and running the app is more about checking the code’s correctness.
Using the Android Sleep API
To use this API, you’ll need two pieces of code:
- The
ActivityRecognition
client that lets you subscribe to sleep updates. - A
BrodcastReceiver
, to receive the updates from theActivityRecognition
client.
Additionally, you need to ask the user for permission to listen to their sleep data, which they grant outside the app, in the Settings screen.
This API will provide two sets of information:
- The confidence level that your user is sleeping, which the API reports periodically a few minutes after the previous emission.
- The daily sleep segment the API emits once the device detects the user is awake.
To use this API, you first need to include the dependencies. Open app ‣ build.gradle and add the following line in the dependencies
block:
implementation 'com.google.android.gms:play-services-location:18.0.0'
Now you’re all set to start writing some code.
Listening for Sleep Data
Before you can do anything else, you need to receive sleep data. The component that provides this information is the BroadcastReceiver
.
Open SleepReceiver.kt. Notice SleepReceiver
already extends BroadcastReceiver
with an empty onReceive
. This method is where you’ll add the logic that filters the data.
Open AndroidManifest.xml. You’ll see SleepReceiver
is already declared inside, right below MainActivity
. It looks like this:
<receiver
android:name=".receiver.SleepReceiver"
android:enabled="true"
android:exported="true" />
You need to declare SleepReceiver
in AndroidManifest.xml so the system knows BroadcastReceiver
is available in your app.
Now that you have SleepReceiver
set up, it’s time to write the logic that will filter the events coming from the Intent
.
Filtering Sleep Data
Open SleepReceiver. Add the following statement inside onReceive()
:
if (SleepSegmentEvent.hasEvents(intent)) {
} else if (SleepClassifyEvent.hasEvents(intent)) {
}
Here, you check whether the Intent
contains SleepSegmentEvents
or SleepClassifyEvents
.
Next, add the following companion object to the bottom of the class:
companion object {
private const val TAG = "SLEEP_RECEIVER"
}
You’ll use this tag to log events to the console and filter the text you’ll show in a few lines.
Now, to focus on the first branch of the if
statement!
Right below the if
line, add:
val events =
SleepSegmentEvent.extractEvents(intent)
Log.d(TAG, "Logging SleepSegmentEvents")
for (event in events) {
Log.d(TAG,
"${event.startTimeMillis} to ${event.endTimeMillis} with status ${event.status}")
}
In case the Intent
you receive contains a SleepSegmentEvent
, you extract it and print its starting and ending timestamps and its status to the console. This represents the UNIX timestamp when the device detected the user began sleeping, woke up and a status code that indicates if the system succeeded in collecting sleep data, respectively.
Now you can get the sleep segments, but you also want to classify the events. You can do this in the statement’s else
branch by adding:
val events = SleepClassifyEvent.extractEvents(intent)
Log.d(TAG, "Logging SleepClassifyEvents")
for (event in events) {
Log.d(TAG,
"Confidence: ${event.confidence} - Light: ${event.light} - Motion: ${event.motion}"
)
}
Once again, you need to extract the information about the event and print its data to the console, highlighting the confidence level of the classification, light quantity and value of the motion.
At this point, if you build and run the app, you won’t see any output in the console. You still need to take a few more steps before you can get the data!
Requesting Activity Recognition Permissions
To get the sleep data, you need to have permission from your user to access it. It’s not as straightforward as with other permissions since you need to open the settings for the data, and the user needs to grant your app the Activity Recognition permissions. But it’s not that complicated either.
First, open AndroidManifest.xml and add the following permission within manifest
:
<uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION" />
Next, you need to create a method inside MainActivity.kt that will open the settings screen. Open MainActivity and add the following, importing android.provider.Settings
:
private fun requestActivityRecognitionPermission() {
val intent = Intent().apply {
action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
data = Uri.fromParts("package", BuildConfig.APPLICATION_ID, null)
flags = Intent.FLAG_ACTIVITY_NEW_TASK
}
startActivity(intent)
}
Here you create the Settings Intent
, adding the Activity Recognition action and your app package extra. You then run the Intent
.
Now, since you need to request permissions, you can leverage the ActivityResultContracts
API, which will help reduce the boilerplate to listen for the activity result.
Start by adding the activity ktx library to app ‣ build.gradle:
implementation 'androidx.activity:activity-ktx:1.2.3'
Sync your gradle file. This adds ActivityResultContracts
and ActivityResultLauncher
to your project.
Then, add this property to MainActivity
:
private val permissionRequester: ActivityResultLauncher<String> =
registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted ->
if (!isGranted) {
requestActivityRecognitionPermission()
} else {
// Request goes here
}
}
Here, you create an object that will listen for the Activity result from your permission request and pass it to you once this object parses it.
It’s not time to build and run your app yet. If you try, it still won’t show any data. But it will soon!