Android M introduces a new runtime permissions model. Under this model, user is not presented with a list of permissions at
install or update time. Instead, an app throws a pop-up at runtime when it
needs a permission in order to complete a specific action (e.g. reading
contacts, taking picture etc.). Once an app is installed on an Android M device, a user
has the option to revoke permissions by navigating to the settings screen. Android M
introduces a new Context.checkSelfPermission() API that an app targeted for M must use to check if it currently has the required permission
to perform a specific operation. Also, on M, an app can request permissions at runtime by calling Activity.requestPermissions() API. But, what if you
are still not prepared to support the new permissions model and the targetSdkVersion
of your app is still API level 22 or lower? In another scenario, what if someone tries to install your legacy app on M developer preview and turns off its permissions? Will this break your
app’s functionality and cause your app to crash?
In answer to the above described scenarios, your app will not crash and M will return an empty data set. For example, if you request to read Contacts Provider component, and the Contacts permission is revoked, you will get no results. In this blog post, I will demonstrate how Android M gracefully handles permission revocation for legacy apps to be forward compatible when a user turns off app permissions at runtime.
In answer to the above described scenarios, your app will not crash and M will return an empty data set. For example, if you request to read Contacts Provider component, and the Contacts permission is revoked, you will get no results. In this blog post, I will demonstrate how Android M gracefully handles permission revocation for legacy apps to be forward compatible when a user turns off app permissions at runtime.
Note: this post is based off release 1 of Android M Developer Preview. The way runtime permission revocation works is subject to
change.
An example
I created an example project on Github consisting of a single Activity that reads phone contacts. The focus here should not be the code that queries the ContactProvider to retrieves contacts, but to see how Android M reacts to turning off permission at runtime post install or update.Adding permissions in AndroidManifest.xml
You still need to declare permissions in the Manifest. The
following code snippet shows that the app claims READ_CONTACTS permission.
<uses-permission android:name="android.permission.READ_CONTACTS" />
Given that the targetSdkVersion of our app is 22 (Lollipop
5.1 release), all permissions claimed by the app shall be presented to the user
at install time. It's worth noting that the READ_CONTACTS permission
falls under the CONTACTS group. A permission group is a logical classification
of related permissions. Screenshot 1 below shows the app running when Contacts permission is granted on an Android M Developer Preview release 1 Android Virtual Device (AVD) .
Revoking permissions
As mentioned earlier, on M, users can revoke an app's
permissions at any time after the initial install or update. Screenshot 2 shows the permissions settings screen for our app. As you can see, currently, Contacts permission is enabled.
Screenshot 2: Granular app permission in settings |
Screenshot 3 depicts a pop-up that user sees when revoking app permissions.
Screenshot 3: User can revoke any permission at runtime |
Since the targetSdkVersion of our app is 22, when the user turns off permission after it is installed (or updated), Android M will throw a warning message indicating that the app may malfunction. If the user clicks on Deny, permission to read Contacts will be revoked, but the OS will not notify our app. That said, Android would handle permission revocation by returning no data when a legacy app
calls a permission protected API. You will not get a SecurityException if a
user turns off an app’s permission. In our contacts app, you will notice that
after we turn off the Contacts permission, our app will continue to run but we
will not get any contacts. The ContactsProvider will return an empty set. The cursor
will have zero results. Screenshot 4 shows our contacts app when Contacts permission is turned off.
Screenshot 4: after revoking the Contacts permission, the dataset is empty |
Caution: According to
this Google I/O 2015 talk, when a user turns off an app’s permission while it is performing a certain restricted feature, M shall terminate the process.
Backward compatibility
If you install an app that uses the new permissions model on
a device that is not running M, system will behave the old way, that is, the user will be prompted to grant all permissions declared in the Manifest file at install and update time only.
Conclusion
From a user experience standpoint, granular app permissions
make sense. Users will be presented with a pop-up message the first time an app
tries to use a protected API (for that action alone) or it can even request
specific permissions, instead of presenting a bunch of permissions at install
or update time. For example, when a user presses the microphone button, an app
can request for the microphone permission. A user would always know the exact reason
for the requested permission. Your
legacy apps will continue to work even if a user turns off its permissions
after install or update. But, your app may not behave properly because now
you will get empty set or fake data. As developers, it is in our best interest to
migrate to the new runtime permissions model introduced by Android M. Also, if
an app targets the M Developer Preview, it must use the new
permissions model. This means that in addition to declaring permissions in the
Manifest, an app must also leverage the new APIs at runtime to check whether it
has the required permission, and request permissions if the user has revoked
them.
References
http://developer.android.com/preview/features/runtime-permissions.html#compatibility
http://developer.android.com/preview/index.html
https://www.youtube.com/watch?v=f17qe9vZ8RM
http://developer.android.com/preview/index.html
https://www.youtube.com/watch?v=f17qe9vZ8RM