SCHEDULE_EXACT_ALARM or USE_EXACT_ALARM? Android Alarm Permission Explained

Everything you need to know about Alarm permissions in Android

There are 2 types of alarm that you can set in your app, it can either be an inexact alarm or an exact alarm. This totally depends on the use-case your app is targeting. But in most cases, it’s recommended that you create an inexact alarm unless the functionality of your app depends precisely timed alarm.

SCHEDULE_EXACT_ALARM and USE_EXACT_ALARM permission explained
Placeholder image for alarm: Photo by stefan moertl

Using an exact alarm

If your app needs to perform certain operations that are time-sensitive and have to be executed at a precise time then it is okay to use an exact alarm. Otherwise, an inexact alarm should be sufficient to cater the most of the common use cases such as scheduling a background sync or log upload

When the system triggers an exact alarm, it results in consuming a great deal of system resources so one has to be cautious while making use of an exact alarm. Common use cases where an exact alarm is required are an alarm clock app or a calendar app

Use-cases that can be addressed using an exact alarm
  • Showing a time-based notification for a calendar event
  • Developing an alarm or calendar app
Ways to set an exact alarm
  • setExact(): Use setExact() when you want your alarm to be triggered at a nearly precise time in the future. Note that this will still be impacted by the state battery-saving restrictions on the device. If your app’s work is time crtical, consider using setExactAndAllowWhileIdle()
  • setExactAndAllowWhileIdle(): Invoke an alarm at a nearly precise time in the future, even if battery-saving measures are in effect
  • setAlarmClock(): Schedule an alarm that represents an alarm clock. This will cause the device to fully wake the device up causing the screen to turn on, play a sound, vibrate, etc. These alarms will be allowed to trigger even if the system is in a low-power idle (a.k.a. doze) mode
Permissions required:

If you are making use of an exact alarm, you need to declare either of the 2 permissions: SCHEDULE_EXACT_ALARM or USE_EXACT_ALARM. Your app should use exact alarms, and declare either SCHEDULE_EXACT_ALARM or USE_EXACT_ALARM permission, only if a user-facing function in your app requires precisely-timed actions.

If your app targets Android 12 or above, you must obtain the “Alarms & reminders” special app access. To do so, declare the SCHEDULE_EXACT_ALARM permission in your app’s manifest file, as shown below:

<manifest ...>
    <uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/>
    <application ...>
        ...
    </application>
</manifest>

For apps targeting Android 13 and above, you have the choice to declare either the SCHEDULE_EXACT_ALARM or the USE_EXACT_ALARM permission.

<manifest ...>
    <uses-permission android:name="android.permission.USE_EXACT_ALARM"/>
    <application ...>
        ...
    </application>
</manifest>

While both the permissions look similar, they are designed to support different use-cases. Check the details below:

Using USE_EXACT_ALARM permission:

USE_EXACT_ALARM is a restricted permission that is granted automatically. Since this permission is a restricted permission, apps that request this restricted permission are subject to review, and those that do not meet the acceptable use case criteria will be disallowed from publishing on Google Play. Here’s what is mentioned in the Google policies:

Your app must use the USE_EXACT_ALARM functionality only when your app’s core, user facing functionality requires precisely-timed actions, such as:

  • The app is an alarm or timer app.
  • The app is a calendar app that shows event notifications.
https://support.google.com/googleplay/android-developer/answer/9888170?sjid=10510309997098831402-AP

If you have a use case for exact alarm functionality that’s not covered above, you should evaluate if using SCHEDULE_EXACT_ALARM as an alternative is an option.

Using SCHEDULE_EXACT_ALARM permission

Unlike, the SCHEDULE_EXACT_ALARM permission must be granted by the user. System or User can revoke this permission at any point in time. Use canScheduleExactAlarms() method to check whether the permission is granted to your app or not. On revoking the permission, all the future exact alarms will get canceled.

If canScheduleExactAlarms() returns false, You can take the users to the “Alarms & reminders” special app access screen in system settings where they can provide this special access to our app.

val alarmManager: AlarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager

when {
    alarmManager.canScheduleExactAlarms() -> {
         // permission granted
     }
     else -> {
         // open alarm permission screen
         Intent().apply {
            action = ACTION_REQUEST_SCHEDULE_EXACT_ALARM
         }.also {
            startActivity(it)
         }
      }
}

When the SCHEDULE_EXACT_ALARMS permission is granted to your app, the system sends it the ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED broadcast. Implement a broadcast to listen to the state change and perform further actions. The system does not send the broadcast when permission is revoked

Also always make sure to check the current alarm permission state with the broadcast receiver before performing any action. It is important as this check protects your app from the case where the user grants your app permission, and then revokes it almost immediately afterward.

class AlarmReceiver : BroadcastReceiver() {
    private val TAG = "AlarmReceiver"

    override fun onReceive(context: Context, intent: Intent) {
    val alarmManager: AlarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
        when (intent.action) {
            ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED -> {
                if(alarmManager.canScheduleExactAlarms())
                    // Permission granted
            }
            "from alarm" -> {
                // Alarm fired
            }
        }
    }
}

Using an inexact Alarm

When using an inexact alarm, the system invokes the alarm at some point in the future. Although it is not guaranteed to get the alarm delivered at the exactly requested time, an inexact alarm provides some guarantee regarding the timing of alarm delivery while respecting battery-saving restrictions. On Android 12 and above, the system invokes the alarm within one hour of the requested trigger time, unless battery-saving restrictions are on.

Inexact alarms help in conserving the device’s resources as the system can batch these requests and optimize resource utilization.

Use-cases that can be addressed using inexact alarm:
  • Your app needs to upload logs or sync the data with the backend. These operations do not have to be time-critical or precisely timed. You can either make use of AlarmManager’s set() / setAndAllowWhileIdle() or WorkManager
  • You need to perform some action during a certain time window in the future. This can be done using setWindow(). If your app targets Android 12 or above, the smallest allowed window length is 10 minutes.
Ways to set an inexact alarm
  • Trigger an alarm after a specific time
    An alarm can be triggered after a specific time using set()setInexactRepeating(), or setAndAllowWhileIdle() methods. On Android 12 and above, the system invokes the alarm within one hour of the requested trigger time, unless battery-saving restrictions are in effect.
  • Trigger an alarm during a time window
    setWindow() can be used to trigger an alarm during a time window. If your app targets Android 12 or above, the system can delay the delivery of a time-windowed inexact alarm by at least 10 minutes. Because of this, windowLengthMillis parameter values below 600000 are clipped to 600000 Millis
Permissions required

No permission is required to set an inexact alarm

Example
private var alarmMgr: AlarmManager? = null
private lateinit var alarmIntent: PendingIntent
...
alarmMgr = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
alarmIntent = Intent(context, AlarmReceiver::class.java).let { intent ->
    PendingIntent.getBroadcast(context, 0, intent, 0)
}

alarmMgr?.set(
        AlarmManager.ELAPSED_REALTIME_WAKEUP,
        SystemClock.elapsedRealtime() + 60 * 1000,
        alarmIntent
)

I hope this article helps you in implementing alarm permissions correctly. If it does, please leave a comment below.

5 thoughts on “SCHEDULE_EXACT_ALARM or USE_EXACT_ALARM? Android Alarm Permission Explained”

Leave a comment