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 对于以 Android 15 或更高版本为目标平台的应用,在 dataSync 中引入了新的超时行为。此行为也适用于新的 mediaProcessing 前台服务类型

系统允许应用的 dataSync 服务在 24 小时内运行总共 6 小时,之后系统会调用正在运行的服务的 Service.onTimeout(int, int) 方法(在 Android 15 中引入)。此时,服务只有几秒钟的时间来调用 Service.stopSelf()。当调用 Service.onTimeout() 时,该服务不再被视为前台服务。如果服务未调用 Service.stopSelf(),则会发生故障,并显示以下错误消息:“A for 前台服务 (<fgs_type> does not stop in their timeout: <component_name>)”。在 Beta 版 2 中,失败消息显示为 ANR,但在未来的 Beta 版中,此失败消息将抛出自定义异常。

为避免此行为变更出现问题,您可以执行以下一项或多项操作:

  1. 让您的服务实现新的 Service.onTimeout(int, int) 方法。当应用收到回调时,请确保在几秒钟内调用 stopSelf()。(如果您没有立即停止应用,系统会生成故障。)
  2. 确保应用的 dataSync 服务在任何 24 小时内的运行时间总共不超过 6 小时(除非用户与应用互动,请重置计时器)。
  3. 仅因直接用户互动而启动 dataSync 前台服务;由于您的应用在服务启动时正处于前台,因此在它进入后台后,您的服务有整整六个小时的时间。
  4. 请使用替代 API,而不要使用 dataSync 前台服务。

如果应用的 dataSync 前台服务在过去 24 小时内运行了 6 小时,那么除非用户已将您的应用带到前台(这会重置计时器),否则您无法启动其他 dataSync 前台服务。如果您尝试启动另一个 dataSync 前台服务,系统会抛出 ForegroundServiceStartNotAllowedException,并显示“时间限制已用完前台服务类型 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

以前,如果应用拥有 SYSTEM_ALERT_WINDOW 权限,那么即使该应用当前在后台运行,它也可以启动前台服务(如不受后台启动限制的豁免中所述)。

如果应用以 Android 15 为目标平台,此豁免范围现在会更严格。该应用现在需要具有 SYSTEM_ALERT_WINDOW 权限,并且具有可见的叠加窗口。也就是说,在您启动前台服务之前,应用需要先启动 TYPE_APPLICATION_OVERLAY 窗口,并且该窗口必须处于可见状态。

如果您的应用尝试在不满足这些新要求的情况下从后台启动前台服务(并且没有其他某些豁免),系统会抛出 ForegroundServiceStartNotAllowedException

如果您的应用声明 SYSTEM_ALERT_WINDOW 权限并从后台启动前台服务,则可能会受到此项变更的影响。如果您的应用收到 ForegroundServiceStartNotAllowedException,请检查应用的操作顺序,并确保应用在尝试从后台启动前台服务之前已具备有效的叠加窗口。您可以通过调用 View.getWindowVisibility() 检查叠加层窗口当前是否可见,也可以替换 View.onWindowVisibilityChanged(),以便在可见性发生变化时收到通知。

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 tipo de componente de Arrays.asList(...).toArray(): Cuando se usa Arrays.asList(...).toArray(), el tipo de componente del array resultante ahora es un Object, no el tipo de los elementos del array subyacente. Por lo tanto, el siguiente código arroja una ClassCastException:

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

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

    String[] elements = Arrays.asList("two", "one").toArray(new String[0]);
    
  • Cambios en el manejo del código de idioma: Cuando 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 通过添加变更来防止恶意后台应用将其他应用带到前台、提升其权限和滥用用户互动,从而保护用户免受恶意应用的侵害,并使用户能够更好地控制其设备。从 Android 10(API 级别 29)开始,后台 activity 启动已受到限制。

阻止与堆栈中顶部 UID 不匹配的应用启动 activity

恶意应用可以在同一任务内启动另一个应用的 activity,然后叠加在上面,制造出作为该应用的错觉。这种“任务劫持”攻击绕过了当前的后台启动限制,因为它都发生在同一可见任务内。为了降低这种风险,Android 15 添加了一个标志,用于阻止与堆栈上的顶级 UID 不匹配的应用启动 activity。如需选择启用应用的所有 activity,请更新应用的 AndroidManifest.xml 文件中的 allowCrossUidActivitySwitchFromBelow 属性:

<application android:allowCrossUidActivitySwitchFromBelow="false" >

如果满足以下所有条件,则新的安全措施就会生效:

  • 执行启动的应用以 Android 15 为目标平台。
  • 任务堆栈顶部的应用以 Android 15 为目标平台。
  • 所有可见的活动均已启用新版保护措施

如果启用了安全措施,应用如果完成自己的任务,可能会返回主屏幕,而不是返回上一个可见的应用。

其他变更

