5

The Quick Developers Guide to Migrate Their Apps to Android 11

 3 years ago
source link: https://proandroiddev.com/the-quick-developers-guide-to-migrate-their-apps-to-android-11-e4ca2b011176
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

The Quick Developers Guide to Migrate Their Apps to Android 11

Getting your app ready for Scoped Storage, Package Visibility, Permission changes, and much more…

Image for post
Image for post
Photo by Mika Baumeister on Unsplash

Android 11 has been launched already and is soon to be released on Android phones from most of the major manufactures. Android 11 is much awaited with features like Enhanced 5G Support, Native Screen Recorder, Notifications Priority Conversations, Notification Chat Bubble, and many privacy enhancements like Scoped Storage and Package Visibility.

Most of the apps are already ready to rock Android 11, but for some of you who have still not acknowledged this change, it is high time and this article is specifically for you.

In this article, we will quickly start with the important stuff first and later will be reviewing some good-to-have enhancements and deprecations of existing APIs and features.

So without further ado, let's quickly review what Android 11 got for us.

Foreground Service Type

If your app targets Android 11 (API level 30) or higher and accesses the camera or microphone in a foreground service, then you will have to declare the camera or microphone foreground service types, respectively, as attributes of your <service> component.

<manifest>
...
<service ...
android:foregroundServiceType="location|camera|microphone" />
</manifest>

Add foreground service types of Work Manager Workers

Similar to foreground services, if you have a long-running worker that requires access to location, camera, or microphone, then you need to declare the worker’s foreground service type in your app’s manifest.

<service
android:name="androidx.work.impl.foreground.SystemForegroundService"
android:foregroundServiceType="location|camera|microphone"
tools:node="merge" />

Note the Service name here.

android:name=”androidx.work.impl.foreground.SystemForegroundService”

To learn more, refer to “Support for long-running workers”.

Background Location Permission

In the previous version of Android, ie. Android 10, we need to ask for Background Location permission in order for our app to access the location in the background.

In Android 11, it is taking one step further as now Background Permission cannot be given access before the Foreground Location Permission.

That means Foreground and Background Location Permissions cannot be requested together. If you request a foreground location permission and the background location permission at the same time, the system ignores the request and doesn’t grant your app either permission.

Another important point to note is that beginning with Android 11, the system dialog doesn’t include the Allow all the time option. Instead, users must enable the background location from the app’s settings page.

Image for post
Image for post
App’s Settings page

Other enhancements in Permissions

One-Time Permissions

Considering the User’s Privacy in mind, whenever your app requests permission related to location, microphone, or camera, Android now gives the option to the user to allow permission only once. This means as soon as your app gets killed, all the One-Time permissions will be revoked.

Image for post
Image for post
Permission Dialog in Android 11, with Background Location Permission request

Some Important points here to keep in mind are:

  • It is applicable only for Runtime permissions.
  • If the user sends your app to the background, your app can continue to access the data for a short period of time.
  • If you launch a foreground service while the activity is visible, and the user then moves your app to the background, your app can continue to access the data until that foreground service stops. And even if the user enters the activity again while the foreground service was running, then the granted permission will remain accessible.

Although for One-Time Permission you don't have to handle anything in your code, it is still worth mentioning, as it may affect your existing functionality especially if you are not following the best practices for requesting location permissions.

The system can Auto Revoke permissions from unused apps

If your app targets Android 11 or higher and isn’t used for a few months, the system protects user data by automatically resetting the sensitive runtime permissions that the user had granted your app.

Auto Revoked Permissions can be disabled from the app’s settings page, as shown below.

Image for post
Image for post

Alternatively, you can request the user to disable it by sending him to the permissions page, using action Intent.ACTION_AUTO_REVOKE_PERMISSIONS

Y̵o̵u̵ ̵c̵a̵n̵ ̵a̵l̵s̵o̵ ̵c̵o̵n̵f̵i̵g̵u̵r̵e̵ ̵A̵u̵t̵o̵ ̵R̵e̵v̵o̵k̵e̵ ̵P̵e̵r̵m̵i̵s̵s̵i̵o̵n̵s̵ ̵p̵r̵o̵g̵r̵a̵m̵m̵a̵t̵i̵c̵a̵l̵l̵y̵ ̵b̵y̵ ̵u̵s̵i̵n̵g̵ ̵a̵n̵d̵r̵o̵i̵d̵:̵a̵u̵t̵o̵R̵e̵v̵o̵k̵e̵P̵e̵r̵m̵i̵s̵s̵i̵o̵n̵s̵ ̵a̵t̵t̵r̵i̵b̵u̵t̵e̵ ̵i̵n̵ ̵y̵o̵u̵r̵ ̵a̵p̵p̵s̵ ̵M̵a̵n̵i̵f̵e̵s̵t̵ ̵f̵i̵l̵e̵.̵
Note that the
android:autoRevokePermission attribute is no longer used and will do nothing.

