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 a 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 de revisar también la lista de cambios de 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.

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 adecuado 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.

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.

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

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

Si un receptor BOOT_COMPLETED intenta iniciar cualquiera de esos tipos de servicios en primer plano, el sistema arrojará ForegroundServiceStartNotAllowedException.

Cambios en la capacidad de las apps para 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 OpenJDK 17

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 LTS de OpenJDK.

Uno de estos cambios puede afectar la compatibilidad de las apps orientadas a Android 15:

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

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

    IllegalFormatArgumentIndexException: Illegal format argument index = 0
    

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

  • Cambios en el manejo del código de idioma: Cuando se usa la API de Locale, los códigos de idioma para hebreo, indonesio y yidis ya no se convierten a sus formas obsoletas (hebreo: iw, yiddish: ji e indonesio: in). Cuando se especifica el código de idioma de una de estas configuraciones regionales, usa los códigos de ISO 639-1 (hebreo: he, yidis: yi0 e indonesio}).id

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

    En general, este cambio no debería causar un comportamiento irreversible en la app, pero tu código no debería esperar que la secuencia generada a partir de los métodos Random.ints() coincida con Random.nextInt().

Seguridad

Android 15 incluye cambios que promueven la seguridad del sistema para proteger a los usuarios y las apps 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" >

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.

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

Android 15 incluye algunos cambios destinados a crear una experiencia del usuario más intuitiva y coherente.

Cambios en la inserción de ventana

En Android 15, habrá dos cambios relacionados con las inserciones de ventana. En la versión Beta 1, se aplicará de borde a borde. También hay próximos cambios de configuración, incluida la configuración predeterminada de las barras del sistema.

Aplicación de borde a borde

Las apps serán de borde a borde de forma predeterminada en dispositivos que ejecutan Android 15 si están orientadas a esa versión.

Una app que se orienta a Android 14 y no es de borde a borde en un dispositivo con Android 15


Esta es una app que se orienta a Android 15 y que es de borde a borde en un dispositivo con Android 15. Esta app usa principalmente componentes de Compose de Material 3 que aplican inserciones automáticamente. Esta pantalla no se ve afectada negativamente por la aplicación de borde a borde de Android 15.

Este es un cambio rotundo que podría afectar de forma negativa la IU de tu app. Los cambios son los siguientes:

  • Barra de navegación del controlador de gestos
    • Es transparente de forma predeterminada.
    • El desplazamiento inferior está inhabilitado para que el contenido se dibuje detrás de la barra de navegación del sistema, a menos que se apliquen inserciones.
    • setNavigationBarColor y R.attr#navigationBarColor dejaron de estar disponibles y no afectan la navegación por gestos.
    • setNavigationBarContrastEnforced y R.attr#navigationBarContrastEnforced continúan sin tener efecto en la navegación por gestos.
  • Navegación con 3 botones
    • La opacidad se establece en un 80% de forma predeterminada y es posible que el color coincida con el fondo de la ventana.
    • El desplazamiento inferior está inhabilitado para que el contenido se dibuje detrás de la barra de navegación del sistema, a menos que se apliquen inserciones.
    • setNavigationBarColor y R.attr#navigationBarColor están configurados para que coincidan con el fondo de la ventana de forma predeterminada. El fondo de la ventana debe ser un elemento de diseño de color para que se aplique este valor predeterminado. Esta API dejó de estar disponible, pero continúa afectando la navegación de tres botones.
    • setNavigationBarContrastEnforced y R.attr#navigationBarContrastEnforced son verdaderos de forma predeterminada, lo que agrega un 80% de fondo opaco en la navegación con tres botones.
  • Barra de estado
    • Es transparente de forma predeterminada.
    • El desplazamiento superior está inhabilitado, por lo que el contenido se dibujará detrás de la barra de estado, a menos que se apliquen inserciones.
    • setStatusBarColor y R.attr#statusBarColor dejaron de estar disponibles y no tienen efecto en Android 15.
    • setStatusBarContrastEnforced y R.attr#statusBarContrastEnforced dejaron de estar disponibles, pero aún tienen efecto en Android 15.
  • Corte de pantalla
    • El layoutInDisplayCutoutMode de las ventanas no flotantes debe ser LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS. En la versión beta 1 de Android 15, las apps fallarán con una IllegalArgumentException si se usa SHORT_EDGES, NEVER o DEFAULT (p.ej., LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT). En la versión beta 2 de Android 15, SHORT_EDGES, NEVER y DEFAULT se interpretarán como ALWAYS para que los usuarios no vean una barra negra causada por el corte de pantalla y aparezcan de borde a borde.

En el siguiente ejemplo, se muestra una app antes y después de orientarla a Android 15, y antes y después de aplicar las inserciones.

Una app que se orienta a Android 14 y no es de borde a borde en un dispositivo con Android 15
App que se orienta a Android 15 y que es de borde a borde en un dispositivo con Android 15 Sin embargo, muchos elementos ahora están ocultos por la barra de estado, la barra de navegación de 3 botones o el corte de pantalla debido a las aplicaciones de borde a borde de Android 15. La IU ocluida incluye la TopAppBar de Material 2, el BAF y los elementos de lista.
Una app que se orienta a Android 15, está de borde a borde en un dispositivo con Android 15 y aplica inserciones para que la IU no quede oculta.