除了 UID 匹配的限制之外,还包含以下其他更改:

  • PendingIntent 创建者更改为默认阻止后台 activity 启动。这有助于防止应用意外创建可能会被恶意操作者滥用的 PendingIntent
  • 请勿将应用置于前台,除非 PendingIntent 发送者允许该应用。此变更旨在防止恶意应用滥用在后台启动 activity 的功能。默认情况下,不允许应用将任务堆栈置于前台,除非创建者允许后台 activity 启动特权或发送者具有后台 activity 启动特权。
  • 控制任务堆栈的顶层 activity 完成其任务的方式。如果顶层 activity 完成某项任务,Android 会返回到上次处于活动状态的任务。此外,如果非顶层 activity 完成其任务,Android 将返回主屏幕;它不会阻止此非顶部 activity 的完成。
  • 防止将其他应用中的任意 activity 启动到您自己的任务中。这项变更会通过创建看似来自其他应用的活动,防止恶意应用向用户进行钓鱼式攻击。
  • 阻止系统考虑将不可见窗口用于后台 activity 启动。这有助于防止恶意应用滥用后台 activity 启动来向用户显示不受欢迎或恶意内容。

Intents más seguros

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

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

Kotlin


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

Java


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

IU del sistema y experiencia del usuario

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

Cambios en la inserción de ventana

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 están orientadas a esta 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 afectan las siguientes áreas de la IU:

  • Barra de navegación del controlador de gestos
    • Es transparente de forma predeterminada.
    • El desplazamiento inferior está inhabilitado, por lo que el contenido se dibuja 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 coincidir 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 con 3 botones.
    • setNavigationBarContrastEnforced y R.attr#navigationBarContrastEnforced son verdaderos de forma predeterminada, lo que agrega un 80% de fondo opaco 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 las 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.
  • Recorte de pantalla
    • El 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 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 barra superior de la app de Material 2, los botones de acción flotante 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.
Qué debes 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 en la mayoría de los casos, excepto en las siguientes situaciones. Sin embargo, incluso si crees que no te verás afectado, te recomendamos que pruebes la app.

  • Tienes una ventana no flotante, como un 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 la pantalla de presentación principal a 1.2.0-alpha01 o una versión posterior, o bien configurar window.attributes.layoutInDisplayCutoutMode = WindowManager.LayoutInDisplayCutoutMode.always.
  • Es posible que haya pantallas con poco tráfico y una IU oculta. Verifica que estas pantallas menos visitadas no tengan una IU oculta. Estas son las pantallas con menor tráfico:
    • Pantallas de integración o acceso
    • Páginas de configuración
Qué debes verificar si tu app aún no es de borde a borde

Si tu app aún no es de borde a borde, es muy probable que este te afecte. Además de las situaciones de 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 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 versiones posteriores, usa el parámetro windowInsets para aplicar las inserciones manualmente para BottomAppBar, TopAppBar, BottomNavigation y NavigationRail. Del mismo modo, 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.
  • En el caso de los elementos componibles personalizados, aplica las inserciones de forma manual como padding. Si tu contenido está dentro de un Scaffold, puedes consumir las inserciones con los valores de padding de Scaffold. De lo contrario, aplica padding mediante uno de los WindowInsets.
  • Si la app usa vistas y 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".
Qué debes comprobar si tu app debe ofrecer protección en segundo plano personalizada

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

Recursos adicionales de borde a borde

Consulta las guías de vistas de borde a borde y vista de borde a borde para obtener consideraciones adicionales sobre la aplicación de inserciones.

APIs obsoletas

Las siguientes APIs dejaron de estar disponibles:

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 ViewGroup, WindowInsets o WindowMetricsCalculator, 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

在以前的 Android 版本中,一些采用复杂形状的草体字体或语言可能会在上一个或下一个字符区域中绘制字母。在某些情况下,此类字母会在开始或结束位置被截断。从 Android 15 开始,TextView 会分配宽度来为此类字母绘制足够的空间,并允许应用请求左侧添加额外的内边距以防止被裁剪。

由于此变更会影响 TextView 确定宽度的方式,因此如果应用以 Android 15 或更高版本为目标平台,TextView 会默认分配更多宽度。您可以通过对 TextView 调用 setUseBoundsForWidth API 来启用或停用此行为。

由于添加左侧内边距可能会导致现有布局未对齐,因此默认情况下,系统不会添加内边距,即使对于以 Android 15 或更高版本为目标平台的应用也是如此。不过,您可以通过调用 setShiftDrawingOffsetForStartOverhang 添加额外的内边距以防止裁剪。

以下示例展示了这些更改如何改进某些字体和语言的文本布局。

以手写体字体显示的英语文本的标准布局。部分字母会被截断。相应的 XML 如下:

<TextView
    android:fontFamily="cursive"
    android:text="java" />
包含额外宽度和内边距的相同英文文本的布局。相应的 XML 如下:

<TextView
    android:fontFamily="cursive"
    android:text="java"
    android:useBoundsForWidth="true"
    android:shiftDrawingOffsetForStartOverhang="true" />
泰语文字的标准版式。部分字母被截断。 相应的 XML 如下:

<TextView
    android:text="คอมพิวเตอร์" />
相同泰语文本的布局,但有额外的宽度和内边距。相应的 XML 如下:

<TextView
    android:text="คอมพิวเตอร์"
    android:useBoundsForWidth="true"
    android:shiftDrawingOffsetForStartOverhang="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.