Further, you can programmatically check if Auto Revoke Permissions are whitelisted or not

public boolean PackageManager#isAutoRevokeWhitelisted ()
Check for Auto Revoke Permission whitelisting and if not, send the user to the app’s settings page

Permission Dialog Visibility

Repeated denial of runtime permission by the user will imply “Don’t ask again”. The system then will no longer prompt the user with the permission dialog and you have to request the user to grant permission from the apps settings page.

Make sure you are already following the best practices to request runtime permissions.

Scoped Storage

Scoped Storage was first introduced in Android 10, to give users more control over their files and to limit file clutter. What Scoped Storage really is, simply, instead of giving the app permission to view/modify whole external storage, give it access only to the app-specific directory on external storage, as well as specific types of media that the app has created.

Scoped Storage is necessary to —

  • protect the user’s data
  • prevent apps from scattering files all over the disc
  • delete junk app files when that app is uninstalled

By introducing Scoped Storage, they separated storage into collections and limiting broad access to shared storage. Storage is divided into:

  • Apps Private Storage — Internal or External storage accessible only by your app.
  • Shared Storage — With is further categorized into Photos, Videos, Audio, and Downloads.
Image for post
Image for post
Source: Google

In Android 10 scoped storage was very controversial and thankfully optional.
But this is not the case with Android 11. With some changes to it, Scoped Storage is now mandatory for Android 11.

Luckily, in Android 11, apart from MediaStore APIs, we can use

  • Regular Java’sFile API (with is internally delegated to MediaStore API)
  • Native libraries, such as fopen().

Modifying the media files is not as same as before, you require the user’s consent for that. Using createWriteRequest() and createDeleteRequest() you can write and delete the media file respectively. Both methods support modifying multiple files (Bulk Operation) at the same time with a single request.

Also, two new Media Store concepts are introduced:

  • Trash — Similar to a Recycle bin on Windows OS, where you can restore the media files or else they will be deleted permanently after some time. This can be achieved usingcreateTrashRequest().
  • Favorites — Media files can be marked favorites by the user. This can be achieved usingcreateFavoriteRequest().

If your app still has files stored outside of the app and your app targets API level 29, use the requestLegacyExternalStorageattribute and migrate your files to the app directory.

Apps that run on Android 11 but target Android 10 (API level 29) can still request the requestLegacyExternalStorage attribute.

Refer to this helpful tutorial by Raywanderlitch: “Scoped Storage Tutorial for Android 11: Deep Dive” to help you get started with the Scoped Storage and alternatively you can refer to “Storage updates in Android 11” from the official Android Documentation.

Package Visibility

Earlier, apps could query the full list of installed apps on the system using methods like queryIntentActivities(). Mostly, I was far broader access you what you actually require.

With Android 11, this is no longer the case. Using the <queries> element, apps can define the set of other packages that they can access. This element helps encourage the principle of least privilege by telling the system which other packages to make visible to your app.

If your app targets Android 11 or higher, you might need to add the <queries> element in your app's manifest file. Within the <queries> element, you can specify packages by name, by intent signature, or by provider authority.

<manifest package="com.example.myapp">
<queries> <!-- Specific apps you interact with, eg: -->
<package android:name="com.example.store" />
<package android:name="com.example.maps" />

<!--
Specific intents you query for,
eg: for a custom share UI
-->
<intent>
<action android:name="android.intent.action.SEND" />
<data android:mimeType="image/png" />
</intent> </queries>
...
</manifest>

Example

Suppose you want to send an email, you have to create an Intent for it and let the system find an appropriate app to handle the request.

val intent = Intent().apply {
action = Intent.ACTION_SENDTO
data
= (Uri.parse("mailto:[email protected]"))
putExtra(Intent.EXTRA_EMAIL, "Hi! How are you?")
putExtra(Intent.EXTRA_SUBJECT, "Testing Package Visibility")
}startActivity(intent)

This code will work fine (even on the API level 30) if the email app is installed on the device. But what if there are no apps that can handle this request? — The app will crash by throwing ActivityNotFoundException.

