Android 4.2 API

Nivel de API: 17

Android 4.2 (JELLY_BEAN_MR1) es una actualización del lanzamiento de Jelly Bean que ofrece nuevas funciones para los usuarios desarrolladores. En este documento, se ofrece una introducción a las APIs nuevas más distinguidas y útiles para los desarrolladores.

Si eres desarrollador de apps, debes descargar la imagen del sistema Android 4.2 y la plataforma del SDK desde SDK Manager lo antes posible. Si no tienes un dispositivo con Android 4.2 en el cual probar tu app, usa la imagen del sistema de Android 4.2 para probarla en el emulador de Android. Luego, compila las apps con la plataforma Android 4.2 para comenzar a usar las APIs más recientes.

Para optimizar mejor tu app para dispositivos con Android 4.2, debes configurar tu targetSdkVersion en "17", instalarla en una imagen del sistema Android 4.2, probarla y, luego, publicar una actualización con este cambio.

Tú puedes usar APIs en Android 4.2 y, al mismo tiempo, admitir versiones anteriores agregando condiciones a tu código que comprueben el nivel de API del sistema antes de la ejecución APIs no compatibles con tu minSdkVersion. Para obtener más información sobre cómo mantener la retrocompatibilidad, consulta Cómo crear IU retrocompatibles.

Puedes encontrar más información sobre el funcionamiento de los niveles de API en Qué es la API nivel?

Importantes cambios en los comportamientos

Si publicaste anteriormente una app para Android, ten en cuenta lo siguiente: cambios que podrían afectar el comportamiento de tu app:

  • Los proveedores de contenido ya no se exportan de forma predeterminada. Es decir, el valor predeterminado del atributo android:exported ahora es “false". Si es importante que otras apps acceder a tu proveedor de contenido, ahora debes configurar android:exported="true" de forma explícita.

    Este cambio se aplica solo si estableces android:targetSdkVersion o android:minSdkVersion en 17 o una versión posterior. De lo contrario, el valor predeterminado sigue siendo “true" incluso cuando se ejecuta en Android 4.2 y versiones posteriores.

  • En comparación con versiones anteriores de Android, los resultados de la ubicación del usuario pueden ser menos precisos si tu app solicita el permiso ACCESS_COARSE_LOCATION, pero no solicita el permiso ACCESS_FINE_LOCATION.

    Para cumplir con las expectativas de privacidad de los usuarios cuando la app solicita permiso para lo siguiente: ubicación aproximada (y no precisa), el sistema no proporcionará una estimación de la ubicación del usuario que es más preciso que una manzana.

  • Algunos parámetros de configuración del dispositivo definidos por Settings.System ahora son de solo lectura. Si tu app intenta escribir cambios en la configuración definida en Settings.System que se movieron a Settings.Global, ocurrirá lo siguiente: La operación de escritura fallará silenciosamente cuando se ejecute en Android 4.2 y versiones posteriores.

    Incluso si el valor de android:targetSdkVersion y android:minSdkVersion es inferior a 17, tu app no puede modificar la configuración que se trasladó a Settings.Global cuando se ejecuta en Android 4.2 y versiones posteriores.

  • Si tu app usa WebView, Android 4.2 agrega una capa adicional de para que puedas vincular JavaScript a tu Código de Android Si configuraste tu targetSdkVersion en 17 o un valor posterior, ahora debes agregar la anotación @JavascriptInterface a cualquier método que desees que esté disponible para el código de JavaScript (el método también debe ser público). Si no proporcionas la anotación, no se puede acceder al método desde una página web en tu WebView cuando se ejecuta en Android 4.2 o versiones posteriores. Si configuras targetSdkVersion en 16 o menos, no se requiere la anotación, pero te recomendamos que actualices la versión de destino y agregues la anotación para mayor seguridad.

    Más información sobre la vinculación Código JavaScript a código de Android.

Daydream

Daydream es un nuevo modo de protector de pantalla interactivo para dispositivos Android. Se activa automáticamente cuando el dispositivo se inserta en una estación de carga o cuando se deja inactivo mientras está conectado a un cargador (en lugar de apagar la pantalla). Daydream muestra un sueño a la vez, lo que puede ser una pantalla puramente visual y pasiva que se descarta con el tacto o puede ser interactiva y responsiva al kit completo de eventos de entrada. Tus sueños se desarrollan en el proceso de tu app y tienen acceso completo a el kit de herramientas de IU de Android, que incluye vistas, diseños y animaciones, para que sean más flexibles y potentes que los fondos de pantalla animados o los widgets de apps.

