17 September 2021
Posted by Peter Visontay, Software Engineer; Bessie Jiang, Software Engineer
Contributors: Inara Ramji, Software Engineer; Rodrigo Farell, Interaction Designer; James Kelly, Product Manager; Henry Chin, Program Manager.
Most users spend a lot of time on their smartphones. Whether working, playing games, or connecting with friends, people often use apps as the primary gateway for their digital lives. In order to work, apps often need to request certain permissions, but with dozens of apps on any given device, it can be tough to keep up with the permissions you’ve previously granted – especially if you haven’t used an app for an extended period of time.
In Android 11, we introduced the permission auto-reset feature. This feature helps protect user privacy by automatically resetting an app’s runtime permissions – which are permissions that display a prompt to the user when requested – if the app isn’t used for a few months. Starting in December 2021, we are expanding this to billions more devices. This feature will automatically be enabled on devices with Google Play services that are running Android 6.0 (API level 23) or higher.
The feature will be enabled by default for apps targeting Android 11 (API level 30) or higher. However, users can enable permission auto-reset manually for apps targeting API levels 23 to 29.
So what does this mean for developers?
Some apps and permissions are automatically exempted from revocation, like active Device Administrator apps used by enterprises, and permissions fixed by enterprise policy.
If needed, developers can ask the user to prevent the system from resetting their app's permissions. This is useful in situations where users expect the app to work primarily in the background, even without interacting with it. The main use cases are listed here.
Current behavior | New behavior |
Permissions are automatically reset on Android 11 (API level 30) and higher devices. | Permissions are automatically reset on the following devices:
|
Permissions are reset by default for apps targeting Android 11 or later. The user can manually enable auto-reset for apps targeting Android 6.0 (API level 23) or later. | No change from the current behavior. |
Apps can request the user to disable auto-reset for the app. | No change from the current behavior. |
If an app targets at least API 30, and asks the user to disable permission auto-reset, then developers will need to make a few simple code changes. If the app does not disable auto-reset, then no code changes are required.
Note: this API is only intended for apps whose targetSDK is API 30 or higher, because permission auto-reset only applies to these apps by default. Developers don’t need to change anything if the app‘s targetSDK is API 29 or lower.
The table below summarizes the new, cross-platform API (compared to the API published in Android 11):
Action | Android 11 API (works only on Android 11 and later devices) |
New, cross-platform API (works on Android 6.0 and later devices, including Android 11 and later devices) |
Check if permission auto-reset is enabled on the device | Check if Build.VERSION.SDK_INT >= Build.VERSION_CODES.R |
Call androidx.core.content.PackageManagerCompat.getUnusedAppRestrictionsStatus() |
Check if auto-reset is disabled for your app | Call PackageManager. |
Call androidx.core.content. |
Request that the user disable auto-reset for your app | Send an intent with action Intent.ACTION_AUTO_REVOKE_PERMISSIONS |
Send an intent created with androidx.core.content. |
This cross-platform API is part of the Jetpack Core library, and will be available in Jetpack Core v1.7.0. This API is now available in beta.
Sample logic for an app that needs the user to disable auto-reset:
val future: ListenableFuture<Int> = PackageManagerCompat.getUnusedAppRestrictionsStatus(context) future.addListener( { onResult(future.get()) }, ContextCompat.getMainExecutor(context) ) fun onResult(appRestrictionsStatus: Int) { when (appRestrictionsStatus) { // Status could not be fetched. Check logs for details. ERROR -> { } // Restrictions do not apply to your app on this device. FEATURE_NOT_AVAILABLE -> { } // Restrictions have been disabled by the user for your app. DISABLED -> { } // If the user doesn't start your app for months, its permissions // will be revoked and/or it will be hibernated. // See the API_* constants for details. API_30_BACKPORT, API_30, API_31 -> handleRestrictions(appRestrictionsStatus) } } fun handleRestrictions(appRestrictionsStatus: Int) { // If your app works primarily in the background, you can ask the user // to disable these restrictions. Check if you have already asked the // user to disable these restrictions. If not, you can show a message to // the user explaining why permission auto-reset and Hibernation should be // disabled. Tell them that they will now be redirected to a page where // they can disable these features. Intent intent = IntentCompat.createManageUnusedAppRestrictionsIntent (context, packageName) // Must use startActivityForResult(), not startActivity(), even if // you don't use the result code returned in onActivityResult(). startActivityForResult(intent, REQUEST_CODE) }
The above logic will work on Android 6.0 – Android 10 and also Android 11+ devices. It is enough to use just the new APIs; you won’t need to call the Android 11 auto-reset APIs anymore.
The new APIs are also compatible with app hibernation introduced by Android 12 (API level 31). Hibernation is a new restriction applied to unused apps. This feature is not available on OS versions before Android 12.
The getUnusedAppRestrictionsStatus()
API will return API_31
if both permission auto-reset and app hibernation apply to an app.