Al igual que las versiones anteriores, Android 15 incluye cambios de comportamiento que podrían afectar tu app. Los siguientes cambios se aplican exclusivamente a las apps orientadas a Android 15 o versiones posteriores. Si tu app está orientada a Android 15 o versiones posteriores, debes modificarla para que admita estos comportamientos correctamente, cuando corresponda.
Asegúrate también de revisar la lista de cambios en el comportamiento que afectan a todas las apps que se ejecutan en Android 15, independientemente de la targetSdkVersion
de tu app.
Funcionalidad principal
Android 15 modifica o expande varias capacidades principales del sistema Android.
Cambios en los servicios en primer plano
Realizamos los siguientes cambios en los servicios en primer plano con Android 15.
- Comportamiento de tiempo de espera del servicio en primer plano de sincronización de datos
- Nuevo tipo de servicio en primer plano de procesamiento de contenido multimedia
- Restricciones en los receptores de emisión
BOOT_COMPLETED
que inician servicios en primer plano - Restricciones para iniciar servicios en primer plano mientras una app tiene el permiso
SYSTEM_ALERT_WINDOW
Comportamiento de tiempo de espera del servicio en primer plano de la sincronización de datos
Android 15 introduce un nuevo comportamiento de tiempo de espera en dataSync
para la segmentación de apps
Android 15 o una versión posterior Este comportamiento también se aplica a la nueva mediaProcessing
tipo de servicio en primer plano.
El sistema permite que los servicios de dataSync
de una app se ejecuten durante un total de 6 horas
en un período de 24 horas, después de lo cual el sistema llama a la red del
Método Service.onTimeout(int, int)
(presentado en Android)
15). En este momento, el servicio tiene unos segundos para llamar
Service.stopSelf()
. Cuando se llama a Service.onTimeout()
, el elemento
servicio ya no se considera un servicio en primer plano. Si el servicio no
llama a Service.stopSelf()
, el sistema arrojará una excepción interna. El
se registra en Logcat con el siguiente mensaje:
Fatal Exception: android.app.RemoteServiceException: "A foreground service of
type dataSync did not stop within its timeout: [component name]"
Para evitar problemas con este cambio de comportamiento, puedes realizar una o más de las siguientes acciones: lo siguiente:
- 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 astopSelf()
en una unos pocos segundos. (Si no detienes la app de inmediato, el sistema genera falla). - Asegúrate de que los servicios de
dataSync
de tu app no se ejecuten durante un total de 6 horas en cualquier período de 24 horas (salvo que el usuario interactúe con la app) restableciendo el temporizador). - Solo iniciar
dataSync
servicios en primer plano como resultado de la acción de un usuario directo interacción dado que tu app está en primer plano cuando se inicia el servicio el servicio tiene las seis horas completas después de que la app pasa a segundo plano. - En lugar de usar un servicio en primer plano de
dataSync
, usa un alternativa.
Si los servicios en primer plano de dataSync
de tu app se ejecutaron durante 6 horas durante el último período
24, no puedes iniciar otro servicio en primer plano de dataSync
, a menos que el usuario
Puso tu aplicación al primer plano (lo que restablece el temporizador). Si intentas
iniciar otro servicio dataSync
en primer plano, el sistema arrojará
ForegroundServiceStartNotAllowedException
con un mensaje de error como “Ya se agotó el tiempo para el servicio en primer plano
escribe dataSync”.
Pruebas
Para probar el comportamiento de tu app, habilita los tiempos de espera de la sincronización de datos incluso si la app
No está orientada a Android 15 (siempre y cuando la app se ejecute en un dispositivo Android 15).
dispositivo). Para habilitar los tiempos de espera, ejecuta el siguiente comando adb
:
adb shell am compat enable FGS_INTRODUCE_TIME_LIMITS your-package-name
También puedes ajustar el tiempo de espera para probar cómo tus
se comporta cuando se alcanza el límite. Para establecer un nuevo tiempo de espera, ejecuta
siguiente comando adb
:
adb shell device_config put activity_manager data_sync_fgs_timeout_duration duration-in-milliseconds
Nuevo tipo de servicio en primer plano de procesamiento de contenido multimedia
Android 15 presenta un nuevo tipo de servicio en primer plano: mediaProcessing
. Este tipo de servicio es apropiado para operaciones como la transcodificación de archivos multimedia. Por ejemplo, una app de música podría descargar un archivo de audio y necesitar convertirlo a un formato diferente antes de reproducirlo. Puedes usar un servicio en primer plano mediaProcessing
para asegurarte de que la conversión continúe incluso mientras la app se encuentra en segundo plano.
El sistema permite que se ejecuten los servicios de mediaProcessing
de una app durante un total de 6 horas en un período de 24 horas. Después de eso, el sistema llama al método Service.onTimeout(int, int)
del servicio en ejecución (presentado en Android 15). En este momento, el servicio tiene unos segundos para llamar a Service.stopSelf()
. Si el servicio no llama a Service.stopSelf()
, el sistema arroja una excepción interna. La excepción se registra en Logcat con el siguiente mensaje:
Fatal Exception: android.app.RemoteServiceException: "A foreground service of
type mediaProcessing did not stop within its timeout: [component name]"
Para evitar la excepción, puedes realizar una de las siguientes acciones:
- 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 astopSelf()
en unos pocos segundos. (Si no detienes la app de inmediato, el sistema genera una falla). - Asegúrate de que los servicios de
mediaProcessing
de tu app no se ejecuten durante más de 6 horas en total en cualquier período de 24 horas (salvo que el usuario interactúe con la app y restablezca el temporizador). - Solo inicia los servicios en primer plano de
mediaProcessing
como resultado de la interacción directa del usuario. Dado que tu app está en primer plano cuando se inicia el servicio, el servicio tiene seis horas completas después de que la app pasa a segundo plano. - En lugar de usar un servicio en primer plano de
mediaProcessing
, usa una API alternativa, como WorkManager.
Si los servicios en primer plano de mediaProcessing
de tu app se ejecutaron durante 6 horas durante las últimas 24, no podrás iniciar otro servicio mediaProcessing
en primer plano, a menos que el usuario haya llevado la app al primer plano (lo que restablece el temporizador). Si intentas iniciar otro servicio mediaProcessing
en primer plano, el sistema arrojará una ForegroundServiceStartNotAllowedException
con un mensaje de error como "El límite de tiempo ya se agotó para el tipo de servicio en primer plano mediaProcessing".
Para obtener más información sobre el tipo de servicio mediaProcessing
, consulta Cambios en los tipos de servicio en primer plano para Android 15: Procesamiento de contenido multimedia.
Prueba
Para probar el comportamiento de tu app, puedes habilitar los tiempos de espera del procesamiento de contenido multimedia, incluso si tu app no está orientada a Android 15 (siempre y cuando se ejecute en un dispositivo con Android 15). Para habilitar los tiempos de espera, ejecuta el siguiente comando adb
:
adb shell am compat enable FGS_INTRODUCE_TIME_LIMITS your-package-name
También puedes ajustar el tiempo de espera para facilitar la prueba del comportamiento de tu app cuando se alcanza el límite. Para establecer un nuevo tiempo de espera, ejecuta el siguiente comando adb
:
adb shell device_config put activity_manager media_processing_fgs_timeout_duration duration-in-milliseconds
Restricciones en los receptores de emisión de BOOT_COMPLETED
que lanzan 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:
dataSync
camera
mediaPlayback
phoneCall
mediaProjection
microphone
(this restriction has been in place formicrophone
since Android 14)
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 estaba en segundo plano (como se explica en Exenciones de restricciones de inicio en segundo plano).
Si una app se orienta a Android 15, esta exención ahora es menor. Ahora, la app necesita tener el permiso SYSTEM_ALERT_WINDOW
y también tener una ventana superpuesta visible. Es decir, la app debe iniciar primero una ventana TYPE_APPLICATION_OVERLAY
, y esta debe ser visible antes de iniciar un servicio en primer plano.
Si tu app intenta iniciar un servicio en primer plano desde el segundo plano sin cumplir con estos nuevos requisitos (y no tiene alguna otra exención), el sistema arrojará una ForegroundServiceStartNotAllowedException
.
Si tu app declara el permiso SYSTEM_ALERT_WINDOW
e inicia servicios en primer plano desde el segundo plano, es posible que este cambio la afecte. Si tu app obtiene un ForegroundServiceStartNotAllowedException
, verifica el orden de operaciones y asegúrate de que ya tenga una ventana superpuesta activa antes de intentar iniciar un servicio en primer plano en segundo plano. Para comprobar si la ventana de superposición es visible actualmente, llama a View.getWindowVisibility()
. También puedes anular View.onWindowVisibilityChanged()
para recibir notificaciones cada vez que cambie la visibilidad.
Cambios en el momento en que las apps pueden modificar el estado global del modo No interrumpir
Apps that target Android 15 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 continúa la tarea de actualizar las bibliotecas principales de Android para alinearlas con las funciones de las versiones más recientes de OpenJDK LTS.
Algunos de estos cambios pueden afectar la compatibilidad de las apps con la segmentación Android 15 (nivel de API 35):
Cambios en las APIs de formato de cadenas: Validación de índices de argumentos, marcas, ancho y precisión ahora son más estrictas cuando se usan los siguientes APIs de
String.format()
yFormatter.format()
:String.format(String, Object[])
String.format(Locale, String, Object[])
Formatter.format(String, Object[])
Formatter.format(Locale, String, Object[])
Por ejemplo, se arroja la siguiente excepción cuando un índice de argumento es 0. (
%0
en la cadena de formato):IllegalFormatArgumentIndexException: Illegal format argument index = 0
En este caso, el problema se puede solucionar usando un índice de argumentos de 1 (
%1
en la cadena de formato).Cambios en el tipo de componente de
Arrays.asList(...).toArray()
: Cuando se usaArrays.asList(...).toArray()
, el tipo de componente del array resultante es ahora es unObject
, no el tipo de elementos del array subyacente. Entonces, El siguiente código arroja unaClassCastException
:String[] elements = (String[]) Arrays.asList("one", "two").toArray();
En este caso, para conservar
String
como el tipo de componente en la array, puedes usarCollection.toArray(Object[])
en su lugar:String[] elements = Arrays.asList("two", "one").toArray(new String[0]);
Cambios en el manejo del código de idioma: Cuando usas la API de
Locale
, los códigos de idioma del hebreo, el yidis e indonesio ya no se convierten a sus formas obsoletas (en hebreo:iw
, yidis:ji
e indonesio:in
). Al especificar el código de idioma para una de estas configuraciones regionales, utiliza los códigos de ISO 639-1 en su lugar (hebreo:he
, yidis:yi
e indonesio:id
).Cambios en secuencias int aleatorias: Sigue los cambios realizados en https://bugs.openjdk.org/browse/JDK-8301574, los siguientes Los métodos
Random.ints()
ahora muestran una secuencia de números diferente a la los métodosRandom.nextInt()
hacen lo siguiente:Por lo general, este cambio no debería causar un comportamiento rotundo en la app, pero el código no debería esperar que la secuencia generada a partir de los métodos
Random.ints()
coincide conRandom.nextInt()
.
La nueva API de SequencedCollection
puede afectar la compatibilidad de tu app
después de actualizar compileSdk
en la configuración de compilación de tu app para que se use
Android 15 (nivel de API 35):
Colisiones con
MutableList.removeFirst()
y Funciones de extensiónMutableList.removeLast()
enkotlin-stdlib
El tipo
List
en Java se asigna al tipoMutableList
en Kotlin. Debido a que las APIs deList.removeFirst()
yList.removeLast()
se introdujeron en Android 15 (nivel de API 35), el compilador de Kotlin que resuelve llamadas a funciones (por ejemplo,list.removeFirst()
) de forma estática al nuevas APIs deList
en lugar de las funciones de extensión enkotlin-stdlib
:Si se vuelve a compilar una app con
compileSdk
establecido en35
yminSdk
establecido en34
o versiones anteriores, y luego la app se ejecuta en Android 14 y versiones anteriores, un entorno de ejecución se genera el siguiente error:java.lang.NoSuchMethodError: No virtual method removeFirst()Ljava/lang/Object; in class Ljava/util/ArrayList;
La opción de lint
NewApi
existente en el complemento de Android para Gradle puede detectar estos nuevos usos de la API../gradlew lint
MainActivity.kt:41: Error: Call requires API level 35 (current min is 34): java.util.List#removeFirst [NewApi] list.removeFirst()Para corregir la excepción del tiempo de ejecución y los errores de lint, los comandos
removeFirst()
y Las llamadas a funciónremoveLast()
se pueden reemplazar porremoveAt(0)
yremoveAt(list.lastIndex)
respectivamente en Kotlin. Si utilizas Ladybug de Android Studio | 2024.1.3 o una versión posterior, también proporciona una solución rápida para estos errores.Te recomendamos quitar
@SuppressLint("NewApi")
ylintOptions { disable 'NewApi' }
si se inhabilitó la opción de lint.Colisión con otros métodos en Java
Se agregaron métodos nuevos a los tipos existentes, por ejemplo,
List
yDeque
. Es posible que estos nuevos métodos no sean compatibles con métodos con el mismo nombre y los mismos tipos de argumentos en otras interfaces y clases. En el caso de una colisión de firma de método con incompatibilidad, el compiladorjavac
genera un error de tiempo de compilación. Por ejemplo:Ejemplo de error 1:
javac MyList.java
MyList.java:135: error: removeLast() in MyList cannot implement removeLast() in List public void removeLast() { ^ return type void is not compatible with Object where E is a type-variable: E extends Object declared in interface ListEjemplo de error 2:
javac MyList.java
MyList.java:7: error: types Deque<Object> and List<Object> are incompatible; public class MyList implements List<Object>, Deque<Object> { both define reversed(), but with unrelated return types 1 errorEjemplo de error 3:
javac MyList.java
MyList.java:43: error: types List<E#1> and MyInterface<E#2> are incompatible; public static class MyList implements List<Object>, MyInterface<Object> { class MyList inherits unrelated defaults for getFirst() from types List and MyInterface where E#1,E#2 are type-variables: E#1 extends Object declared in interface List E#2 extends Object declared in interface MyInterface 1 errorPara corregir estos errores de compilación, la clase que implementa estas interfaces debe anular el método con un tipo de datos que se devuelve compatible. Por ejemplo:
@Override public Object getFirst() { return List.super.getLast(); }
Seguridad
Android 15 incluye cambios que promueven la seguridad del sistema para ayudar a proteger las apps y a los usuarios de apps maliciosas.
Lanzamientos seguros de actividades en segundo plano
Android 15 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).
Block apps that don't match the top UID on the stack from launching activities
Malicious apps can launch another app's activity within the same task, then
overlay themselves on top, creating the illusion of being that app. This "task
hijacking" attack bypasses current background launch restrictions because it all
occurs within the same visible task. To mitigate this risk, Android 15 adds a
flag that blocks apps that don't match the top UID on the stack from launching
activities. To opt in for all of your app's activities, update the
allowCrossUidActivitySwitchFromBelow
attribute in your app's AndroidManifest.xml
file:
<application android:allowCrossUidActivitySwitchFromBelow="false" >
The new security measures are active if all of the following are true:
- The app performing the launch targets Android 15.
- The app on top of the task stack targets Android 15.
- Any visible activity has opted in to the new protections
If the security measures are enabled, apps might return home, rather than the last visible app, if they finish their own task.
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 aPendingIntent
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 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 el uso inadecuado de los intents que las apps maliciosas pueden aprovechar. Hay dos mejoras principales en la seguridad de los intents en Android 15:
- Coincidir con filtros de intents de destino: Los intents que se orientan a componentes específicos deben coincidir de forma precisa 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 de destino debe alinearse con los filtros de intents declarados de la actividad receptora.
- Intents que 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.
- Intents pendientes: Se trata al creador del intent pendiente como el remitente del intent contenedor, no como el remitente del intent pendiente.
Kotlin
fun onCreate() { StrictMode.setVmPolicy(VmPolicy.Builder() .detectUnsafeIntentLaunch() .build() ) }
Java
public void onCreate() { StrictMode.setVmPolicy(new VmPolicy.Builder() .detectUnsafeIntentLaunch() .build()); }
IU del sistema y experiencia del usuario
En Android 15, se incluyen algunos cambios destinados a crear una experiencia del usuario más intuitiva y coherente.
Cambios en la inserción de ventana
Hay dos cambios relacionados con las inserciones de ventana en Android 15: de borde a borde se aplica de forma predeterminada, y también hay cambios de configuración, como la configuración predeterminada de las barras del sistema.
Aplicación de borde a borde
Las apps son de borde a borde de forma predeterminada en dispositivos que ejecutan Android 15 si se usan orientadas a Android 15 (nivel de API 35).
![](https://developer.android.com/static/about/versions/15/images/edge-to-edge-1.png?authuser=5&hl=es)
Este es un cambio rotundo que podría afectar negativamente la IU de tu app. El afectan las siguientes áreas de la IU:
- Barra de navegación del controlador por gestos
- Es transparente de forma predeterminada.
- El desplazamiento inferior está inhabilitado, por lo que el contenido se dibuja detrás de la navegación del sistema. a menos que se apliquen inserciones.
setNavigationBarColor
yR.attr#navigationBarColor
son y no afectan la navegación por gestos.setNavigationBarContrastEnforced
yR.attr#navigationBarContrastEnforced
siguen sin tener efecto en navegación por gestos.
- Navegación con 3 botones
- Opacidad establecida en 80% de forma predeterminada, con color posiblemente coincidente con la ventana en segundo plano.
- Se inhabilitó el desplazamiento inferior, por lo que el contenido se dibuja detrás de la barra de navegación del sistema a menos que se apliquen inserciones.
setNavigationBarColor
yR.attr#navigationBarColor
son se configura para que coincida 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 es obsoleta, pero continúa afectando la navegación con 3 botones.setNavigationBarContrastEnforced
yR.attr#navigationBarContrastEnforced
es verdadero 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, por lo que el contenido se dibuja detrás de la barra de estado, a menos que se aplican las inserciones.
setStatusBarColor
yR.attr#statusBarColor
son obsoleto y no afectan a Android 15.setStatusBarContrastEnforced
yR.attr#statusBarContrastEnforced
dejaron de estar disponibles, pero aún tienen un el efecto en Android 15.
- Recorte de pantalla
- El
layoutInDisplayCutoutMode
de las ventanas no flotantes deben tenerLAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
SHORT_EDGES
,NEVER
yDEFAULT
se interpretan comoALWAYS
, de modo que los usuarios no ven un negro causada por el corte de la pantalla y aparece de borde a borde.
- El
En el siguiente ejemplo, se muestra una app antes y después de la segmentación Android 15 (nivel de API 35), y antes y después de aplicar inserciones.
![](https://developer.android.com/static/about/versions/15/images/edge-to-edge-4.png?authuser=5&hl=es)
![](https://developer.android.com/static/about/versions/15/images/edge-to-edge-6.png?authuser=5&hl=es)
![](https://developer.android.com/static/about/versions/15/images/edge-to-edge-2.png?authuser=5&hl=es)
Qué debes verificar si tu app ya está de borde a borde
Si tu aplicación ya es de borde a borde y aplica inserciones, puedes hacer lo siguiente: en su mayoría no se verán afectados, excepto en los siguientes escenarios. Sin embargo, incluso si piensas no te afectará, te recomendamos que pruebes tu app.
- Tienes una ventana no flotante, como una
Activity
que usaSHORT_EDGES
,NEVER
oDEFAULT
en lugar deLAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
Si tu app falla durante el inicio, esto podría deberse a la pantalla de presentación. Se pueden actualizar los principales Dependencia de splashscreen a 1.2.0-alpha01 o posterior, o configurawindow.attributes.layoutInDisplayCutoutMode = WindowManager.LayoutInDisplayCutoutMode.always
. - Es posible que haya pantallas con poco tráfico con una IU oculta. Verificar estas opciones
las pantallas menos visitadas no tienen una IU oculta. Las pantallas con poco tráfico incluyen:
- Pantallas de incorporación o acceso
- Páginas de configuración
Qué debes verificar si tu app aún no está de borde a borde
Si tu app aún no está de borde a borde, lo más probable es que te veas afectado. En además de los casos de apps que ya están de borde a borde, considera lo siguiente:
- Si tu app usa componentes de Material 3 (
androidx.compose.material3
) en Compose, comoTopAppBar
,BottomAppBar
yNavigationBar
, es probable que estos componentes no porque manejan automáticamente las inserciones. - Si tu app usa componentes de Material 2 (
androidx.compose.material
) en Compose, estos componentes no controlan automáticamente las inserciones. Sin embargo, puedes acceder a las inserciones y aplicarlos manualmente. En androidx.compose.material 1.6.0 y, luego, usa el parámetrowindowInsets
para aplicar las inserciones de forma manualBottomAppBar
,TopAppBar
BottomNavigation
yNavigationRail
. Del mismo modo, usa el parámetrocontentWindowInsets
paraScaffold
- Si tu app usa vistas y componentes de Material
(
com.google.android.material
), la mayoría de las vistas de Material basadas en vistas Componentes comoBottomNavigationView
,BottomAppBar
,NavigationRailView
oNavigationView
controlan las inserciones y no requieren trabajo adicional. Sin embargo, debes agregarandroid:fitsSystemWindows="true"
si usasAppBarLayout
. - En el caso de los elementos componibles personalizados, aplica las inserciones de forma manual como padding. Si el
contenido dentro de un
Scaffold
, puedes consumir inserciones con elScaffold
valores de padding. De lo contrario, aplica el padding con uno de losWindowInsets
- Si tu app usa vistas y
BottomSheet
,SideSheet
o personalizados contenedores, aplica el relleno conViewCompat.setOnApplyWindowInsetsListener
ParaRecyclerView
, aplica padding con este objeto de escucha y agregaclipToPadding="false"
Qué verifica si tu app debe ofrecer protección personalizada de fondo
Si tu app debe ofrecer protección personalizada en segundo plano para la navegación con 3 botones o
la barra de estado, tu app debe colocar un elemento componible o una vista detrás de la barra del sistema
usando WindowInsets.Type#tappableElement()
para obtener el botón de 3
altura de la barra de navegación o WindowInsets.Type#statusBars
Recursos adicionales de borde a borde
Consulta Vistas de borde a borde y Redacción de borde a borde. para obtener información adicional sobre la aplicación de inserciones.
APIs obsoletas
Las siguientes APIs dejaron de estar disponibles:
R.attr#enforceStatusBarContrast
R.attr#navigationBarColor
R.attr#navigationBarDividerColor
R.attr#statusBarColor
Window#getNavigationBarColor
Window#getNavigationBarDividerColor
Window#getStatusBarColor
Window#isStatusBarContrastEnforced
Window#setDecorFitsSystemWindows
Window#setNavigationBarColor
Window#setNavigationBarDividerColor
Window#setStatusBarColor
Window#setStatusBarContrastEnforced
Configuración estable
Si tu app se orienta a Android 15 (nivel de API 35) o versiones posteriores, Configuration
no
excluye las barras del sistema. Si utilizas el tamaño de la pantalla
Configuration
para el cálculo de diseño, debes reemplazarla por una
alternativas como un ViewGroup
, WindowInsets
o
WindowMetricsCalculator
según tus necesidades.
Configuration
está disponible desde la API 1. Por lo general, se obtienen de
Activity.onConfigurationChanged
. Proporciona información como la densidad de la ventana,
la orientación y los tamaños. Una característica importante de los tamaños de ventana
que muestra Configuration
es que antes excluía las barras del sistema.
Por lo general, el tamaño de la configuración se usa para seleccionar recursos, como
/res/layout-h500dp
, y este sigue siendo un caso de uso válido. Sin embargo, usarlo para
el cálculo de diseño siempre se desaconsejó. Si lo haces, deberías
ahora. Debes reemplazar el uso de Configuration
por algo.
sean más adecuados
según tu caso de uso.
Si lo usas para calcular el diseño, utiliza un ViewGroup
adecuado, como
CoordinatorLayout
o ConstraintLayout
. Si lo usas para determinar la altura
de la barra de navegación del sistema, usa WindowInsets
. Si quieres saber el tamaño actual
de la ventana de tu app, usa computeCurrentWindowMetrics
.
En la siguiente lista, se describen los campos que se verán afectados por este cambio:
- Ya no se muestran los tamaños de
Configuration.screenWidthDp
yscreenHeightDp
excluir las barras del sistema. Configuration.smallestScreenWidthDp
se ve afectado indirectamente por los cambios ascreenWidthDp
yscreenHeightDp
.Configuration.orientation
se ve afectado indirectamente por los cambios enscreenWidthDp
yscreenHeightDp
en dispositivos cercanos al cuadrado.Display.getSize(Point)
se ve afectado indirectamente por los cambios enConfiguration
Esto dejó de estar disponible a partir del nivel de API 30.Display.getMetrics()
ya funciona de esta manera desde el nivel de API 33.
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.
![](https://developer.android.com/static/about/versions/15/images/elegant-text-height-before.png?authuser=5&hl=es)
elegantTextHeight
para las apps que se orientan a Android 14 (nivel de API 34) y versiones anteriores.![](https://developer.android.com/static/about/versions/15/images/elegant-text-height-after.png?authuser=5&hl=es)
elegantTextHeight
para las apps orientadas a Android 15.Cambios de ancho de TextView para formas de letras complejas
En versiones anteriores de Android, algunas fuentes cursivas o idiomas con formas complejas podían dibujar las letras en el área del carácter anterior o siguiente.
En algunos casos, esas letras se recortaban en la posición inicial o final.
A partir de Android 15, un TextView
asigna ancho a fin de generar suficiente espacio para esas letras y permite que las apps soliciten paddings adicionales a la izquierda para evitar el recorte.
Debido a que este cambio afecta la manera en que una TextView
decide el ancho, TextView
asigna más ancho de forma predeterminada si la app se orienta a Android 15 o versiones posteriores. Para habilitar o inhabilitar este comportamiento, llama a la API de setUseBoundsForWidth
en TextView
.
Como agregar padding izquierdo puede causar una desalineación para los diseños existentes, el padding no se agrega de forma predeterminada incluso en el caso de las apps orientadas a Android 15 o versiones posteriores.
Sin embargo, puedes agregar padding adicional para evitar el recorte llamando a setShiftDrawingOffsetForStartOverhang
.
En los siguientes ejemplos, se muestra cómo estos cambios pueden mejorar el diseño del texto de algunos idiomas y fuentes.
![](https://developer.android.com/static/about/versions/15/images/cursive-clipped.png?authuser=5&hl=es)
<TextView android:fontFamily="cursive" android:text="java" />
![](https://developer.android.com/static/about/versions/15/images/cursive-noclipping.png?authuser=5&hl=es)
<TextView android:fontFamily="cursive" android:text="java" android:useBoundsForWidth="true" android:shiftDrawingOffsetForStartOverhang="true" />
![](https://developer.android.com/static/about/versions/15/images/thai-clipped.png?authuser=5&hl=es)
<TextView android:text="คอมพิวเตอร์" />
![](https://developer.android.com/static/about/versions/15/images/thai-noclipping.png?authuser=5&hl=es)
<TextView android:text="คอมพิวเตอร์" android:useBoundsForWidth="true" android:shiftDrawingOffsetForStartOverhang="true" />
Altura de línea predeterminada de la configuración regional para EditText
In previous versions of Android, the text layout stretched the height of the
text to meet the line height of the font that matched the current locale. For
example, if the content was in Japanese, because the line height of the Japanese
font is slightly larger than the one of a Latin font, the height of the text
became slightly larger. However, despite these differences in line heights, the
EditText
element was sized uniformly, regardless
of the locale being used, as illustrated in the following image:
![](https://developer.android.com/static/about/versions/15/images/locale-aware-line-height-before.png?authuser=5&hl=es)
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:
![](https://developer.android.com/static/about/versions/15/images/locale-aware-line-height-after.png?authuser=5&hl=es)
EditText
elements that
can contain text from English (en), Japanese (ja), and Burmese (my). The
height of the EditText
now includes space to accommodate the
default line height for these languages' fonts.If needed, your app can restore the previous behavior by specifying the
useLocalePreferredLineHeightForMinimum
attribute
to false
, and your app can set custom minimum vertical metrics using the
setMinimumFontMetrics
API in Kotlin and Java.
Cámara y contenido multimedia
En Android 15, se realizan los siguientes cambios en el comportamiento de la cámara y el contenido multimedia para las apps orientadas a Android 15 o versiones posteriores.
Restricciones para solicitar foco de audio
Las apps orientadas a Android 15 deben ser la app principal o que ejecuten un servicio en primer plano para solicitar foco de audio. Si una app intenta solicitar el foco cuando no cumple con uno de estos requisitos, la llamada mostrará AUDIOFOCUS_REQUEST_FAILED
.
Puedes obtener más información sobre el foco de audio en Cómo administrar el foco de audio.
Actualización de restricciones que no pertenecen al SDK
Android 15 incluye listas actualizadas de usuarios restringidos que no pertenecen al SDK basadas en la colaboración con desarrolladores de Android y la las pruebas internas. Siempre que sea posible, nos aseguramos de que las alternativas públicas estén disponibles antes de restringir las interfaces que no pertenecen al SDK.
Si tu app no está orientada a Android 15, se implementarán algunos de estos cambios. podría no afectarte de inmediato. Sin embargo, si bien es posible que tu app acceder a algunas interfaces que no pertenecen al SDK según el nivel de API objetivo de tu app, con cualquier método o campo siempre conlleva un alto riesgo de error para tu app.
Si no sabes con certeza si tu app usa interfaces que no pertenecen al SDK, puedes prueba tu app para averiguarlo. Si tu app depende del SDK , debes planificar la migración a alternativas de SDK. Sin embargo, entendemos que algunas apps tienen casos de uso válidos para usar que no pertenecen al SDK. Si no encuentras una alternativa al uso de un SDK interfaz de una función de tu app, deberías solicitar una nueva API pública
Para obtener más información sobre los cambios implementados en esta versión de Android, consulta Actualizaciones a las restricciones de interfaces que no pertenecen al SDK en Android 15. Para obtener más información sobre interfaces que no pertenecen al SDK en general, consulta Restricciones en interfaces que no pertenecen al SDK.