Cambios en el comportamiento: apps orientadas a Android 15 o versiones posteriores

Al igual que las versiones anteriores, Android 15 incluye cambios de comportamiento que podrían afectar tu app. Los siguientes cambios se aplican exclusivamente a las apps orientadas a Android 15 o versiones posteriores. Si tu app está orientada a Android 15 o versiones posteriores, debes modificarla para que admita estos comportamientos correctamente, cuando corresponda.

Asegúrate también de revisar la lista de cambios en el comportamiento que afectan a todas las apps que se ejecutan en Android 15, independientemente de la targetSdkVersion de tu app.

Funcionalidad principal

Android 15 modifica o expande varias capacidades principales del sistema Android.

Cambios en los servicios en primer plano

Realizaremos los siguientes cambios en los servicios en primer plano con Android 15.

Comportamiento del tiempo de espera del servicio en primer plano de sincronización de datos

Android 15 introduce un nuevo comportamiento de tiempo de espera en dataSync para la segmentación de apps Android 15 o una versión posterior Este comportamiento también se aplica a la nueva mediaProcessing tipo de servicio en primer plano.

El sistema permite que los servicios de dataSync de una app se ejecuten durante un total de 6 horas en un período de 24 horas, después de lo cual el sistema llama a la red del Método Service.onTimeout(int, int) (presentado en Android) 15). En este momento, el servicio tiene unos segundos para llamar Service.stopSelf(). Cuando se llama a Service.onTimeout(), el elemento servicio ya no se considera un servicio en primer plano. Si el servicio no llama a Service.stopSelf(), el sistema arrojará una excepción interna. El se registra en Logcat con el siguiente mensaje:

Fatal Exception: android.app.RemoteServiceException: "A foreground service of
type dataSync did not stop within its timeout: [component name]"

Para evitar problemas con este cambio de comportamiento, puedes realizar una o más de las siguientes acciones: lo siguiente:

  1. Haz que tu servicio implemente el nuevo método Service.onTimeout(int, int). Cuando tu app reciba la devolución de llamada, asegúrate de llamar a stopSelf() en una unos pocos segundos. (Si no detienes la app de inmediato, el sistema genera falla).
  2. Asegúrate de que los servicios de dataSync de tu app no se ejecuten durante un total de 6 horas en cualquier período de 24 horas (salvo que el usuario interactúe con la app) restableciendo el temporizador).
  3. Solo iniciar dataSync servicios en primer plano como resultado de la acción de un usuario directo interacción dado que tu app está en primer plano cuando se inicia el servicio el servicio tiene las seis horas completas después de que la app pasa a segundo plano.
  4. En lugar de usar un servicio en primer plano de dataSync, usa un alternativa.

Si los servicios en primer plano de dataSync de tu app se ejecutaron durante 6 horas durante el último período 24, no puedes iniciar otro servicio en primer plano de dataSync, a menos que el usuario Puso tu aplicación al primer plano (lo que restablece el temporizador). Si intentas iniciar otro servicio dataSync en primer plano, el sistema arrojará ForegroundServiceStartNotAllowedException con un mensaje de error como “Ya se agotó el tiempo para el servicio en primer plano escribe dataSync”.

Pruebas

Para probar el comportamiento de tu app, habilita los tiempos de espera de la sincronización de datos incluso si la app No está orientada a Android 15 (siempre y cuando la app se ejecute en un dispositivo Android 15). dispositivo). Para habilitar los tiempos de espera, ejecuta el siguiente comando adb:

adb shell am compat enable FGS_INTRODUCE_TIME_LIMITS your-package-name

También puedes ajustar el tiempo de espera para probar cómo tus se comporta cuando se alcanza el límite. Para establecer un nuevo tiempo de espera, ejecuta siguiente comando adb:

adb shell device_config put activity_manager data_sync_fgs_timeout_duration duration-in-milliseconds

Nuevo tipo de servicio en primer plano de procesamiento de contenido multimedia

Android 15 presenta un nuevo tipo de servicio en primer plano: mediaProcessing. Este tipo de servicio es apropiado para operaciones como la transcodificación de archivos multimedia. Por ejemplo, una app de música podría descargar un archivo de audio y necesitar convertirlo a un formato diferente antes de reproducirlo. Puedes usar un servicio en primer plano mediaProcessing para asegurarte de que la conversión continúe incluso mientras la app se encuentra en segundo plano.