A safe option is to first check that if we have at least one app which can handle this request. So we could do something like:

// It will always return null on Android 11, unless <queries> specified in manifest!if (intent.resolveActivity(packageManager) == null) {
toast("No app found to handle this request")
} else {
startActivity(intent)
}

Now, this is where your code will fail, as your app is not allowed to query other installed apps. Here, in order for your code to work, you will have to add <queries> in your app’s manifest file and declare your intent.

App’s Manifest file with <queries> element

Custom Tabs

When using Custom Tabs to open a Web URL, it is possible that there may be some non-browser apps that can also handle that URL. It is recommended that you allow the non-browser app to handle that URL first.

FLAG_ACTIVITY_REQUIRE_NON_BROWSER can be used here to query Non-Browser apps only.

To learn more about it, refer to “Configuring package visibility based on use cases” from Android Documentation.

Important Point

The system makes some apps visible to your app automatically, but it hides other apps by default. Generally, these are apps that are linked to your app in some ways, like, Any app that starts or binds to a service in your app, access a content provider in your app, whose content provider your app accesses, etc.

You can start another app’s activity using either an implicit or explicit intent, regardless of whether that other app is visible to your app. You just cannot query the intent.

What do I do if my App is an App Launcher or similar, where I need to know all the apps that are installed on the device?

To allow your app to see all other installed apps, the system provides the QUERY_ALL_PACKAGES permission.

<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>

This permission is appropriate for apps that genuinely need this permission like a Launcher App, a Security App, Device Management App, Accessibility App, etc.

In an upcoming policy update, look for Google Play to provide guidelines for apps that need the QUERY_ALL_PACKAGES permission.

Good-to-Have Enhancements

Notifications

Notifications now have support for Priority conversations and native chat bubbles, and sending images right from the notification panel.

Image for post
Image for post

Conversations notifications are styled differently from other Non-Conversation notifications with a strong emphasis on the avatar representing people combined with the app carrying the conversation. These notifications bring some actions like marking this conversation as a priority, promoting this conversation as a bubble, setting custom sounds or vibrations, or simply silencing the notification.

To learn more about Conversation Space, MessagingStyle, and the Chat Bubble, refer to “People and conversations” from Android Documentation.

Synchronized IME transitions

New APIs let you synchronize your app’s UI with the IME (input method editor, or on-screen keyboard) and system bars as they animate on and offscreen, making it much easier to create natural, intuitive, and jank-free IME transitions.

Image for post
Image for post

The new WindowInsetsAnimation.Callback API notifies apps of per-frame changes to insets while the system bars or the IME animate.

And moreover, finally, a question that was being asked for decades “How to check if On-Screen Keyboard is visible” can now finally be answered.

Read more about it in this detailed, amazing article by Chris Banes.

Deprecations

Async Task is deprecated

Starting from API level 30 AsyncTask is deprecated. It means you can still use it in your code, but it is no longer a recommended approach and you should soon migrate to java.util.concurrent or Kotlin concurrency utilities (Kotlin Coroutines) instead.

Android is now Kotlin first and it is very strongly recommended to use Kotlin Coroutines for such tasks.

The Non-Looper constructor of Handler is deprecated

Handler() and Handler(Handler.Callback callback) are deprecated because they do not specify a Looper, which can cause bugs, for example, mistakingly specifying a Handler on a thread without an active looper will cause your app to crash.

Android recommends explicitly passing a Looper to the Handler using these constructors: Handler(Looper looper) and Handler(Looper looper, Handler.Callback callback)

val mHandler: Handler = Handler(Looper.getMainLooper())

Custom Toast Views are deprecated

ie. Toast#setView and Toast#getView methods are now deprecated. Apps can create a standard text toast or use a Snackbar when in the foreground.

Also in order to make the UI consistent, starting from API level 30, custom toast messages will not be displayed while the app is in the background.

Another important thing here is that although Toast#setMargin and Toast#setGravity are not deprecated, but these methods are a no-op when called on text toasts. However, they work fine with simple toasts.

A “Simple Toast” is a toast constructed from Toast(context: Context) whereas a “Text Toast” is a toast constructed from the static method Toast(context: Context, text: CharSequence, duration: Int)

Parting Words

Let me know your suggestions and if you think I missed mentioning an important change in Android 11.

Now that you know everything to migrate your amazing app to Android 11, what are you waiting for?

I got to decorate my Christmas Tree now — Merry Christmas to all. 🎄

Thank you!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK