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 de revisar también la lista de cambios de comportamiento que afectan a todas las apps que se ejecutan en Android 15, independientemente de targetSdkVersion de la app.

Funcionalidad principal

Android 15 modifica o expande varias funciones 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 introduces a new timeout behavior to dataSync for apps targeting Android 15 (API level 35) or higher. This behavior also applies to the new mediaProcessing foreground service type.

The system permits an app's dataSync services to run for a total of 6 hours in a 24-hour period, after which the system calls the running service's Service.onTimeout(int, int) method (introduced in Android 15). At this time, the service has a few seconds to call Service.stopSelf(). When Service.onTimeout() is called, the service is no longer considered a foreground service. If the service does not call Service.stopSelf(), the system throws an internal exception. The exception is logged in Logcat with the following message:

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

To avoid problems with this behavior change, you can do one or more of the following:

  1. Have your service implement the new Service.onTimeout(int, int) method. When your app receives the callback, make sure to call stopSelf() within a few seconds. (If you don't stop the app right away, the system generates a failure.)
  2. Make sure your app's dataSync services don't run for more than a total of 6 hours in any 24-hour period (unless the user interacts with the app, resetting the timer).
  3. Only start dataSync foreground services as a result of direct user interaction; since your app is in the foreground when the service starts, your service has the full six hours after the app goes to the background.
  4. Instead of using a dataSync foreground service, use an alternative API.

If your app's dataSync foreground services have run for 6 hours in the last 24, you cannot start another dataSync foreground service unless the user has brought your app to the foreground (which resets the timer). If you try to start another dataSync foreground service, the system throws ForegroundServiceStartNotAllowedException with an error message like "Time limit already exhausted for foreground service type dataSync".

Testing

To test your app's behavior, you can enable data sync timeouts even if your app is not targeting Android 15 (as long as the app is running on an Android 15 device). To enable timeouts, run the following adb command:

adb shell am compat enable FGS_INTRODUCE_TIME_LIMITS your-package-name

You can also adjust the timeout period, to make it easier to test how your app behaves when the limit is reached. To set a new timeout period, run the following adb command:

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 adecuado para operaciones como la transcodificación de archivos multimedia. Por ejemplo, una app de música puede 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 está en segundo plano.

El sistema permite que los servicios mediaProcessing de una app se ejecuten durante un total de 6 horas en un período de 24 horas, después del cual 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 tener 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 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. Inicia servicios en primer plano de mediaProcessing solo como resultado de la interacción directa del usuario. Como tu app está en primer plano cuando se inicia el servicio, este 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 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 puedes 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 en primer plano mediaProcessing, el sistema arroja ForegroundServiceStartNotAllowedException con un mensaje de error como "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.

Prueba

Para probar el comportamiento de tu app, puedes habilitar los tiempos de espera de procesamiento de contenido multimedia, incluso si tu app no está orientada a Android 15 (siempre que 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 para los receptores de emisión BOOT_COMPLETED que inician servicios en primer plano

There are new restrictions on BOOT_COMPLETED broadcast receivers launching foreground services. BOOT_COMPLETED receivers are not allowed to launch the following types of foreground services:

If a BOOT_COMPLETED receiver tries to launch any of those types of foreground services, the system throws ForegroundServiceStartNotAllowedException.

Testing

To test your app's behavior, you can enable these new restrictions even if your app is not targeting Android 15 (as long as the app is running on an Android 15 device). Run the following adb command:

adb shell am compat enable FGS_BOOT_COMPLETED_RESTRICTIONS your-package-name

To send a BOOT_COMPLETED broadcast without restarting the device, run the following adb command:

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

Restricciones para iniciar servicios en primer plano mientras una app tiene 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 la app estaba en segundo plano (como se explica en exenciones de las restricciones de inicio en segundo plano).

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

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

Si tu app declara el permiso SYSTEM_ALERT_WINDOW y, luego, inicia servicios en primer plano desde el segundo plano, es posible que se vea afectada por este cambio. Si tu app obtiene una ForegroundServiceStartNotAllowedException, verifica el orden de operaciones de tu app y asegúrate de que ya tenga una ventana de superposición activa antes de intentar iniciar un servicio en primer plano desde el segundo plano. Puedes verificar si tu ventana de superposición es visible actualmente llamando a View.getWindowVisibility() o puedes anular View.onWindowVisibilityChanged() para recibir notificaciones cada vez que cambie la visibilidad.

Prueba

Para probar el comportamiento de tu app, puedes habilitar estas nuevas restricciones, incluso si tu app no está segmentada para Android 15 (siempre que la app se ejecute en un dispositivo con Android 15). Para habilitar estas nuevas restricciones para iniciar servicios en primer plano desde segundo plano, ejecuta el siguiente comando adb:

adb shell am compat enable FGS_SAW_RESTRICTIONS your-package-name

Se modificaron los momentos en que las apps pueden modificar el estado global del modo No interrumpir.

Apps that target Android 15 (API level 35) and higher can no longer change the global state or policy of Do Not Disturb (DND) on a device (either by modifying user settings, or turning off DND mode). Instead, apps must contribute an AutomaticZenRule, which the system combines into a global policy with the existing most-restrictive-policy-wins scheme. Calls to existing APIs that previously affected global state (setInterruptionFilter, setNotificationPolicy) result in the creation or update of an implicit AutomaticZenRule, which is toggled on and off depending on the call-cycle of those API calls.

Note that this change only affects observable behavior if the app is calling setInterruptionFilter(INTERRUPTION_FILTER_ALL) and expects that call to deactivate an AutomaticZenRule that was previously activated by their owners.

Cambios en la API de OpenJDK

Android 15 continues the work of refreshing Android's core libraries to align with the features in the latest OpenJDK LTS releases.

Some of these changes can affect app compatibility for apps targeting Android 15 (API level 35):

  • Changes to string formatting APIs: Validation of argument index, flags, width, and precision are now more strict when using the following String.format() and Formatter.format() APIs:

    For example, the following exception is thrown when an argument index of 0 is used (%0 in the format string):

    IllegalFormatArgumentIndexException: Illegal format argument index = 0
    

    In this case, the issue can be fixed by using an argument index of 1 (%1 in the format string).

  • Changes to component type of Arrays.asList(...).toArray(): When using Arrays.asList(...).toArray(), the component type of the resulting array is now an Object—not the type of the underlying array's elements. So the following code throws a ClassCastException:

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

    For this case, to preserve String as the component type in the resulting array, you could use Collection.toArray(Object[]) instead:

    String[] elements = Arrays.asList("two", "one").toArray(new String[0]);
    
  • Changes to language code handling: When using the Locale API, language codes for Hebrew, Yiddish, and Indonesian are no longer converted to their obsolete forms (Hebrew: iw, Yiddish: ji, and Indonesian: in). When specifying the language code for one of these locales, use the codes from ISO 639-1 instead (Hebrew: he, Yiddish: yi, and Indonesian: id).

  • Changes to random int sequences: Following the changes made in https://bugs.openjdk.org/browse/JDK-8301574, the following Random.ints() methods now return a different sequence of numbers than the Random.nextInt() methods do:

    Generally, this change shouldn't result in app-breaking behavior, but your code shouldn't expect the sequence generated from Random.ints() methods to match Random.nextInt().

The new SequencedCollection API can affect your app's compatibility after you update compileSdk in your app's build configuration to use Android 15 (API level 35):

  • Collision with MutableList.removeFirst() and MutableList.removeLast() extension functions in kotlin-stdlib

    The List type in Java is mapped to the MutableList type in Kotlin. Because the List.removeFirst() and List.removeLast() APIs have been introduced in Android 15 (API level 35), the Kotlin compiler resolves function calls, for example list.removeFirst(), statically to the new List APIs instead of to the extension functions in kotlin-stdlib.

    If an app is re-compiled with compileSdk set to 35 and minSdk set to 34 or lower, and then the app is run on Android 14 and lower, a runtime error is thrown:

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

    The existing NewApi lint option in Android Gradle Plugin can catch these new API usages.

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

    To fix the runtime exception and lint errors, the removeFirst() and removeLast() function calls can be replaced with removeAt(0) and removeAt(list.lastIndex) respectively in Kotlin. If you're using Android Studio Ladybug | 2024.1.3 or higher, it also provides a quick fix option for these errors.

    Consider removing @SuppressLint("NewApi") and lintOptions { disable 'NewApi' } if the lint option has been disabled.

  • Collision with other methods in Java

    New methods have been added into the existing types, for example, List and Deque. These new methods might not be compatible with the methods with the same name and argument types in other interfaces and classes. In the case of a method signature collision with incompatibility, the javac compiler outputs a build-time error. For example:

    Example 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
    

    Example 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
    

    Example 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
    

    To fix these build errors, the class implementing these interfaces should override the method with a compatible return type. For example:

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

Seguridad

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

Versiones de TLS restringidas

Android 15 restringe el uso de las versiones 1.0 y 1.1 de TLS. Estas versiones ya habían dejado de estar disponibles en Android, pero ahora no se permiten para las apps que se orientan a Android 15.

Inicios de actividades en segundo plano seguros

Android 15 protects users from malicious apps and gives them more control over their devices by adding changes that prevent malicious background apps from bringing other apps to the foreground, elevating their privileges, and abusing user interaction. Background activity launches have been restricted since Android 10 (API level 29).

Other changes

In addition to the restriction for UID matching, these other changes are also included:

  • Change PendingIntent creators to block background activity launches by default. This helps prevent apps from accidentally creating a PendingIntent that could be abused by malicious actors.
  • Don't bring an app to the foreground unless the PendingIntent sender allows it. This change aims to prevent malicious apps from abusing the ability to start activities in the background. By default, apps are not allowed to bring the task stack to the foreground unless the creator allows background activity launch privileges or the sender has background activity launch privileges.
  • Control how the top activity of a task stack can finish its task. If the top activity finishes a task, Android will go back to whichever task was last active. Moreover, if a non-top activity finishes its task, Android will go back to the home screen; it won't block the finish of this non-top activity.
  • Prevent launching arbitrary activities from other apps into your own task. This change prevents malicious apps from phishing users by creating activities that appear to be from other apps.
  • Block non-visible windows from being considered for background activity launches. This helps prevent malicious apps from abusing background activity launches to display unwanted or malicious content to users.

Intents más seguros

Android 15 introduces new optional 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.

In order to check how your app responds to these changes, use StrictMode in your app. To see detailed logs about Intent usage violations, add the following method:

Kotlin

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

Java

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

Experiencia del usuario y IU del sistema

Android 15 incluye algunos cambios que tienen como objetivo crear una experiencia del usuario más intuitiva y coerente.

Cambios en la inserción de ventana

There are two changes related to window insets in Android 15: edge-to-edge is enforced by default, and there are also configuration changes, such as the default configuration of system bars.

Aplicación de borde a borde

Las apps se muestran de borde a borde de forma predeterminada en los dispositivos que ejecutan Android 15 si se orientan a Android 15 (nivel de API 35).

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


Una app que se orienta a Android 15 (nivel de API 35) y que ocupa todo el 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 forzosa 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 afectan las siguientes áreas de la IU:

  • Barra de navegación con control 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 siguen sin tener efecto en la navegación por gestos.
  • Navegación con 3 botones
    • La opacidad se establece en 80% de forma predeterminada, y el color puede coincidir con el fondo de la ventana.
    • Se inhabilitó el desplazamiento inferior 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 se configuran 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 sigue afectando la navegación de 3 botones.
    • setNavigationBarContrastEnforced y R.attr#navigationBarContrastEnforced son verdaderos de forma predeterminada, lo que agrega un fondo opaco del 80% en la navegación con 3 botones.
  • Barra de estado
    • Es transparente de forma predeterminada.
    • El desplazamiento superior está inhabilitado para que el contenido se dibuje 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 ningún efecto en Android 15.
    • setStatusBarContrastEnforced y R.attr#statusBarContrastEnforced dejaron de estar disponibles, pero aún tienen un efecto en Android 15.
  • Recorte de la pantalla
    • layoutInDisplayCutoutMode de las ventanas no flotantes debe ser LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS. SHORT_EDGES, NEVER y DEFAULT se interpretan como ALWAYS para que los usuarios no vean una barra negra causada por el corte de la pantalla y se muestren de borde a borde.

En el siguiente ejemplo, se muestra una app antes y después de orientarse a Android 15 (nivel de API 35), y antes y después de aplicar inserciones.

Una app que se orienta a Android 14 y no es de borde a borde en un dispositivo Android 15.
Una app que se orienta a Android 15 (nivel de API 35) y 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 forzosas de borde a borde de Android 15. La IU oculta incluye la barra superior de la app de Material 2, los botones de acción flotantes y los elementos de lista.
Una app que se orienta a Android 15 (nivel de API 35), se extiende de borde a borde en un dispositivo Android 15 y aplica inserciones para que la IU no esté oculta.
Qué verificar si tu app ya es de borde a borde

Si tu app ya es de borde a borde y aplica inserciones, no se verá afectada, excepto en las siguientes situaciones. Sin embargo, incluso si crees que no se verá afectada, te recomendamos que pruebes tu app.

  • Tienes una ventana no flotante, como una Activity 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 splashscreen principal a 1.2.0-alpha01 o una versión posterior, o bien configurar window.attributes.layoutInDisplayCutoutMode = WindowManager.LayoutInDisplayCutoutMode.always.
  • Puede haber pantallas con menos tráfico con una IU ocluida. Verifica que estas pantallas menos visitadas no tengan una IU ocluida. Entre las pantallas con menos tráfico, se incluyen las siguientes:
    • Pantallas de integración o acceso
    • Páginas de configuración
Qué verificar si tu app aún no es de borde a borde

Si tu app aún no es de borde a borde, es probable que se vea afectada. Además de las situaciones de las apps que ya son de borde a borde, debes 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 automáticamente las inserciones.
  • Si tu app usa componentes de Material 2 (androidx.compose.material) en Compose, estos 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 versiones posteriores, usa el parámetro windowInsets para aplicar las inserciones de forma manual para BottomAppBar, TopAppBar, BottomNavigation y NavigationRail. De la misma manera, usa el parámetro contentWindowInsets para Scaffold.
  • Si tu app usa vistas y componentes de Material (com.google.android.material), la mayoría de los componentes de Material basados en vistas, como BottomNavigationView, BottomAppBar, NavigationRailView o NavigationView, controlan las inserciones y no requieren trabajo adicional. Sin embargo, debes agregar android:fitsSystemWindows="true" si usas AppBarLayout.
  • Para los elementos componibles personalizados, aplica las inserciones de forma manual como relleno. Si tu contenido está dentro de un Scaffold, puedes consumir inserciones con los valores de padding Scaffold. De lo contrario, aplica el padding con uno de los WindowInsets.
  • Si tu app usa vistas y BottomSheet, SideSheet o contenedores personalizados, aplica relleno con ViewCompat.setOnApplyWindowInsetsListener. Para RecyclerView, aplica relleno con este objeto de escucha y también agrega clipToPadding="false".
Qué verificar si tu app debe ofrecer protección en segundo plano personalizada

Si tu app debe ofrecer protección en segundo plano personalizada a la navegación de 3 botones o a la barra de estado, 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 de 3 botones o WindowInsets.Type#statusBars.

Recursos adicionales de borde a borde

Consulta las guías Views de borde a borde y Compose de borde a borde para obtener más información sobre la aplicación de inserciones.

APIs obsoletas

Las siguientes APIs dejaron de estar disponibles, pero no están inhabilitadas:

Las siguientes APIs dejaron de estar disponibles y están inhabilitadas:

Configuración estable

Si tu app está orientada a Android 15 (nivel de API 35) 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 mejores alternativas, 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, orientación y tamaño de la ventana. Una característica importante de los tamaños de ventana que se muestran desde Configuration es que anteriormente excluía las barras del sistema.

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

Si lo usas para calcular el diseño, usa 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 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 elegantTextHeight tiene el valor predeterminado de verdadero.

En el caso de las apps orientadas a Android 15 (nivel de API 35), el atributo elegantTextHeight TextView se convierte en true de forma predeterminada, lo que reemplaza la fuente compacta que se usa de forma predeterminada con algunas secuencias de comandos que tienen métricas verticales grandes por una que es mucho más legible. La fuente compacta se introdujo para evitar que se rompan los diseños. Android 13 (nivel de API 33) evita muchos de estos daños, ya que permite 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 probable que no sea compatible con las próximas versiones. Por lo tanto, si tu app admite las siguientes secuencias de comandos: árabe, lao, birmano, tamil, guyaratí, canarés, malabar, odía, telugu o tailandés, configura elegantTextHeight como true para probarla.

Comportamiento de elegantTextHeight para apps orientadas a Android 14 (nivel de API 34) y versiones anteriores.
Comportamiento de elegantTextHeight para apps orientadas a Android 15.

Cambios en el ancho de TextView para formas de letras complejas

En versiones anteriores de Android, algunas fuentes o idiomas en cursiva que tienen formas complejas podrían dibujar las letras en el área del carácter anterior o siguiente. En algunos casos, esas letras se cortaron al principio o al final. A partir de Android 15, un TextView asigna ancho para dibujar suficiente espacio para esas letras y permite que las apps soliciten paddings adicionales a la izquierda para evitar los recortes.

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

Como agregar padding izquierdo puede causar un desajuste en 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 de texto para algunas fuentes y algunos idiomas.

Diseño estándar para texto en inglés en una fuente cursiva. Algunas de las letras están cortadas. 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 cortadas. 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 que se adapta a 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 (API level 35), 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

Android 15 realiza 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 el foco de audio

Apps that target Android 15 (API level 35) must be the top app or running a foreground service in order to request audio focus. If an app attempts to request focus when it does not meet one of these requirements, the call returns AUDIOFOCUS_REQUEST_FAILED.

You can learn more about audio focus at Manage audio focus.

Actualización de restricciones que no pertenecen al SDK

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

If your app does not target Android 15, some of these changes might not immediately affect you. However, while it's possible for your app to access some non-SDK interfaces depending on your app's target API level, using any non-SDK method or field always carries a high risk of breaking your app.

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

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