El sistema permite que se ejecuten los servicios de mediaProcessing de una app durante un total de 6 horas en un período de 24 horas. Después de eso, el sistema llama al método Service.onTimeout(int, int) del servicio en ejecución (presentado en Android 15). En este momento, el servicio tiene unos segundos para llamar a Service.stopSelf(). Si el servicio no llama a Service.stopSelf(), el sistema arroja una excepción interna. La excepción se registra en Logcat con el siguiente mensaje:

Fatal Exception: android.app.RemoteServiceException: "A foreground service of
type mediaProcessing did not stop within its timeout: [component name]"

Para evitar la excepción, puedes realizar una de las siguientes acciones:

  1. Haz que tu servicio implemente el nuevo método Service.onTimeout(int, int). Cuando tu app reciba la devolución de llamada, asegúrate de llamar a stopSelf() en unos pocos segundos. (Si no detienes la app de inmediato, el sistema genera una falla).
  2. Asegúrate de que los servicios de mediaProcessing de tu app no se ejecuten durante más de 6 horas en total en cualquier período de 24 horas (salvo que el usuario interactúe con la app y restablezca el temporizador).
  3. Solo inicia los servicios en primer plano de mediaProcessing como resultado de la interacción directa del usuario. Dado que tu app está en primer plano cuando se inicia el servicio, el servicio tiene seis horas completas después de que la app pasa a segundo plano.
  4. En lugar de usar un servicio en primer plano de mediaProcessing, usa una API alternativa, como WorkManager.

Si los servicios en primer plano de mediaProcessing de tu app se ejecutaron durante 6 horas durante las últimas 24, no podrás iniciar otro servicio mediaProcessing en primer plano, a menos que el usuario haya llevado la app al primer plano (lo que restablece el temporizador). Si intentas iniciar otro servicio mediaProcessing en primer plano, el sistema arrojará una ForegroundServiceStartNotAllowedException con un mensaje de error como "El límite de tiempo ya se agotó para el tipo de servicio en primer plano mediaProcessing".

Para obtener más información sobre el tipo de servicio mediaProcessing, consulta Cambios en los tipos de servicio en primer plano para Android 15: Procesamiento de contenido multimedia.

Prueba

Para probar el comportamiento de tu app, puedes habilitar los tiempos de espera del procesamiento de contenido multimedia, incluso si tu app no está orientada a Android 15 (siempre y cuando se ejecute en un dispositivo con Android 15). Para habilitar los tiempos de espera, ejecuta el siguiente comando adb:

adb shell am compat enable FGS_INTRODUCE_TIME_LIMITS your-package-name

También puedes ajustar el tiempo de espera para facilitar la prueba del comportamiento de tu app cuando se alcanza el límite. Para establecer un nuevo tiempo de espera, ejecuta el siguiente comando adb:

adb shell device_config put activity_manager media_processing_fgs_timeout_duration duration-in-milliseconds

Restricciones en los receptores de emisión de BOOT_COMPLETED que inician servicios en primer plano

Hay nuevas restricciones para los receptores de emisión de BOOT_COMPLETED que se lanzan servicios en primer plano. Los receptores de BOOT_COMPLETED no tienen permitido iniciar la los siguientes tipos de servicios en primer plano:

Si un receptor BOOT_COMPLETED intenta iniciar cualquiera de esos tipos de primer plano. servicios, el sistema arroja una ForegroundServiceStartNotAllowedException.

Pruebas

Para probar el comportamiento de tu app, puedes habilitar estas nuevas restricciones incluso si tu La app no está orientada a Android 15 (siempre y cuando se ejecute en un sistema operativo dispositivo). Ejecuta el siguiente comando adb:

adb shell am compat enable FGS_BOOT_COMPLETED_RESTRICTIONS your-package-name

Para enviar una transmisión de BOOT_COMPLETED sin reiniciar el dispositivo, haz lo siguiente: Ejecuta el siguiente comando adb:

adb shell am broadcast -a android.intent.action.BOOT_COMPLETED your-package-name

Restricciones para el inicio de servicios en primer plano mientras una app conserva el permiso SYSTEM_ALERT_WINDOW