Si tu app:

  • ya es de de borde a borde y aplica inserciones, en la mayoría de los casos, no se verá afectado, excepto en las siguientes situaciones. Sin embargo, incluso si sientes que no te afecta, te recomendamos que pruebes la app.
    • Tienes una ventana no flotante, como una actividad que usa SHORT_EDGES, NEVER o DEFAULT en lugar de LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS. Si tu app falla durante el inicio, es posible que se deba a la pantalla de presentación. Puedes actualizar la dependencia de la pantalla de presentación principal a la versión 1.2.0-alpha01 o una posterior, configurar window.attributes.layoutInDisplayCutoutMode = WindowManager.LayoutInDisplayCutoutMode.always o realizar una prueba con la versión beta 2 de Android 15 en lugar de la versión 1.
    • Es posible que haya pantallas con menos tráfico si la IU está oculta. Verifica que estas pantallas menos visitadas no tengan una IU oculta. Estas son algunas de las pantallas de menor tráfico:
      • Pantallas de integración o acceso
      • Páginas de configuración
  • no es de borde a borde, lo más probable es que te afecte. Además de las situaciones de las apps que ya son de borde a borde, deberás tener en cuenta lo siguiente:
    • Si tu app usa componentes de Material 3 (androidx.compose.material3 en Compose, como TopAppBar, BottomAppBar y NavigationBar, es probable que estos componentes no se vean afectados porque controlan las inserciones automáticamente.
    • Si tu app usa componentes de Material 2 (androidx.compose.material en Compose, estos componentes no controlan las inserciones automáticamente. Sin embargo, puedes obtener acceso a las inserciones y aplicarlas manualmente. En androidx.compose.material 1.6.0 y posteriores, usa el parámetro windowInsets para aplicar las inserciones de forma manual para BottomAppBar, TopAppBar, BottomNavigation y NavigationRail. Del mismo modo, usa el parámetro contentWindowInsets para Scaffold.
    • Si tu app usa Views y componentes de Material (com.google.android.material, la mayoría de los componentes de Material basados en Views, como BottomNavigationView, BottomAppBar, NavigationRailView o NavigationView), controlan las inserciones y no requieren trabajo adicional. Sin embargo, deberás agregar android:fitsSystemWindows="true" si usas AppBarLayout.
    • En el caso de los elementos componibles personalizados, aplica las inserciones de forma manual como padding. Si tu contenido está dentro de Scaffold, puedes consumir inserciones con valores de padding de Scaffold. De lo contrario, aplica padding mediante uno de los WindowInsets.
    • Si tu app usa Views, BottomSheet, SideSheet o contenedores personalizados, aplica padding con ViewCompat.setOnApplyWindowInsetsListener. Para RecyclerView, aplica padding con este objeto de escucha y también agrega clipToPadding="false".
  • debes ofrecer una protección de fondo personalizada para la navegación con tres botones o la barra de estado, tu app debe colocar un elemento componible o una vista detrás de la barra del sistema con WindowInsets.Type#tappableElement() para obtener la altura de la barra de navegación con tres botones o WindowInsets.Type#statusBars.

Consulta las guías de Edge to Edge Views y las guías de Edge to Edge Compose para obtener consideraciones adicionales sobre la aplicación de inserciones.

Esta es la lista de APIs inhabilitadas y obsoletas:

  • R.attr#estadoBarColor
  • R.attr#navegaciónBarColor
  • R.attr#navegaciónBarDividerColor
  • Ventana#setDecorFitsSystemWindows
  • Ventana#setStatusBarColor
  • Ventana#setStatusBarContrastEnforced
  • Ventana#setNavigationBarColor
  • Ventana#setNavigationBarDividerColor
  • Ventana#getStatusBarColor
  • Ventana#getStatusBarContrastEnforced
  • Ventana#getNavigationBarColor
  • Ventana#getNavigationBarDividerColor

Configuración estable

Este cambio no está disponible para probar en la versión beta 1, pero pronto lo estará.

Si tu app se orienta a Android 15 o versiones posteriores, Configuration ya no excluye las barras del sistema. Si usas el tamaño de pantalla en la clase Configuration para el cálculo del diseño, debes reemplazarlo por alternativas mejores, como un ViewGroup, WindowInsets o WindowMetricsCalculator apropiados según tus necesidades.

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

El tamaño de la configuración se suele usar para la selección de recursos, como /res/layout-h500dp, y este sigue siendo un caso de uso válido. Sin embargo, siempre no se recomienda su uso para el cálculo del diseño. Si lo haces, debes dejar de hacerlo ahora. Debes reemplazar el uso de Configuration por algo más adecuado según tu caso de uso.

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

En la siguiente lista, se describen los campos 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 en el 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:shiftDrawingOffsetForStartOverhan="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:shiftDrawingOffsetForStartOverhan="true" />

Altura de línea predeterminada en función 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 ejecutar un servicio en primer plano relacionado con el audio para solicitar el foco de audio. Si una app intenta solicitar el foco cuando no cumple con uno de estos requisitos, la llamada mostrará AUDIOFOCUS_REQUEST_FAILED.

Un servicio en primer plano se considera relacionado con el audio si su tipo es mediaPlayback, camera, microphone o phoneCall.

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 este tipo de interfaces que están basadas en la colaboración con desarrolladores de Android y las pruebas internas más recientes. 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, es posible que algunos de estos cambios no te afecten de inmediato. Sin embargo, aunque es posible que tu app acceda a algunas interfaces que no pertenecen al SDK según el nivel de API al que está orientada tu app, usar cualquier método o campo que no pertenece al SDK siempre implica un gran riesgo de error para tu app.

Si no sabes con certeza si tu app usa este tipo de interfaces, puedes probarla para averiguarlo. Si tu app depende de interfaces que no pertenecen al SDK, debes comenzar a planificar una migración hacia otras alternativas SDK. Sin embargo, sabemos que algunas apps tienen casos de uso válidos para usar interfaces que no pertenecen al SDK. Si no encuentras una alternativa para reemplazar el uso de una interfaz que no pertenece al SDK para 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.