Begin and End Sleep Tracking

For sleep tracking, the app must continuously perform recording, data processing, and network operations throughout the night. However, the Android OS may enter Doze Mode, which can disable microphone and network resources or suspend running processes, imposing various restrictions. As a result, the sleep tracking process may be interrupted.

To address this issue, developers typically use a Foreground Service to separate tasks into a persistent process. However, this approach can be complex and challenging to implement.

To simplify this process, we have abstracted all these complexities within the SDK. Now, developers can easily start and stop sleep tracking by simply calling beginSleepTracking() and endSleepTracking(). This reduces the development burden and enables a faster and more stable implementation of sleep tracking functionality.

📘

Additional Guidance for Hardware Control

If hardware control must be guaranteed based on Sleep Stage values during sleep, the built-in SDK functionality may have limitations.
In such cases, you should either:

  • Implement control using a Webhook Server.
  • Design a custom Foreground Service to ensure uninterrupted operation throughout the night.

Begin SleepTracking

Asleep.beginSleepTracking()

  • This function starts the sleep tracking process, and the following tasks are performed automatically:

    1. Foreground Service Execution: The Foreground Service starts automatically, ensuring background tasks remain stable.
    2. Notification Display:
      • According to Android system policies, a notification will be displayed in the status bar while the foreground service is running.
      • This notification informs the user that sleep tracking is in progress and can support user interaction if needed.
    3. Start Sleep Tracking:
      • The SleepTrackingManager immediately begins the sleep tracking process.
beginSleepTracking(
		asleepConfig: AsleepConfig,
  	notificationClass: Class<*>? = null,
  	notificationTitle: String? = null,
  	notificationText: String? = null,
  	notificationIcon: Int? = null,
  	asleepTrackingListener: AsleepTrackingListener
)

ParameterTypeDescription
asleepConfigAsleepConfigValue received from initAsleepConfig.
notificationClassClass<*>?Activity to open when tapping the foreground service notification.
notificationTitleString?Title of the foreground service notification.
notificationTextString?Body text of the foreground service notification.
notificationIconInt?Icon resource for the foreground service notification.
asleepTrackingListenerAsleep.AsleepTrackingListenerListener to receive callbacks during sleep tracking

AsleepNotificationConfig (v3.3.0)

The four notification parameters (notificationClass · notificationTitle · notificationText · notificationIcon) can be passed bundled into a single object. The behavior is the same as before, only the form in which they are passed is different.

beginSleepTracking(
    asleepConfig: AsleepConfig,
    notificationConfig: AsleepNotificationConfig?,
    asleepTrackingListener: AsleepTrackingListener
)
val notificationConfig = AsleepNotificationConfig.Builder()
    .setActivityClass(MainActivity::class.java)
    .setTitle("Sleep Tracking")
    .setText("Good night!")
    .setSmallIcon(R.drawable.ic_sleep)
    .build()

Asleep.beginSleepTracking(
    asleepConfig = asleepConfig,
    notificationConfig = notificationConfig,
    asleepTrackingListener = asleepTrackingListener
)
Builder methodMatching existing parameterDefault value
setActivityClass(cls)notificationClassNone (tapping the notification does not navigate)
setTitle(title)notificationTitle"Sleep Tracking"
setText(text)notificationText"Good night!"
setSmallIcon(resId)notificationIconThe system default icon
  • If you pass null to notificationConfig, every value is applied as its default.
  • Passing the four existing parameters as before keeps working. Use whichever is more convenient.
  • It can also be used together with CompletableAsleepTrackingListener.
Asleep.beginSleepTracking(
    asleepConfig = asleepConfig,
    notificationConfig = notificationConfig,
    completableAsleepTrackingListener = completableListener,
    recordingPath = recordingPath,
    recordingType = RecordingType.ALL
)
📘

AsleepNotificationConfig is Parcelable, so it is passed to the foreground service as it is.

There is nothing else to handle.

Asleep.AsleepTrackingListener

  • An interface that provides callbacks for the start, end, and status of sleep tracking.
interface AsleepTrackingListener {
  	fun onStart(sessionId: String)
  	fun onPerform(sequence: Int)
  	fun onFinish(sessionId: String?)
  	fun onFail(errorCode: Int, detail: String)
}
FunctionParameterTypeDescription
onStartsessionIdStringCalled when sleep tracking starts, providing the session ID.
onPerformsequenceIntCalled every 30 seconds during analysis, providing a sequence value starting from 0.
onFinishsessionIdStringCalled when sleep tracking ends, providing the session ID of the completed session.
onFailerrorCodeIntCalled if an error occurs during the sleep tracking process, returning an errorCode.
detailStringAdditional description related to the errorCode.

Termination Based on Error Codes

If the following errors are returned in the errorCode parameter of onFail(), sleep tracking is considered unable to continue and will automatically terminate, triggering the onFinish() callback.

ERR_AUDIO, ERR_CREATE_FAILED, ERR_CREATE_UNAUTHORIZED, ERR_CREATE_CONFLICT, ERR_CREATE_VALIDATION, ERR_CREATE_SERVER_ERROR, ERR_UPLOAD_TRACKING_TERMINATED, ERR_CLOSE_FAILED, ERR_CLOSE_BAD_REQUEST, ERR_CLOSE_UNAUTHORIZED, ERR_CLOSE_FORBIDDEN, ERR_CLOSE_NOT_FOUND, ERR_CLOSE_SERVER_ERROR

For other errors, sleep tracking will not be terminated, even if temporary issues prevent proper measurement:

ERR_AUDIO_SILENCED, ERR_AUDIO_UNSILENCED, ERR_UPLOAD_FAILED


Analysis complete notification · saving recording files (v3.3.0)

