Behavior changes: all apps

The Android 12 platform includes behavior changes that may affect your app. The following behavior changes apply to all apps when they run on Android 12, regardless of targetSdkVersion. You should test your app and then modify it as needed to support these properly, where applicable.

Make sure to also review the list of behavior changes that only affect apps targeting Android 12.

User experience

Overscroll effect

The behavior for overscroll events changes in Android 12. See Overscroll effect for more information.

Foreground service notifications UX delay

To provide a streamlined experience for short-running foreground services on Android 12, the system can delay the display of foreground service notifications by 10 seconds for certain foreground services. This change gives short-lived tasks a chance to complete before their notifications appear.

If a foreground service has at least one of the following characteristics, the system shows the associated notification immediately after the service starts:

  • The service is associated with a notification that includes action buttons.
  • The service has a foregroundServiceType of mediaPlayback, mediaProjection, or phoneCall.
  • The service provides a use case related to phone calls, navigation, or media playback, as defined in the notification's category attribute.
  • The service has opted out of the behavior change by passing FOREGROUND_SERVICE_IMMEDIATE into setForegroundServiceBehavior() when setting up the notification.

Immersive mode improvements for gesture navigation

Android 12 simplifies immersive mode to make gesture navigation easier and more consistent with the rest of the experience of activities such as watching a video and reading a book. To learn more, see the corresponding entry on the features page.

Web intent resolution

To provide a more streamlined experience when users select web links, Android 12 opens a given web intent in the user's default browser if that intent contains an unapproved domain. Your app can get approved for the domain using one of the following approaches:

  • Verify the domain using Android App Links.
  • Request the user to associate your app with a domain.

If your app invokes web intents, consider adding a prompt or dialog that asks the user to confirm the action.

Learn more about the changes to web intent resolution.

Restrictive App Standby bucket

App Standby Buckets help the system prioritize an app's resource requests based on how recently and how frequently the app is used.

Each bucket represents a priority. A low priority means the system imposes more restrictions on running your app.

Starting in Android 12, there is a new bucket named restricted. The restricted bucket has the lowest priority (and the highest restrictions) of all the buckets. The buckets in order of priority from high to low are:

  1. Active: App is currently being used or was very recently used
  2. Working set: App is in regular use
  3. Frequent: App is often used, but not every day
  4. Rare: App is not frequently used
  5. Restricted

The system considers your app's behavior, in addition to usage patterns, to decide whether to place your app in the restricted bucket. Your app is less likely to be placed in the restricted bucket if your app uses system resources more responsibly.

The system places your app in a less restrictive bucket if the user interacts directly with your app.

Power management restrictions

If the system places your app in the restricted bucket, the following restrictions apply:

  • You can run jobs once per day, in a 10-minute batched session. During this session, the system groups your app's jobs with other apps' jobs.
  • Your app can run fewer expedited jobs, compared to when the system places your app in a less-restrictive bucket.
  • Your app's inexact alarms are delivered once per day. You create an inexact alarm when you call the set(), setInexactRepeating(), setAndAllowWhileIdle(), or setWindow() methods.
  • Your app can receive five high-priority Firebase Cloud Messaging (FCM) messages per day in a timely manner. All subsequent FCM messages are delivered with normal priority, so the messages might be delayed if the device is in a power-saving mode.

Foreground services allowance

If the system places your app in the restricted bucket, your app can still run foreground services. However, if your app targets Android 12, it's still affected by the foreground service launch restrictions.

Check whether your app is in the restricted bucket

To check whether the system has placed your app in the restricted bucket, call getAppStandbyBucket(). If the return value of this method is STANDBY_BUCKET_RESTRICTED, then your app is in the restricted bucket.

Test the restricted bucket behavior

To test how your app behaves when the system places your app into the restricted bucket, you can manually move your app to that bucket. To do so, run the following command in a terminal window:

adb shell am set-standby-bucket PACKAGE_NAME restricted

Display#getRealSize and getRealMetrics: deprecation and sandboxing