Puedes crear un sueño para Daydream implementando una subclase de DreamService. Las APIs de DreamService son diseñados para ser similares a los de Activity. Para especificar la IU de tu sueño, pasa un ID de recurso de diseño o View a setContentView() en cualquier momento después de que tengas una ventana, como desde la devolución de llamada de onAttachedToWindow().

La clase DreamService proporciona otros métodos importantes de devolución de llamada del ciclo de vida además de las APIs de Service básicas, como onDreamingStarted(), onDreamingStopped() y onDetachedFromWindow(). No puedes iniciar una DreamService desde tu la aplicación, el sistema la inicia automáticamente.

Si tu sueño es interactivo, puedes iniciar una actividad desde el sueño para enviar al usuario la IU completa de tu app para obtener más detalles o control. Puedes usar finish() para finalizar el sueño, de modo que el usuario pueda ver el actividad nueva.

Para que tu daydream esté disponible para el sistema, declara tu DreamService con un elemento <service>. en tu archivo de manifiesto. Luego, debes incluir un filtro de intents con la acción "android.service.dreams.DreamService". Por ejemplo:

<service android:name=".MyDream" android:exported="true"
    android:icon="@drawable/dream_icon" android:label="@string/dream_label" >
    <intent-filter>
        <action android:name="android.service.dreams.DreamService" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</service>

Hay otros métodos útiles en DreamService debes tener en cuenta:

  • setInteractive(boolean) controla si El sueño recibe eventos de entrada o sale inmediatamente después de la entrada del usuario. Si el sueño es interactivo, el usuario puede usar los botones Atrás o Inicio para salir del sueño, o bien puedes llamar a finish() para detenerlo.
  • Si quieres una pantalla completamente envolvente, puedes llamar a setFullscreen() para ocultar la barra de estado.
  • Antes de que se inicie el protector de pantalla interactivo, la pantalla se atenúa para indicarle al usuario que el tiempo de espera de inactividad se acerca. Llamar a setScreenBright(true) te permite configurar la pantalla con el brillo habitual.

Para obtener más información, consulta la documentación de DreamService.

Pantallas secundarias

Android ahora permite que tu app muestre contenido único en pantallas adicionales que están conectadas al dispositivo del usuario a través de una conexión con cable o Wi-Fi. Para crear contenido único para una pantalla secundaria, extiende la clase Presentation e implementa la devolución de llamada onCreate(). En un radio de onCreate(), especifica la IU para la pantalla secundaria llamando a setContentView(). Como una extensión de la clase Dialog, la clase Presentation proporciona la región en la que tu app puede mostrar una IU única en la pantalla secundaria.

Para detectar pantallas secundarias en las que puedes mostrar tu Presentation, usa DisplayManager o MediaRouter. APIs Si bien las APIs de DisplayManager te permiten enumerar varias pantallas que pueden estar conectadas a la vez, por lo general, debes usar MediaRouter para acceder rápidamente a la pantalla predeterminada del sistema para las presentaciones.

Para obtener la pantalla predeterminada de tu presentación, llama a MediaRouter.getSelectedRoute() y pásale ROUTE_TYPE_LIVE_VIDEO. Esto muestra un objeto MediaRouter.RouteInfo que describe la ruta seleccionada actualmente por el sistema para las presentaciones de video. Si MediaRouter.RouteInfo no es nulo, llama a getPresentationDisplay() para obtener el Display que representa la pantalla conectada.

Luego, puedes mostrar tu presentación pasando el objeto Display. a un constructor para la clase Presentation. Ahora, tu presentación en la pantalla secundaria.

Para detectar en el tiempo de ejecución cuándo se conectó una pantalla nueva, crea una instancia de MediaRouter.SimpleCallback en la que implementes el método de devolución de llamada onRoutePresentationDisplayChanged(), al que el sistema llamará cuando se conecte una nueva pantalla de presentación. Luego, registra el MediaRouter.SimpleCallback pasándolo a MediaRouter.addCallback() junto con el tipo de ruta ROUTE_TYPE_LIVE_VIDEO. Cuando recibas una llamada a onRoutePresentationDisplayChanged(), simplemente llama a MediaRouter.getSelectedRoute() como se mencionó anteriormente.