If you pass a CompletableAsleepTrackingListener, onComplete is called when the server analysis is finished after tracking is stopped. The optional parameters (recordingPath, recordingType) for saving the recording files of snoring · unstable-breathing sections can be used together with it.

val notificationConfig = AsleepNotificationConfig.Builder()
    .setActivityClass(MainActivity::class.java)
    .setTitle("Sleep Tracking")
    .setText("Good night!")
    .build()

val recordingPath = context.getExternalFilesDir(null)?.absolutePath + "/recordings"

Asleep.beginSleepTracking(
    asleepConfig = asleepConfig,
    notificationConfig = notificationConfig,
    completableAsleepTrackingListener = object : Asleep.CompletableAsleepTrackingListener {
        override fun onStart(sessionId: String) { }
        override fun onPerform(sequence: Int) { }
        override fun onFinish(sessionId: String?) { }
        override fun onComplete(session: Session?) { }
        override fun onFail(errorCode: Int, detail: String) { }
    },
    recordingPath = recordingPath,
    recordingType = RecordingType.ALL
)
ParameterTypeDescription
completableAsleepTrackingListenerCompletableAsleepTrackingListenerListener to receive tracking events and the analysis complete notification
recordingPathString?Path to save the recording files. If omitted or null, no recording file is created. Default null
recordingTypeRecordingTypeType of recording to keep. Applied only when recordingPath is set. Default ALL
🚧

recordingPath / recordingType are available only on the Completable listener overload. If you pass them together with the existing AsleepTrackingListener, they are rejected with onFail(11009).

Asleep.CompletableAsleepTrackingListener

interface CompletableAsleepTrackingListener {
    fun onStart(sessionId: String)
    fun onPerform(sequence: Int)
    fun onFinish(sessionId: String?)
    fun onComplete(session: Session?)
    fun onFail(errorCode: Int, detail: String)
}
  • onComplete(session) — Called when the server analysis is finished after tracking is stopped and the result can be retrieved.
  • The other callbacks, onStart, onPerform, onFinish and onFail, are the same as in the existing AsleepTrackingListener.

Callback flow

[AsleepTrackingListener (existing)]
onStart → onPerform(0) → onPerform(1) → … → onFinish

[CompletableAsleepTrackingListener]
onStart → onPerform(0) → … → onFinish → onComplete or onFail(28000)

The check for analysis completion runs every 3 seconds after the session is stopped, up to 10 times (about 30 seconds).

📘

ERR_COMPLETE_TIMEOUT(28000) is not a tracking failure. The session has already been closed normally (onFinish), and it only means that the analysis did not finish within 30 seconds. Retrieve the result with Reports.getReport(sessionId) a little later.

The location and number of the recording files, RecordingType and how to use Asleep.createRecordingFileManager() are the same as in the "Saving recording files" section of the SleepTrackingManager page.



Asleep.getCurrentSleepData()

  • Retrieves real-time sleep data measured so far.
Asleep.getCurrentSleepData(asleepSleepDataListener = object: Asleep.AsleepSleepDataListener {
  	override fun onSleepDataReceived(session: Session) {
  	}
  	override fun onFail(errorCode: Int, detail: String) {
  	}
})

Asleep.AsleepSleepDataListener

  • On success, retrieves the session values through the onSleepDataReceived() function.
  • On failure, returns an errorCode through the onFail() function.
interface AsleepSleepDataListener {
  	fun onSleepDataReceived(session: Session)
		fun onFail(errorCode: Int, detail: String)
}

Asleep.isSleepTrackingAlive()

  • This function checks whether sleep tracking is currently in progress.
  • If the Foreground Service is running, it returns true.
  • When the app starts, calling this function will determine if sleep tracking is active.
    • If true is returned, the app should display a UI indicator to inform the user that sleep tracking is in progress.
Asleep.isSleepTrackingAlive(context: Context)

Asleep.connectSleepTracking()

  • If isSleepTrackingAlive() returns true, it means sleep tracking is running normally.
  • In this case, re-register the AsleepTrackingListener to receive events and data related to the sleep tracking status.
  • This ensures synchronization between the sleep tracking process and the UI state.
Asleep.connectSleepTracking(asleepTrackingListener: AsleepBeginEndTrackingListener)

End SleepTracking

Asleep.endSleepTracking()

This function stops the sleep tracking session started with beginSleepTracking().

  • Calling this function immediately halts sleep tracking.
  • The Foreground Service is also terminated, ensuring that all sleep tracking-related processes are safely and completely stopped.
Asleep.endSleepTracking()

Specifying the analysis range (v3.3.0)

When you stop tracking, you can specify the range (start · end time) that the server will analyze yourself. For example, use it when you want to analyze only the "time the user fell asleep ~ time the user woke up" that the user entered.

// Analyze the whole tracking (existing)
Asleep.endSleepTracking()

// Analyze only the specified range
Asleep.endSleepTracking(analysisStartTime, analysisEndTime)
ParameterTypeDescription
analysisStartTimeDateAnalysis start time
analysisEndTimeDateAnalysis end time. It must be later than analysisStartTime
  • The two values are always passed together. To stop without a range, call Asleep.endSleepTracking().
  • If the start time is later than or the same as the end time, onFail(11009) is called without a server request and then the session is closed without a range.
  • If the server rejects the range (400), the SDK requests the close again without the range. If it succeeds, the normal flow proceeds and the app is not notified separately.
  • If a range is specified, Session.startTime / endTime become the times of the analysis range, and the stage arrays are returned only for that range. Check the information about the analyzed range with Report.analysis on the Reports page.

📘

Refer to the Sample App for Sleep Tracking using the Begin-End method.


Did this page help you?