Android devices are available in many different form factors, such as large screens, tablets, and foldables. To render content appropriately for each device, your app needs to determine the screen or display size. Over time, Android provided different APIs for retrieving this information. In Android 11, we introduced the WindowMetrics API and deprecated these methods:

In Android 12 we're continuing to recommend using WindowMetrics, and are deprecating these methods:

To mitigate the behavior of applications using Display APIs to retrieve the application's bounds, Android 12 adds a new sandboxing mechanism to correct the information returned by these APIs. This could have an impact on apps that are using this information with MediaProjection.

Apps should use the WindowMetrics APIs to query the bounds of their window, and Configuration.densityDpi to query the current density.

For broader compatibility with older versions of Android, you can use the Jetpack WindowManager library, which includes a WindowMetrics class that supports Android 4.0 (API level 14) and higher.

Examples of how to use WindowMetrics

First, be sure your app's activities are fully resizable.

An activity should rely upon WindowMetrics from an activity context for any UI-related work, particularly WindowManager.getCurrentWindowMetrics().

If your app creates a MediaProjection, the bounds must be correctly sized since the projection captures the display. If the app is fully resizable, the activity context returns the correct bounds like so:

WindowMetrics projectionMetrics = activityContext
        .getSystemService(WindowManager.class).getMaximumWindowMetrics();

If the app is not fully resizable, it must query the bounds from a WindowContext instance, and retrieve the WindowMetrics of the maximum display area available to the application using WindowManager.getMaximumWindowMetrics().

Context windowContext = mContext.createWindowContext(mContext.getDisplay(),
        TYPE_APPLICATION, null /* options */);
WindowMetrics projectionMetrics = windowContext.getWindowManager()
        .getMaximumWindowMetrics();

Graphics and images

Improved refresh rate switching

In Android 12, refresh rate changes using setFrameRate() can happen regardless of whether the display supports a seamless transition to the new refresh rate; a seamless transition is one that doesn't have any visual interruptions, such as a black screen for a second or two. Previously, if the display did not support a seamless transition, it would typically continue using the same refresh rate after setFrameRate() is called. You can determine in advance whether the transition to the new refresh will likely be seamless by calling getAlternativeRefreshRates(). Generally, the callback onDisplayChanged() is called after the refresh rate switch completes, but for some externally-connected displays, it is called during a non-seamless transition.

Here’s an example of how you might implement this:

Kotlin

// Determine whether the transition will be seamless.
// Non-seamless transitions may cause a 1-2 second black screen.
val refreshRates = this.display?.mode?.alternativeRefreshRates
        val willbeSeamless = Arrays.asList<FloatArray>(refreshRates).contains(newRefreshRate)

// Set the frame rate even if the transition will not be seamless.
surface.setFrameRate(newRefreshRate, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ALWAYS)

Java

// Determine whether the transition will be seamless.
// Non-seamless transitions may cause a 1-2 second black screen.
Display display = context.getDisplay(); // API 30+
Display.Mode mode = display.getMode();
float[] refreshRates = mode.getAlternativeRefreshRates();
boolean willbeSeamless = Arrays.asList(refreshRates).contains(newRefreshRate);

// Set the frame rate even if the transition will not be seamless.
surface.setFrameRate(newRefreshRate, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ALWAYS);

Security and privacy

Microphone and camera toggles

Quick settings tiles are labeled 'Camera access' and
         'Mic access'
Figure 1. Microphone and camera toggles in Quick Settings.

On Android 12, supported devices allow users to enable and disable camera and microphone access for all apps on the device, by pressing a single toggle option. Users can access the toggleable options from Quick Settings, as shown in figure 1, or from the Privacy screen in system settings.

The camera and microphone toggles affect all apps on the device:

  • When the user turns off camera access, apps receive a blank camera feed.
  • When the user turns off microphone access, apps receive silent audio.

When the user turns off access to camera or microphone, then launches an app that needs access to camera or microphone information, the system reminds the user that the device-wide toggle is turned off.

Check whether a given device supports microphone and camera toggles

To check whether a device supports microphone and camera toggles, add the logic that appears in the following code snippet:

Kotlin

val sensorPrivacyManager = applicationContext
        .getSystemService(SensorPrivacyManager::class.java)
        as SensorPrivacyManager