Para optimizar aún más la IU en tu Presentation para pantallas secundarias, puedes aplicar un tema diferente especificando el atributo android:presentationTheme en el <style> que aplicarse a tu aplicación o actividad.

Ten en cuenta que las pantallas conectadas al dispositivo del usuario suelen tener un tamaño de pantalla más grande y, probablemente, una densidad de pantalla diferente. Debido a que las características de la pantalla pueden ser diferentes, debes proporcionar recursos optimizados específicamente para esas pantallas más grandes. Si necesitas solicitar recursos adicionales de tu Presentation, llama a getContext().getResources() para obtener el objeto Resources correspondiente a la pantalla. Esto proporciona para conocer los recursos adecuados de tu app la densidad y el tamaño de la pantalla secundaria.

Para obtener más información y algunos ejemplos de código, consulta la documentación de la clase Presentation.

Widgets de la pantalla de bloqueo

Android ahora permite que los usuarios agreguen widgets de apps a la pantalla de bloqueo. Para que el widget de la app esté disponible para usarse en la pantalla de bloqueo, agrega el atributo android:widgetCategory al archivo en formato XML que especifica el AppWidgetProviderInfo. Este atributo admite dos valores: home_screen y keyguard. De forma predeterminada, el atributo se establece en home_screen para que los usuarios puedan agregar el widget de tu app a la pantalla principal. Si quieres que el widget de tu app también esté disponible en la pantalla de bloqueo, agrega el valor keyguard:

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    ...
    android:widgetCategory="keyguard|home_screen">
</appwidget-provider>

También debes especificar un diseño inicial para el widget de tu app en la pantalla de bloqueo con el atributo android:initialKeyguardLayout. Funciona de la misma manera que android:initialLayout, ya que proporciona un diseño que puede aparecer de inmediato hasta que se inicializa el widget de tu app y puede actualizar el diseño.

Para obtener más información sobre la compilación de widgets de apps para la pantalla de bloqueo, incluido el tamaño correcto del widget de la app cuando está en la pantalla de bloqueo, consulta la guía Widgets de apps.

Varios usuarios

Android ahora permite múltiples espacios de usuario en dispositivos que se pueden compartir, como tablets. Cada usuario de un dispositivo tiene su propio conjunto de cuentas, apps, parámetros de configuración del sistema, archivos y cualquier otro dato asociado al usuario.

Como desarrollador, no necesitas hacer nada diferente para que tu app funcione correctamente con varios usuarios en un solo dispositivo. Independientemente de la cantidad de usuarios que puedan existir en un dispositivo, los datos que guarda tu app para un usuario determinado se mantienen separados de los datos que guarda tu app para otros usuarios. El sistema realiza un seguimiento de los datos del usuario que pertenecen al proceso de usuario en el que se ejecuta tu app y le proporciona acceso solo a los datos de ese usuario y no permite el acceso a los datos de otros usuarios.

Guarda datos en un entorno multiusuario

Siempre que tu app guarde las preferencias del usuario, cree una base de datos o escriba un archivo en la en un espacio de almacenamiento interno o externo, solo se podrá acceder a esos datos mientras se ejecuten como ese usuario.

Para asegurarte de que tu app se comporte correctamente en un entorno multiusuario, no consultes tu directorio interno de la app o ubicación de almacenamiento externo por medio de rutas hard-coded y, en su lugar, usar siempre las APIs adecuadas:

Independientemente de cuál de estas APIs uses para guardar datos de un usuario determinado, los datos no se y accesibles mientras se ejecuta como un usuario diferente. Desde el punto de vista de tu app, cada usuario ejecuta en un dispositivo completamente independiente.

Identifica usuarios en un entorno multiusuario

Si tu app desea identificar usuarios únicos, por ejemplo, para recopilar estadísticas o crear otras asociaciones de cuenta, debes seguir las prácticas recomendadas para identificar instalaciones únicas. Si creas un nuevo elemento UUID cuando se inicie tu app para la primera vez, se asegurará de obtener un ID único para realizar el seguimiento de cada usuario, independientemente de la usuarios instalan tu app en un solo dispositivo. También puedes guardar un token local recuperado de tu servidor o usa el ID de registro que proporciona Google Cloud Messaging.