Anteriormente, si una app tenía el permiso SYSTEM_ALERT_WINDOW, podía iniciar un servicio en primer plano incluso si estaba en segundo plano (como se explica en Exenciones de restricciones de inicio en segundo plano).

Si una app se orienta a Android 15, esta exención ahora es menor. Ahora, la app necesita tener el permiso SYSTEM_ALERT_WINDOW y también tener una ventana superpuesta visible. Es decir, la app debe iniciar primero una ventana TYPE_APPLICATION_OVERLAY, y esta debe ser visible antes de iniciar un servicio en primer plano.

Si tu app intenta iniciar un servicio en primer plano desde el segundo plano sin cumplir con estos nuevos requisitos (y no tiene alguna otra exención), el sistema arrojará una ForegroundServiceStartNotAllowedException.

Si tu app declara el permiso SYSTEM_ALERT_WINDOW e inicia servicios en primer plano desde el segundo plano, es posible que este cambio la afecte. Si tu app obtiene un ForegroundServiceStartNotAllowedException, verifica el orden de operaciones y asegúrate de que ya tenga una ventana superpuesta activa antes de intentar iniciar un servicio en primer plano en segundo plano. Para comprobar si la ventana de superposición es visible actualmente, llama a View.getWindowVisibility(). También puedes anular View.onWindowVisibilityChanged() para recibir notificaciones cada vez que cambie la visibilidad.

Cambios en el momento en que las apps pueden modificar el estado global del modo No interrumpir

Las apps orientadas a Android 15 ya no pueden cambiar el estado global ni la política de No interrumpir (No interrumpir) en un dispositivo (ya sea modificando la configuración del usuario o desactivando el modo No interrumpir). En cambio, las apps deben aportar un AutomaticZenRule, que el sistema combina en una política global con el esquema existente más restrictivo de la política. Las llamadas a las APIs existentes que anteriormente afectaron el estado global (setInterruptionFilter, setNotificationPolicy) generan la creación o actualización de un AutomaticZenRule implícito, que se activa y desactiva según el ciclo de llamadas de esas llamadas a la API.

Ten en cuenta que este cambio solo afecta el comportamiento observable si la app llama a setInterruptionFilter(INTERRUPTION_FILTER_ALL) y espera que esa llamada desactive una AutomaticZenRule que sus propietarios hayan activado.

Cambios en la API de OpenJDK

Android 15 continúa la tarea de actualizar las bibliotecas principales de Android para alinearlas con las funciones de las versiones más recientes de OpenJDK LTS.

Algunos de estos cambios pueden afectar la compatibilidad de las apps con la segmentación Android 15 (nivel de API 35):

  • Cambios en las APIs de formato de cadenas: Validación de índices de argumentos, marcas, ancho y precisión ahora son más estrictas cuando se usan los siguientes APIs de String.format() y Formatter.format():

    Por ejemplo, se arroja la siguiente excepción cuando un índice de argumento es 0. (%0 en la cadena de formato):

    IllegalFormatArgumentIndexException: Illegal format argument index = 0
    

    En este caso, el problema se puede solucionar usando un índice de argumentos de 1 (%1 en la cadena de formato).

  • Cambios en el tipo de componente de Arrays.asList(...).toArray(): Cuando se usa Arrays.asList(...).toArray(), el tipo de componente del array resultante es ahora es un Object, no el tipo de elementos del array subyacente. Entonces, El siguiente código arroja una ClassCastException:

    String[] elements = (String[]) Arrays.asList("one", "two").toArray();
    

    En este caso, para conservar String como el tipo de componente en la array, puedes usar Collection.toArray(Object[]) en su lugar:

    String[] elements = Arrays.asList("two", "one").toArray(new String[0]);
    
  • Cambios en el manejo del código de idioma: Cuando usas la API de Locale, los códigos de idioma del hebreo, el yidis e indonesio ya no se convierten a sus formas obsoletas (en hebreo: iw, yidis: ji e indonesio: in). Al especificar el código de idioma para una de estas configuraciones regionales, utiliza los códigos de ISO 639-1 en su lugar (hebreo: he, yidis: yi e indonesio: id).

  • Cambios en secuencias int aleatorias: Sigue los cambios realizados en https://bugs.openjdk.org/browse/JDK-8301574, los siguientes Los métodos Random.ints() ahora muestran una secuencia de números diferente a la los métodos Random.nextInt() hacen lo siguiente:

    Por lo general, este cambio no debería causar un comportamiento rotundo en la app, pero el código no debería esperar que la secuencia generada a partir de los métodos Random.ints() coincide con Random.nextInt().

