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.

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 las apps que se orientan a Android 15 o versiones posteriores. Este comportamiento también se aplica al nuevo tipo de servicio en primer plano de mediaProcessing.

El sistema permite que los servicios dataSync de una app se ejecuten durante un total de 6 horas en un período de 24 horas, después de lo cual 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(). Cuando se llama a Service.onTimeout(), el servicio ya no se considera un servicio en primer plano. Si el servicio no llama a Service.stopSelf(), se producirá un error con este mensaje de error: "Un servicio en primer plano de <fgs_type> no se detuvo dentro del tiempo de espera: <component_name>". En la versión beta 2, el mensaje de error se muestra como un error de ANR, pero, en una versión beta futura, este mensaje de error arrojará una excepción personalizada.

Para evitar problemas con este cambio de comportamiento, puedes realizar una o más 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 generará una falla).
  2. Asegúrate de que los servicios dataSync de tu app no se ejecuten durante más de un total de 6 horas en cualquier período de 24 horas (a menos que el usuario interactúe con la app y restablezca el temporizador).
  3. Solo inicia los servicios en primer plano dataSync como resultado de la interacción directa del usuario. Como tu app se encuentra en primer plano cuando se inicia el servicio, este tiene las seis horas completas una vez que la app pasa a segundo plano.
  4. En lugar de usar un servicio en primer plano de dataSync, usa una API alternativa.

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

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.

El sistema permite que se ejecuten los servicios mediaProcessing de una app durante un total de 6 horas en un período de 24 horas, después de lo cual 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(), se producirá un error con este mensaje de error: "Un servicio en primer plano de <fgs_type> no se detuvo durante el tiempo de espera: <component_name>". En la versión beta 2, el mensaje de error se muestra como un error de ANR, pero, en una versión beta futura, este mensaje de error arrojará una excepción personalizada.

Para evitar recibir un error de ANR, 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 generará una falla).
  2. Asegúrate de que los servicios de mediaProcessing de tu app no se ejecuten durante más de un total de 6 horas en cualquier período de 24 horas (a menos que el usuario interactúe con la app y restablezca el temporizador).
  3. Solo inicia los servicios en primer plano mediaProcessing como resultado de la interacción directa del usuario. Como tu app se encuentra en primer plano cuando se inicia el servicio, este tiene las seis horas completas una vez 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 en primer plano de mediaProcessing a menos que el usuario haya llevado la app al primer plano (lo que restablece el temporizador). Si intentas iniciar otro servicio en primer plano mediaProcessing, el sistema arrojará una ForegroundServiceStartNotAllowedException con un mensaje de error, como “Ya se agotó el tiempo límite 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 servicios en primer plano para Android 15: Procesamiento de contenido multimedia.

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.

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 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" >

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 introduce nuevas medidas de seguridad para que los intents sean más seguros y sólidos. El objetivo de estos cambios es evitar posibles vulnerabilidades y un uso inadecuado de los intents que las apps maliciosas pueden aprovechar. Existen dos mejoras principales en la seguridad de los intents en Android 15:

  • Hacer coincidir los filtros de intents objetivo: Los intents que se orientan a componentes específicos deben coincidir con precisión con las especificaciones de filtros de intents del destino. Si envías un intent para iniciar la actividad de otra app, el componente del intent objetivo debe alinearse con los filtros de intents declarados de la actividad receptora.
  • Los intents deben tener acciones: Los intents que no tengan una acción ya no coincidirán con ningún filtro de intents. Esto significa que los intents que se usan para iniciar actividades o servicios deben tener una acción claramente definida.

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

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

En las versiones anteriores de Android, el diseño de texto estiraba la altura del texto para cumplir con la altura de la línea de la fuente que coincidía con la configuración regional actual. Por ejemplo, si el contenido estaba en japonés, debido a que la altura de la línea de la fuente japonesa es ligeramente mayor que la de una fuente latina, la altura del texto se agrandó un poco más grande. Sin embargo, a pesar de estas diferencias en las alturas de las líneas, el tamaño del elemento EditText se dimensionó de manera uniforme, independientemente de la configuración regional que se usara, como se ilustra en la siguiente imagen:

Tres cuadros que representan elementos EditText que pueden contener texto de inglés (en), japonés (ja) y birmano (my). La altura de EditText es la misma, aunque estos idiomas tienen alturas de línea diferentes.

En el caso de las apps orientadas a Android 15, ahora se reserva una altura de línea mínima para que EditText coincida con la fuente de referencia de la configuración regional especificada, como se muestra en la siguiente imagen:

Tres cuadros que representan elementos EditText que pueden contener texto de inglés (en), japonés (ja) y birmano (my). La altura de EditText ahora incluye espacio para adaptarse a la altura de línea predeterminada de las fuentes de estos idiomas.

Si es necesario, tu app puede restablecer el comportamiento anterior especificando el atributo useLocalePreferredLineHeightForMinimum en false, y tu app puede establecer métricas verticales mínimas personalizadas con la API de setMinimumFontMetrics en Kotlin y 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.