Ten en cuenta que si tu app solicita uno de los identificadores de dispositivos de hardware (como el identificador de MAC de Wi-Fi dirección IP o el número de SERIAL), proporcionarán el mismo valor para cada usuario porque estos identificadores están vinculados al hardware y no al usuario. Sin mencionar los otros problemas que introducen estos identificadores, como se explica en la entrada de blog Cómo identificar las instalaciones de aplicaciones.

Nueva configuración global

Se actualizó la configuración del sistema para admitir varios usuarios con la adición de Settings.Global. Este conjunto de parámetros de configuración es similar a los de Settings.Secure porque son de solo lectura, pero se aplican globalmente en a todos los espacios de usuario del dispositivo.

Varios parámetros de configuración existentes se trasladaron aquí, ya sea de Settings.System o Settings.Secure. Si tu app está realizando cambios en la configuración definida anteriormente en Settings.System (como AIRPLANE_MODE_ON), debes esperar que, si esos parámetros de configuración se movieron a Settings.Global, ya no funcione en un dispositivo con Android 4.2 o versiones posteriores. Puedes seguir leyendo la configuración que se encuentra en Settings.Global, pero debido a que la configuración ya no se considera segura para que las apps cambien, intentar hacerlo fallará silenciosamente y el sistema escribirá una advertencia a el registro del sistema cuando ejecutas tu app en Android 4.2 o versiones posteriores.

Compatibilidad con el diseño de derecha a izquierda

Android ahora ofrece varias APIs que te permiten compilar interfaces de usuario que transformen con elegancia la orientación del diseño para admitir idiomas que usan IU y dirección de lectura de derecha a izquierda (RTL), como el árabe y el hebreo.

Para comenzar a admitir diseños de RTL en tu app, establece el atributo android:supportsRtl en el elemento <application> de tu archivo de manifiesto y configúralo como “true". Cuando habilites esto, el sistema habilitará varias APIs de RTL para mostrar tu app con diseños RTL. Por ejemplo, la barra de acciones mostrará el ícono y el título. a la derecha y los botones de acción a la izquierda, y cualquier diseño que hayas creado con el También se revertirán las clases View proporcionadas por el framework.

Si necesitas optimizar aún más la apariencia de tu app cuando se muestra con un diseño de derecha a izquierda, existen dos niveles básicos de optimización:

  1. Convierte las propiedades de diseño orientadas a la izquierda y la derecha en un diseño orientado al inicio y al final propiedades.

    Por ejemplo, usa android:layout_marginStart. en lugar de android:layout_marginLeft y android:layout_marginEnd en lugar de android:layout_marginRight.

    La clase RelativeLayout también proporciona el diseño correspondiente. atributos para reemplazar las posiciones izquierda/derecha, como android:layout_alignParentStart para reemplazar android:layout_alignParentLeft y android:layout_toStartOf en lugar de android:layout_toLeftOf

  2. O bien, para proporcionar una optimización completa para los diseños RTL, puedes proporcionar instrucciones completamente separadas archivos de diseño que usan el calificador de recursos ldrtl (ldrtl significa diseño-dirección-de-derecha a izquierda}). Por ejemplo, puedes guardar tus archivos de diseño predeterminados en res/layout/ y tus diseños optimizados para la escritura de derecha a izquierda en res/layout-ldrtl/.

    El calificador ldrtl es ideal para los recursos de elementos de diseño, de modo que puedas proporcionar gráficos orientados en la dirección correspondiente a la dirección de lectura.

Hay varias otras APIs disponibles en el framework para admitir diseños RTL, como en la clase View, de modo que puedas implementar los comportamientos adecuados para las vistas personalizadas y en Configuration para consultar la dirección del diseño actual.

Nota: Si usas SQlite y tienes nombres de tablas o columnas que son "solo números", ten cuidado: usar String.format(String, Object...) puede generar errores en los que los números se hayan convertido a sus equivalentes en árabe si tu dispositivo está configurado en la configuración regional del árabe. Debes usar String.format(Locale,String,Object...) para asegurarte de que los números se conserven como ASCII. También usa String.format("%d", int) en lugar de String.valueOf(int) para dar formato a los números.