val supportsMicrophoneToggle = sensorPrivacyManager
        .supportsSensorToggle(Sensors.MICROPHONE)
val supportsCameraToggle = sensorPrivacyManager
        .supportsSensorToggle(Sensors.CAMERA)

Java

SensorPrivacyManager sensorPrivacyManager = getApplicationContext()
        .getSystemService(SensorPrivacyManager.class);
boolean supportsMicrophoneToggle = sensorPrivacyManager
        .supportsSensorToggle(Sensors.MICROPHONE);
boolean supportsCameraToggle = sensorPrivacyManager
        .supportsSensorToggle(Sensors.CAMERA);

Check app behavior in response to microphone and camera toggles

The microphone and camera toggles shouldn't affect how your app handles the CAMERA and RECORD_AUDIO permissions, as long as you follow best practices for Android permissions.

In particular, make sure your app does the following:

  • Wait to access the device's camera until the user has granted the CAMERA permission to your app.
  • Wait to access the device's microphone until the user has granted the RECORD_AUDIO permission to your app.

Microphone and camera indicators

A rounded rectangle in the upper-right corner, which
         includes a camera icon and a microphone icon
Figure 2. Microphone and camera indicators, which show recent data access.

On devices that run Android 12, when an app accesses the microphone or camera, an icon appears in the status bar. If the app is in immersive mode, the icon appears in the upper-right corner of the screen. Users can open Quick Settings and select the icon to view which apps are currently using the microphone or camera. Figure 2 shows an example screenshot that contains the icons.

To provide a better user experience, don't access the microphone or camera until the user has explicitly given permission to your app.

Apps can't close system dialogs

To improve user control when interacting with apps and the system, the ACTION_CLOSE_SYSTEM_DIALOGS intent action is deprecated as of Android 12. Except for a few special cases, when your app tries to invoke an intent that contains this action, the system does one of the following based on your app's target SDK version:

  • If your app targets Android 12, a SecurityException occurs.
  • If your app targets Android 11 (API level 30) or lower, the intent doesn't execute, and the following message appears in Logcat:

    E ActivityTaskManager Permission Denial: \
    android.intent.action.CLOSE_SYSTEM_DIALOGS broadcast from \
    com.package.name requires android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS, \
    dropping broadcast.
    

Exceptions

In the following cases, an app can still close system dialogs on Android 12:

  • Your app is running an instrumentation test.
  • Your app targets Android 11 or lower and is showing a window that is on top of the notification drawer.

  • Your app targets Android 11 or lower. In addition, the user has interacted with a notification, possibly using the notification's action buttons, and your app is processing a service or broadcast receiver in response to that user action.

  • Your app targets Android 11 or lower and has an active accessibility service. If your app targets Android 12 and wants to close the notification bar, use the GLOBAL_ACTION_DISMISS_NOTIFICATION_SHADE accessibility action instead.

Untrusted touch events are blocked

To preserve system security and a good user experience, Android 12 prevents apps from consuming touch events where an overlay obscures the app in an unsafe way. In other words, the system blocks touches that pass through certain windows, with a few exceptions.

Affected apps

This change affects apps that choose to let touches pass through their windows, for example by using the FLAG_NOT_TOUCHABLE flag. Several examples include, but aren't limited to, the following:

Exceptions