La nueva API de SequencedCollection puede afectar la compatibilidad de tu app después de actualizar compileSdk en la configuración de compilación de tu app para que se use Android 15 (nivel de API 35):

  • Colisiones con MutableList.removeFirst() y Funciones de extensión MutableList.removeLast() en kotlin-stdlib

    El tipo List en Java se asigna al tipo MutableList en Kotlin. Debido a que las APIs de List.removeFirst() y List.removeLast() se introdujeron en Android 15 (nivel de API 35), el compilador de Kotlin que resuelve llamadas a funciones (por ejemplo, list.removeFirst()) de forma estática al nuevas APIs de List en lugar de las funciones de extensión en kotlin-stdlib:

    Si se vuelve a compilar una app con compileSdk establecido en 35 y minSdk establecido en 34 o versiones anteriores, y luego la app se ejecuta en Android 14 y versiones anteriores, un entorno de ejecución se genera el siguiente error:

    java.lang.NoSuchMethodError: No virtual method
    removeFirst()Ljava/lang/Object; in class Ljava/util/ArrayList;
    

    La opción de lint NewApi existente en el complemento de Android para Gradle puede detectar estos nuevos usos de la API.

    ./gradlew lint
    
    MainActivity.kt:41: Error: Call requires API level 35 (current min is 34): java.util.List#removeFirst [NewApi]
          list.removeFirst()
    

    Para corregir la excepción del tiempo de ejecución y los errores de lint, los comandos removeFirst() y Las llamadas a función removeLast() se pueden reemplazar por removeAt(0) y removeAt(list.lastIndex) respectivamente en Kotlin. Si utilizas Ladybug de Android Studio | 2024.1.3 o una versión posterior, también proporciona una solución rápida para estos errores.

    Te recomendamos quitar @SuppressLint("NewApi") y lintOptions { disable 'NewApi' } si se inhabilitó la opción de lint.

  • Colisión con otros métodos en Java

    Se agregaron métodos nuevos a los tipos existentes, por ejemplo, List y Deque. Es posible que estos nuevos métodos no sean compatibles con métodos con el mismo nombre y los mismos tipos de argumentos en otras interfaces y clases. En el caso de una colisión de firma de método con incompatibilidad, el compilador javac genera un error de tiempo de compilación. Por ejemplo:

    Ejemplo de error 1:

    javac MyList.java
    
    MyList.java:135: error: removeLast() in MyList cannot implement removeLast() in List
      public void removeLast() {
                  ^
      return type void is not compatible with Object
      where E is a type-variable:
        E extends Object declared in interface List
    

    Ejemplo de error 2:

    javac MyList.java
    
    MyList.java:7: error: types Deque<Object> and List<Object> are incompatible;
    public class MyList implements  List<Object>, Deque<Object> {
      both define reversed(), but with unrelated return types
    1 error
    

    Ejemplo de error 3:

    javac MyList.java
    
    MyList.java:43: error: types List<E#1> and MyInterface<E#2> are incompatible;
    public static class MyList implements List<Object>, MyInterface<Object> {
      class MyList inherits unrelated defaults for getFirst() from types List and MyInterface
      where E#1,E#2 are type-variables:
        E#1 extends Object declared in interface List
        E#2 extends Object declared in interface MyInterface
    1 error
    

    Para corregir estos errores de compilación, la clase que implementa estas interfaces debe anular el método con un tipo de datos que se devuelve compatible. Por ejemplo:

    @Override
    public Object getFirst() {
        return List.super.getLast();
    }
    

Seguridad

Android 15 incluye cambios que promueven la seguridad del sistema para ayudar a proteger las apps y a los usuarios de apps maliciosas.

Lanzamientos seguros de actividades en segundo plano

Android 15 protege a los usuarios de apps maliciosas y les brinda más control sobre sus dispositivos, ya que agregan cambios que evitan que las apps maliciosas en segundo plano lleven otras apps al primer plano, elevan sus privilegios y abusen de la interacción con los usuarios. Los inicios de actividades en segundo plano están restringidos desde Android 10 (nivel de API 29).

Bloquear el inicio de actividades en las apps que no coincidan con el UID superior de la pila

Las apps maliciosas pueden iniciar la actividad de otra app dentro de la misma tarea y, luego, superponerse sobre ellas, lo que crea la ilusión de ser esa app. Este ataque de “secuestro de tareas” omite las restricciones actuales de inicio en segundo plano porque todo ocurre dentro de la misma tarea visible. Para mitigar este riesgo, en Android 15, se agrega una marca que bloquea las apps que no coinciden con el UID superior de la pila para que no inicien actividades. Para habilitar todas las actividades de tu app, actualiza el atributo allowCrossUidActivitySwitchFromBelow en el archivo AndroidManifest.xml de la app:

<application android:allowCrossUidActivitySwitchFromBelow="false" >

Las nuevas medidas de seguridad están activas si se cumplen todas las condiciones que se indican a continuación:

  • La app que realiza el lanzamiento se orienta a Android 15.
  • La app de la parte superior de la pila de tareas se orienta a Android 15.
  • Se habilitaron las nuevas protecciones para toda la actividad visible

Si las medidas de seguridad están habilitadas, es posible que las apps regresen al inicio, en lugar de a la última app visible, si finalizan su propia tarea.

Otros cambios

Además de la restricción para la coincidencia de UID, también se incluyen estos otros cambios:

  • Cambia los creadores de PendingIntent para que bloqueen inicios de actividades en segundo plano de forma predeterminada. Esto ayuda a evitar que las apps creen accidentalmente un PendingIntent que podría ser abusado por actores maliciosos.
  • No coloques una app en primer plano, a menos que lo permita el remitente del PendingIntent. El objetivo de este cambio es evitar que apps maliciosas abusen de la capacidad de iniciar actividades en segundo plano. De forma predeterminada, las apps no pueden llevar la pila de tareas al primer plano, a menos que el creador permita privilegios de inicio de la actividad en segundo plano o que el remitente tenga privilegios de inicio de actividad en segundo plano.
  • Controla cómo la actividad superior de una pila de tareas puede completar su tarea. Si la actividad principal finaliza una tarea, Android regresará a la tarea que estuvo activa por última vez. Además, si una actividad que no es principal finaliza su tarea, Android regresará a la pantalla principal y no bloqueará el final de esa actividad no principal.
  • Evita iniciar actividades arbitrarias de otras apps en tu propia tarea. Este cambio evita que las apps maliciosas suplanten a los usuarios mediante la creación de actividades que parecen provenir de otras apps.
  • Bloquea las ventanas no visibles a fin de que no se consideren para el inicio de actividades en segundo plano. Esto ayuda a evitar que las apps maliciosas abusen de los inicios de actividades en segundo plano para mostrar contenido malicioso o no deseado a los usuarios.

Intents más seguros

Android 15 introduces new security measures to make intents safer and more robust. These changes are aimed at preventing potential vulnerabilities and misuse of intents that can be exploited by malicious apps. There are two main improvements to the security of intents in Android 15:

  • Match target intent-filters: Intents that target specific components must accurately match the target's intent-filter specifications. If you send an intent to launch another app's activity, the target intent component needs to align with the receiving activity's declared intent-filters.
  • Intents must have actions: Intents without an action will no longer match any intent-filters. This means that intents used to start activities or services must have a clearly defined action.
  • Pending intents: The creator of the pending intent is treated as the sender of the enclosing intent, not the sender of the pending intent

Kotlin


fun onCreate() {
    StrictMode.setVmPolicy(VmPolicy.Builder()
        .detectUnsafeIntentLaunch()
        .build()
    )
}

Java


public void onCreate() {
    StrictMode.setVmPolicy(new VmPolicy.Builder()
            .detectUnsafeIntentLaunch()
            .build());
}

IU del sistema y experiencia del usuario

En Android 15, se incluyen algunos cambios destinados a crear una experiencia del usuario más intuitiva y coherente.

Cambios en la inserción de ventana

Hay dos cambios relacionados con las inserciones de ventana en Android 15: de borde a borde se aplica de forma predeterminada, y también hay cambios de configuración, como la configuración predeterminada de las barras del sistema.

Aplicación de borde a borde

Apps are edge-to-edge by default on devices running Android 15 if the app is targeting Android 15 (API level 35).

An app that targets Android 14 and is not edge-to-edge on an Android 15 device.


An app that targets Android 15 (API level 35) and is edge-to-edge on an Android 15 device. This app mostly uses Material 3 Compose Components that automatically apply insets. This screen is not negatively impacted by the Android 15 edge-to-edge enforcement.

This is a breaking change that might negatively impact your app's UI. The changes affect the following UI areas:

  • Gesture handle navigation bar
    • Transparent by default.
    • Bottom offset is disabled so content draws behind the system navigation bar unless insets are applied.
    • setNavigationBarColor and R.attr#navigationBarColor are deprecated and don't affect gesture navigation.
    • setNavigationBarContrastEnforced and R.attr#navigationBarContrastEnforced continue to have no effect on gesture navigation.
  • 3-button navigation
    • Opacity set to 80% by default, with color possibly matching the window background.
    • Bottom offset disabled so content draws behind the system navigation bar unless insets are applied.
    • setNavigationBarColor and R.attr#navigationBarColor are set to match the window background by default. The window background must be a color drawable for this default to apply. This API is deprecated but continues to affect 3-button navigation.
    • setNavigationBarContrastEnforced and R.attr#navigationBarContrastEnforced is true by default, which adds an 80% opaque background across 3-button navigation.
  • Status bar
    • Transparent by default.
    • The top offset is disabled so content draws behind the status bar unless insets are applied.
    • setStatusBarColor and R.attr#statusBarColor are deprecated and have no effect on Android 15.
    • setStatusBarContrastEnforced and R.attr#statusBarContrastEnforced are deprecated but still have an effect on Android 15.
  • Display cutout
    • layoutInDisplayCutoutMode of non-floating windows must be LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS. SHORT_EDGES, NEVER and DEFAULT are interpreted as ALWAYS so that users don't see a Black bar caused by the display cutout and appear edge-to-edge.

The following example shows an app before and after targeting Android 15 (API level 35), and before and after applying insets.

An app that targets Android 14 and is not edge-to-edge on an Android 15 device.
An app that targets Android 15 (API level 35) and is edge-to-edge on an Android 15 device. However, many elements are now hidden by the status bar, 3-button navigation bar, or display cutout due to the Android 15 edge-to-edge enforcements. Hidden UI includes the Material 2 top app bar, floating action buttons, and list items.
An app that targets Android 15 (API level 35), is edge to edge on an Android 15 device and applies insets so that UI is not hidden.
What to check if your app is already edge-to-edge

If your app is already edge-to-edge and applies insets, you are mostly unimpacted, except in the following scenarios. However, even if you think you aren't impacted, we recommend you test your app.

  • You have a non-floating window, such as an Activity that uses SHORT_EDGES, NEVER or DEFAULT instead of LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS. If your app crashes on launch, this might be due to your splashscreen. You can either upgrade the core splashscreen dependency to 1.2.0-alpha01 or later or set window.attributes.layoutInDisplayCutoutMode = WindowManager.LayoutInDisplayCutoutMode.always.
  • There might be lower-traffic screens with occluded UI. Verify these less-visited screens don't have occluded UI. Lower-traffic screens include:
    • Onboarding or sign-in screens
    • Settings pages
What to check if your app is not already edge-to-edge

If your app is not already edge-to-edge, you are most likely impacted. In addition to the scenarios for apps that are already edge-to-edge, you should consider the following:

  • If your app uses Material 3 Components ( androidx.compose.material3) in compose, such as TopAppBar, BottomAppBar, and NavigationBar, these components are likely not impacted because they automatically handle insets.
  • If your app is using Material 2 Components ( androidx.compose.material) in Compose, these components don't automatically handle insets. However, you can get access to the insets and apply them manually. In androidx.compose.material 1.6.0 and later, use the windowInsets parameter to apply the insets manually for BottomAppBar, TopAppBar, BottomNavigation, and NavigationRail. Likewise, use the contentWindowInsets parameter for Scaffold.
  • If your app uses views and Material Components (com.google.android.material), most views-based Material Components such as BottomNavigationView, BottomAppBar, NavigationRailView, or NavigationView, handle insets and require no additional work. However, you need to add android:fitsSystemWindows="true" if using AppBarLayout.
  • For custom composables, apply the insets manually as padding. If your content is within a Scaffold, you can consume insets using the Scaffold padding values. Otherwise, apply padding using one of the WindowInsets.
  • If your app is using views and BottomSheet, SideSheet or custom containers, apply padding using ViewCompat.setOnApplyWindowInsetsListener. For RecyclerView, apply padding using this listener and also add clipToPadding="false".
What to check if your app must offer custom background protection

If your app must offer custom background protection to 3-button navigation or the status bar, you app should place a composable or view behind the system bar using WindowInsets.Type#tappableElement() to get the 3-button navigation bar height or WindowInsets.Type#statusBars.

Additional edge-to-edge resources

See the Edge to Edge Views and Edge to Edge Compose guides for additional considerations on applying insets.

Deprecated APIs

The following APIs are now deprecated:

Configuración estable

Si tu app se orienta a Android 15 (nivel de API 35) o versiones posteriores, Configuration no excluye las barras del sistema. Si utilizas el tamaño de la pantalla Configuration para el cálculo de diseño, debes reemplazarla por una alternativas como un ViewGroup, WindowInsets o WindowMetricsCalculator según tus necesidades.

Configuration está disponible desde la API 1. Por lo general, se obtienen de Activity.onConfigurationChanged. Proporciona información como la densidad de la ventana, la orientación y los tamaños. Una característica importante de los tamaños de ventana que muestra Configuration es que antes excluía las barras del sistema.

Por lo general, el tamaño de la configuración se usa para seleccionar recursos, como /res/layout-h500dp, y este sigue siendo un caso de uso válido. Sin embargo, usarlo para el cálculo de diseño siempre se desaconsejó. Si lo haces, deberías ahora. Debes reemplazar el uso de Configuration por algo. sean más adecuados según tu caso de uso.

Si lo usas para calcular el diseño, utiliza un ViewGroup adecuado, como CoordinatorLayout o ConstraintLayout. Si lo usas para determinar la altura de la barra de navegación del sistema, usa WindowInsets. Si quieres saber el tamaño actual de la ventana de tu app, usa computeCurrentWindowMetrics.

En la siguiente lista, se describen los campos que se verán afectados por este cambio:

El atributo eleganteTextHeight se establece en verdadero de forma predeterminada

En el caso de las apps orientadas a Android 15, el atributo TextView elegantTextHeight se convierte en true de forma predeterminada, lo que reemplaza la fuente compacta de forma predeterminada con algunas secuencias de comandos que tienen métricas verticales grandes por una mucho más legible. La fuente compacta se introdujo para evitar diseños rotos. Android 13 (nivel de API 33) evita muchas de estas fallas permitiendo que el diseño de texto estire la altura vertical con el atributo fallbackLineSpacing.

En Android 15, la fuente compacta aún permanece en el sistema, por lo que tu app puede establecer elegantTextHeight en false para obtener el mismo comportamiento que antes, pero es poco probable que se admita en próximas versiones. Por lo tanto, si tu app admite las siguientes secuencias de comandos: árabe, laosiano, Birmania, tamil, guyaratí, canarés, malabar, oriya, telugu o tailandés, configura elegantTextHeight en true para probar la app.

El comportamiento de elegantTextHeight para las apps que se orientan a Android 14 (nivel de API 34) y versiones anteriores.
Comportamiento de elegantTextHeight para las apps orientadas a Android 15.

Cambios de ancho de TextView para formas de letras complejas

En versiones anteriores de Android, algunas fuentes cursivas o idiomas con formas complejas podían dibujar las letras en el área del carácter anterior o siguiente. En algunos casos, esas letras se recortaban en la posición inicial o final. A partir de Android 15, un TextView asigna ancho a fin de generar suficiente espacio para esas letras y permite que las apps soliciten paddings adicionales a la izquierda para evitar el recorte.

Debido a que este cambio afecta la manera en que una TextView decide el ancho, TextView asigna más ancho de forma predeterminada si la app se orienta a Android 15 o versiones posteriores. Para habilitar o inhabilitar este comportamiento, llama a la API de setUseBoundsForWidth en TextView.

Como agregar padding izquierdo puede causar una desalineación para los diseños existentes, el padding no se agrega de forma predeterminada incluso en el caso de las apps orientadas a Android 15 o versiones posteriores. Sin embargo, puedes agregar padding adicional para evitar el recorte llamando a setShiftDrawingOffsetForStartOverhang.

En los siguientes ejemplos, se muestra cómo estos cambios pueden mejorar el diseño del texto de algunos idiomas y fuentes.

Diseño estándar para texto en inglés en fuente cursiva. Algunas de las letras están recortadas. Este es el XML correspondiente:

<TextView
    android:fontFamily="cursive"
    android:text="java" />
Diseño para el mismo texto en inglés con ancho y padding adicionales. Este es el XML correspondiente:

<TextView
    android:fontFamily="cursive"
    android:text="java"
    android:useBoundsForWidth="true"
    android:shiftDrawingOffsetForStartOverhang="true" />
Diseño estándar para texto tailandés. Algunas de las letras están recortadas. Este es el XML correspondiente:

<TextView
    android:text="คอมพิวเตอร์" />
Diseño para el mismo texto tailandés con ancho y padding adicionales. Este es el XML correspondiente:

<TextView
    android:text="คอมพิวเตอร์"
    android:useBoundsForWidth="true"
    android:shiftDrawingOffsetForStartOverhang="true" />

Altura de línea predeterminada de la configuración regional para EditText

In previous versions of Android, the text layout stretched the height of the text to meet the line height of the font that matched the current locale. For example, if the content was in Japanese, because the line height of the Japanese font is slightly larger than the one of a Latin font, the height of the text became slightly larger. However, despite these differences in line heights, the EditText element was sized uniformly, regardless of the locale being used, as illustrated in the following image:

Three boxes representing EditText elements that can contain text from English (en), Japanese (ja), and Burmese (my). The height of the EditText is the same, even though these languages have different line heights from each other.

For apps targeting Android 15, a minimum line height is now reserved for EditText to match the reference font for the specified Locale, as shown in the following image:

Three boxes representing EditText elements that can contain text from English (en), Japanese (ja), and Burmese (my). The height of the EditText now includes space to accommodate the default line height for these languages' fonts.

If needed, your app can restore the previous behavior by specifying the useLocalePreferredLineHeightForMinimum attribute to false, and your app can set custom minimum vertical metrics using the setMinimumFontMetrics API in Kotlin and Java.

Cámara y contenido multimedia

En Android 15, se realizan los siguientes cambios en el comportamiento de la cámara y el contenido multimedia para las apps orientadas a Android 15 o versiones posteriores.

Restricciones para solicitar foco de audio

Las apps orientadas a Android 15 deben ser la app principal o que ejecuten un servicio en primer plano para solicitar foco de audio. Si una app intenta solicitar el foco cuando no cumple con uno de estos requisitos, la llamada mostrará AUDIOFOCUS_REQUEST_FAILED.

Puedes obtener más información sobre el foco de audio en Cómo administrar el foco de audio.

Actualización de restricciones que no pertenecen al SDK

Android 15 incluye listas actualizadas de usuarios restringidos que no pertenecen al SDK basadas en la colaboración con desarrolladores de Android y la las pruebas internas. Siempre que sea posible, nos aseguramos de que las alternativas públicas estén disponibles antes de restringir las interfaces que no pertenecen al SDK.

Si tu app no está orientada a Android 15, se implementarán algunos de estos cambios. podría no afectarte de inmediato. Sin embargo, si bien es posible que tu app acceder a algunas interfaces que no pertenecen al SDK según el nivel de API objetivo de tu app, con cualquier método o campo siempre conlleva un alto riesgo de error para tu app.

Si no sabes con certeza si tu app usa interfaces que no pertenecen al SDK, puedes prueba tu app para averiguarlo. Si tu app depende del SDK , debes planificar la migración a alternativas de SDK. Sin embargo, entendemos que algunas apps tienen casos de uso válidos para usar que no pertenecen al SDK. Si no encuentras una alternativa al uso de un SDK interfaz de una función de tu app, deberías solicitar una nueva API pública

Para obtener más información sobre los cambios implementados en esta versión de Android, consulta Actualizaciones a las restricciones de interfaces que no pertenecen al SDK en Android 15. Para obtener más información sobre interfaces que no pertenecen al SDK en general, consulta Restricciones en interfaces que no pertenecen al SDK.