Fragmentos anidados

Ahora puedes incorporar fragmentos dentro de fragmentos. Esto es útil para una variedad de situaciones en las que deseas colocar componentes de IU dinámicos y reutilizables en un componente de IU que también es dinámico y reutilizable. Por ejemplo, si usas ViewPager para crear fragmentos que se puedan deslizar hacia la izquierda y la derecha, y ocupen la mayor parte del espacio de la pantalla, puedes ahora insertar fragmentos en cada página de fragmento.

Para anidar un fragmento, simplemente llama a getChildFragmentManager() en el Fragment en el que deseas agregar un fragmento. Esto muestra un FragmentManager que puedes usar como lo haces normalmente desde la actividad de nivel superior para crear transacciones de fragmentos. Por ejemplo, aquí tienes código que agrega un fragmento desde adentro una clase Fragment existente:

Kotlin

val videoFragment = VideoPlayerFragment()
childFragmentManager.beginTransaction().apply {
    add(R.id.video_fragment, videoFragment)
    commit()
}

Java

Fragment videoFragment = new VideoPlayerFragment();
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
transaction.add(R.id.video_fragment, videoFragment).commit();

Desde un fragmento anidado, puedes obtener una referencia al fragmento superior llamando a getParentFragment().

La biblioteca de compatibilidad de Android ahora también admite fragmentos anidados, por lo que puedes implementar de fragmentos en Android 1.6 y versiones posteriores.

Nota: No puedes aumentar un diseño en un fragmento cuando ese diseño incluye un <fragment>. Los fragmentos anidados solo se admiten cuando se agregan a un fragmento de forma dinámica.

RenderScript

Se mejoró la funcionalidad de procesamiento de Renderscript con las siguientes características:

Funciones intrínsecas de secuencias de comandos

Puedes usar las funciones intrínsecas de secuencias de comandos integradas de Renderscript para implementar operaciones comunes para ti, como las siguientes:

Para usar un elemento intrínseco de secuencia de comandos, llama al método create() estático de cada elemento intrínseco para crear una instancia de la secuencia de comandos. Luego, llamarás al set() disponible de cada secuencia de comandos intrínseca para configurar las entradas y opciones necesarias. Por último, llama al método forEach() para ejecutar la secuencia de comandos.

Grupos de secuencias de comandos

Los elementos ScriptGroup te permiten encadenar los RenderScript relacionados. de comandos de shell y ejecutarlas con una llamada.

Usa un ScriptGroup.Builder para agregar todas las secuencias de comandos al grupo llamando a addKernel(). Una vez que agregar todas las secuencias de comandos, crear las conexiones entre de comandos llamando a addConnection(). Cuando termines de agregar las conexiones, llama a create() para crear el grupo de secuencias de comandos. Antes de ejecutar el grupo de secuencias de comandos, especifica la entrada Allocation y la secuencia de comandos inicial que se ejecutará con el método setInput(Script.KernelID, Allocation), y proporciona la salida Allocation en la que se escribirá el resultado y la secuencia de comandos final que se ejecutará con setOutput(). Por último, llama execute() para ejecutar el grupo de secuencias de comandos.

Filterscript

Filterscript define restricciones en las APIs de Renderscript existentes que permiten que el código resultante se ejecute en una variedad más amplia de procesadores (CPU, GPU y DSP). Para crear archivos de Filterscript, crea .fs. en lugar de archivos .rs, y especifica #pragma rs_fp_relaxed como Indícale al entorno de ejecución de Renderscript que tus secuencias de comandos no requieren una precisión estricta de punto flotante IEEE 754-2008. Esta precisión permite el vaciado a cero para denormales y el redondeo a cero. Además, tus secuencias de comandos de Filterscript no deben usar tipos integrados de 32 bits y deben especificar una función raíz personalizada con el atributo __attribute__((kernel)), ya que Filterscript no admite punteros, que define la firma predeterminada de la función root().

Nota: Si bien la compatibilidad de Filterscript está en la plataforma, el desarrollador asistencia estará disponible en la versión 21.0.1 de las herramientas del SDK.

Para obtener una vista detallada de todos los cambios de las APIs en Android 4.2, consulta el Informe de diferencias de las APIs.