In the following cases, "pass-through" touches are allowed:

  • Interactions within your app. Your app shows the overlay, and the overlay appears only when the user is interacting with your app.
  • Trusted windows. These windows include (but aren't limited to) the following:

  • Invisible windows. The window's root view is GONE or INVISIBLE.

  • Completely transparent windows. The alpha property is 0.0 for the window.

  • Sufficiently translucent system alert windows. The system considers a set of system alert windows to be sufficiently translucent when the combined opacity is less than or equal to the system's maximum obscuring opacity for touches. In Android 12 Beta, this maximum opacity is 0.8. This value might change in a future beta release.

Detect when an untrusted touch is blocked

If a touch action is blocked by the system, Logcat logs the following message:

Untrusted touch due to occlusion by PACKAGE_NAME

Test the change

Untrusted touches are blocked by default on devices that run Android 12 Developer Preview 3. To allow untrusted touches, run the following ADB command in a terminal window:

# A specific app
adb shell am compat disable BLOCK_UNTRUSTED_TOUCHES com.example.app

# All apps
# If you'd still like to see a Logcat message warning when a touch would be
# blocked, use 1 instead of 0.
adb shell settings put global block_untrusted_touches 0

To revert the behavior to the default (untrusted touches are blocked), run the following command:

# A specific app
adb shell am compat reset BLOCK_UNTRUSTED_TOUCHES com.example.app

# All apps
adb shell settings put global block_untrusted_touches 2

Permission package visibility

On devices that run Android 12, apps that target Android 11 (API level 30) or higher and that call one of following methods receive a filtered set of results, based on the app's package visibility into other apps:

Bouncy Castle implementation removed

Android 12 has removed many BouncyCastle implementations of cryptographic algorithms that were previously deprecated, including all AES algorithms. The system instead uses the Conscrypt implementations of these algorithms.

This change affects your app if any of the following are true:

  • Your app uses 512-bit key sizes. Conscrypt doesn't support this key size. If necessary, update your app's cryptography logic to use different key sizes.
  • You initialize your Galois/Counter Mode (GCM) ciphers using a size other than 12 bytes. Conscrypt's implementation of GcmParameterSpec requires an initialization of 12 bytes, which NIST recommends.

Clipboard access notifications

On Android 12, when an app calls getPrimaryClip() to access ClipData from a different app for the first time, a toast message notifies the user of this clipboard access.

The text inside the toast message contains the following format: APP pasted from your clipboard.

Message doesn't appear when retrieving clip description

Your app might call getPrimaryClipDescription() to receive information about the current data that's on the clipboard. When your app calls this method, the system doesn't show a toast message.

Android 12 enhances this method to detect the following additional details:

Connectivity

Passpoint updates

The following APIs are added in Android 12:

  • isPasspointTermsAndConditionsSupported(): Terms and conditions is a Passpoint feature that allows network deployments to replace insecure captive portals, which use open networks, with a secure Passpoint network. A notification is displayed to the user when terms and conditions are required to be accepted. Apps that suggest Passpoint networks that are gated by terms and conditions must call this API first to make sure that the device supports the capability. If the device does not support the capability, it won't be able to connect to this network, and an alternative or legacy network must be suggested.
  • isDecoratedIdentitySupported(): When authenticating to networks with a prefix decoration, the decorated identity prefix allows network operators to update the Network Access Identifier (NAI) to perform explicit routing through multiple proxies inside of an AAA network (see RFC 7542 for more on this).

    Android 12 implements this feature to conform with the WBA specification for PPS-MO extensions. Apps that suggest Passpoint networks that require a decorated identity must call this API first to make sure that the device supports the capability. If the device does not support the capability, the identity won't be decorated and the authentication to the network might fail.

To create a Passpoint suggestion, apps must use the PasspointConfiguration, Credential, and HomeSp classes. These classes describe the Passpoint profile, which is defined in the Wi-Fi Alliance Passpoint specification.

Updated non-SDK interface restrictions

Android 12 includes updated lists of restricted non-SDK interfaces based on collaboration with Android developers and the latest internal testing. Whenever possible, we make sure that public alternatives are available before we restrict non-SDK interfaces.

If your app does not target Android 12, some of these changes might not immediately affect you. However, while you can currently use some non-SDK interfaces (depending on your app's target API level), using any non-SDK method or field always carries a high risk of breaking your app.

If you are unsure if your app uses non-SDK interfaces, you can test your app to find out. If your app relies on non-SDK interfaces, you should begin planning a migration to SDK alternatives. Nevertheless, we understand that some apps have valid use cases for using non-SDK interfaces. If you cannot find an alternative to using a non-SDK interface for a feature in your app, you should request a new public API.

To learn more about the changes in this release of Android, see Updates to non-SDK interface restrictions in Android 12. To learn more about non-SDK interfaces generally, see Restrictions on non-SDK interfaces.