Nivel de API: 18
Android 4.3 (JELLY_BEAN_MR2
)
es una actualización del lanzamiento de Jelly Bean que ofrece nuevas funciones a los usuarios
desarrolladores. En este documento, se brinda una introducción a los conceptos
APIs nuevas.
Como desarrollador de apps, debes descargar la imagen del sistema de Android 4.3 y la plataforma de SDK desde SDK Manager, como lo antes posible. Si no tienes un dispositivo con Android 4.3 en el cual prueba tu app, usa el sistema Android 4.3 para probar la app en el emulador de Android. Luego, compila tus apps con la plataforma Android 4.3 para comenzar a usar la versión las APIs más recientes.
Actualiza el nivel de tu API de destino
Para optimizar mejor tu app para dispositivos con Android 4.3, haz lo siguiente:
Debes configurar tu targetSdkVersion
como
"18"
, instálala en una imagen del sistema Android 4.3
probarlo y, luego, publicar
una actualización con este cambio.
Puedes usar APIs en Android 4.3 y, al mismo tiempo, admitir versiones anteriores. Para ello, agrega
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 Compatibilidad con diferentes
Versiones de la Plataforma.
En la biblioteca de compatibilidad de Android, también hay disponibles varias APIs que permiten implementar en versiones anteriores de la plataforma.
Para obtener más información sobre cómo funcionan los niveles de API, lee Qué es la API nivel?
Importantes cambios en los comportamientos
Si publicaste anteriormente una app para Android, ten en cuenta que podría verse afectadas por cambios en Android 4.3.
Si tu app usa intents implícitos...
Es posible que tu app no funcione correctamente en un entorno de perfil restringido.
Es posible que los usuarios en un entorno de perfil restringido no puedan
tener disponibles todas las apps estándar de Android. Por ejemplo, un perfil restringido puede tener la
el navegador web y la app de cámara están inhabilitados. Tu app no debe hacer suposiciones sobre cuáles son
disponible, porque si llamas a startActivity()
sin
Verifica si una app está disponible para controlar Intent
tu app podría fallar en un perfil restringido.
Cuando se usa un intent implícito, siempre debes verificar que una app esté disponible para controlar el intent llamando a resolveActivity()
o queryIntentActivities()
. Por ejemplo:
Kotlin
val intent = Intent(Intent.ACTION_SEND) ... if (intent.resolveActivity(packageManager) != null) { startActivity(intent) } else { Toast.makeText(context, R.string.app_not_available, Toast.LENGTH_LONG).show() }
Java
Intent intent = new Intent(Intent.ACTION_SEND); ... if (intent.resolveActivity(getPackageManager()) != null) { startActivity(intent); } else { Toast.makeText(context, R.string.app_not_available, Toast.LENGTH_LONG).show(); }
Si tu app depende de cuentas...
Es posible que tu app no funcione correctamente en un entorno de perfil restringido.
Los usuarios que pertenezcan a un entorno de perfil restringido no tienen acceso a las cuentas de usuario de forma predeterminada.
Si tu app depende de una Account
, es posible que falle o se comporte.
inesperadamente cuando se utiliza en un perfil restringido.
Si no quieres que los perfiles restringidos usen tu app por completo
La app depende de información sensible de la cuenta, especifica el atributo android:requiredAccountType
en el <application>
de tu manifiesto
.
Si quieres permitir que los perfiles restringidos sigan usando tu app aunque no puedan hacerlo crear sus propias cuentas, puedes inhabilitar las funciones de la app que requieren una cuenta o permitir que los perfiles restringidos accedan a las cuentas creadas por el usuario principal. Para ver más consulta la sección a continuación, sobre Cómo brindar compatibilidad con cuentas en un perfil restringido.
Si tu app usa VideoView...
Es posible que el video se vea más pequeño en Android 4.3.
En versiones anteriores de Android, el widget VideoView
era incorrecto.
calculó que el valor de "wrap_content"
para layout_height
y layout_width
sea igual que "match_parent"
. Por lo tanto, si bien el uso de "wrap_content"
para el alto o el ancho puede haber proporcionado previamente el diseño de video deseado,
Si lo haces, podrías producir un video mucho más pequeño en Android 4.3 y versiones posteriores. Para solucionar el problema, reemplaza
"wrap_content"
con "match_parent"
y verifica que el video se muestre como se espera en
Android 4.3 y versiones anteriores.
Perfiles restringidos
En las tablets Android, los usuarios ahora pueden crear perfiles restringidos en función del usuario principal. Cuando los usuarios crean un perfil restringido, pueden habilitar restricciones, como de qué aplicaciones disponibles para el perfil. Un nuevo conjunto de API en Android 4.3 también te permite compilar configuración de restricciones para las apps que desarrollas. Por ejemplo, con las APIs nuevas, puedes les permiten a los usuarios controlar qué tipo de contenido está disponible en tu app cuando se ejecuta en un de perfil restringido.
La interfaz de usuario del sistema
Configuración de la app. Para que el usuario vea la configuración de restricciones de tu app,
Debes declarar las restricciones que proporciona tu app creando un BroadcastReceiver
que reciba el intent ACTION_GET_RESTRICTION_ENTRIES
. El sistema invoca este intent para consultar
todas las apps para conocer las restricciones disponibles y, luego, compila la IU para permitir que el usuario principal
administrar las restricciones de cada perfil restringido
En el método onReceive()
de
tu BroadcastReceiver
, debes crear un RestrictionEntry
para cada restricción que proporcione tu app. Cada RestrictionEntry
define un título de restricción, una descripción y uno de los
los siguientes tipos de datos:
TYPE_BOOLEAN
para una restricción que se verdadero o falso.TYPE_CHOICE
para una restricción que tiene opciones múltiples que son mutuamente excluyentes (opciones de botones de selección).TYPE_MULTI_SELECT
para una restricción que Tiene varias opciones que no son mutuamente excluyentes (opciones de casilla de verificación).
Luego, coloca todos los objetos RestrictionEntry
en un ArrayList
y lo colocas en el resultado del receptor de emisión como el valor del
EXTRA_RESTRICTIONS_LIST
adicionales.
El sistema crea la IU para las restricciones de tu app en la app de Configuración y guarda cada una
restricción con la clave única que proporcionaste para cada RestrictionEntry
. Cuando el usuario abra tu app, podrás consultar las restricciones actuales
llamando a getApplicationRestrictions()
.
Esto muestra un Bundle
que contiene los pares clave-valor para cada restricción.
que definiste con los objetos RestrictionEntry
.
Si deseas proporcionar restricciones más específicas que no se puedan controlar con valores booleanos,
opciones y valores de opción múltiple, puedes crear una actividad en la que el usuario especifique
restricciones y permitir que los usuarios abran esa actividad desde la configuración de restricciones. En tu
receptor de emisión, incluye el EXTRA_RESTRICTIONS_INTENT
adicional
en el resultado Bundle
. Este extra debe especificar un Intent
que indica la clase Activity
que se iniciará (usa el
putParcelable()
para pasar EXTRA_RESTRICTIONS_INTENT
con el intent).
Cuando el usuario principal ingresa a tu actividad para establecer restricciones personalizadas, tu
la actividad debe devolver un resultado que contenga los valores de restricción en un extra mediante
la clave EXTRA_RESTRICTIONS_LIST
o EXTRA_RESTRICTIONS_BUNDLE
, según si especificas
RestrictionEntry
o pares clave-valor, respectivamente.
Cuentas compatibles con un perfil restringido
Todas las cuentas que se agreguen al usuario principal estarán disponibles para un perfil restringido, pero
no se puede acceder a las cuentas desde las APIs de AccountManager
de forma predeterminada.
Si intentas agregar una cuenta con AccountManager
mientras te encuentras en una zona restringida
obtendrás un resultado de error. Debido a estas restricciones, tienes lo siguiente:
tres opciones:
Para acceder a una cuenta desde un perfil restringido, debes agregar el atributo android:restrictedAccountType
a la etiqueta <application>:
<application ... android:restrictedAccountType="com.example.account.type" >
Precaución: Habilitar este atributo proporciona la acceso de la app a las cuentas del usuario principal desde perfiles restringidos. Así que debes permitir solo si la información que muestra la aplicación no revela información de identificación personal (PII) que se considera sensible. La configuración del sistema informará al usuario usuario que tu app otorga perfiles restringidos a sus cuentas, por lo que debe quedar claro que el acceso a la cuenta es importante para la funcionalidad de tu app. Si es posible, también debes Proporcionar controles de restricción adecuados para el usuario principal que definan el nivel de acceso a la cuenta está permitido en tu app.
Si quieres usar cuentas, pero en realidad no las necesitas para la cuenta principal de tu app
puedes comprobar la disponibilidad de la cuenta e inhabilitar funciones cuando no estén disponibles.
Primero debes comprobar si hay una cuenta existente disponible. Si no es así, consulta si
Puedes crear una cuenta nueva si llamas a getUserRestrictions()
y verificas el DISALLOW_MODIFY_ACCOUNTS
adicional en el resultado. Si es true
,
debes inhabilitar cualquier funcionalidad de la aplicación que requiera acceso a las cuentas.
Por ejemplo:
Kotlin
val um = context.getSystemService(Context.USER_SERVICE) as UserManager val restrictions: Bundle = um.userRestrictions if (restrictions.getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS, false)) { // cannot add accounts, disable some functionality }
Java
UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE); Bundle restrictions = um.getUserRestrictions(); if (restrictions.getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS, false)) { // cannot add accounts, disable some functionality }
Nota: En este caso, no debes declarar cualquier atributo nuevo en tu archivo de manifiesto.
Si es importante que la app no esté disponible para perfiles restringidos
Tu app depende de información personal sensible de una cuenta (y debido a que los perfiles restringidos
actualmente no se pueden agregar cuentas nuevas), agregue
El atributo android:requiredAccountType
en la etiqueta <application>:
<application ... android:requiredAccountType="com.example.account.type" >
Por ejemplo, la app de Gmail usa este atributo para inhabilitarse en los perfiles restringidos, porque el correo electrónico personal del propietario no debería estar disponible para perfiles restringidos.
Redes inalámbricas y conectividad
Bluetooth de bajo consumo (listo para dispositivos inteligentes)
Android ahora admite Bluetooth de bajo consumo (LE) con las nuevas APIs en android.bluetooth
.
Con las nuevas API, podrás crear apps para Android que se comuniquen con Bluetooth de bajo consumo
periféricos, como monitores de frecuencia cardíaca y podómetros.
Debido a que Bluetooth LE es una función de hardware que no está disponible en todos los
En los dispositivos con Android, debes declarar en tu archivo de manifiesto un <uses-feature>
elemento para "android.hardware.bluetooth_le"
:
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />
Si ya conoces las APIs de Bluetooth clásico de Android, puedes observar que
Las APIs de Bluetooth LE tienen algunas diferencias. Lo más importante es que ahora hay una clase BluetoothManager
que debes usar para algunas operaciones de alto nivel.
como adquirir un BluetoothAdapter
, obtener una lista de
dispositivos y comprobar su estado. Por ejemplo, así es como deberías obtener la
BluetoothAdapter
:
Kotlin
val bluetoothManager = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager bluetoothAdapter = bluetoothManager.adapter
Java
final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); bluetoothAdapter = bluetoothManager.getAdapter();
Para descubrir periféricos Bluetooth LE, llama a startLeScan()
en el BluetoothAdapter
y pásale una implementación
de la interfaz BluetoothAdapter.LeScanCallback
. Cuando se active el
detecta un periférico Bluetooth LE, tu implementación de BluetoothAdapter.LeScanCallback
recibe una llamada al
onLeScan()
. Esta
proporciona un objeto BluetoothDevice
que representa el
el dispositivo detectado, el valor de RSSI del dispositivo y un array de bytes que contiene el valor
anuncio.
Si deseas buscar solo tipos específicos de periféricos, puedes llamar a startLeScan()
e incluir un array de objetos UUID
que especifiquen los servicios GATT que admite tu app.
Nota: Solo puedes buscar dispositivos Bluetooth LE o buscar dispositivos Bluetooth clásicos con APIs anteriores No se pueden escanear tanto la versión LE como la clásica dispositivos Bluetooth a la vez.
Para conectarte a un periférico Bluetooth LE, llama a connectGatt()
en el
BluetoothDevice
y le pasa una implementación de
BluetoothGattCallback
Tu implementación de BluetoothGattCallback
recibe devoluciones de llamada relacionadas con la conectividad.
el estado con el dispositivo y otros eventos. Es durante el onConnectionStateChange()
que puedes comenzar a comunicarte con el dispositivo si el método pasa STATE_CONNECTED
como el estado nuevo.
Para acceder a las funciones de Bluetooth en un dispositivo, también es necesario que tu app solicite ciertos Permisos del usuario de Bluetooth Para obtener más información, consulta la guía de la API de Bluetooth de bajo consumo.
Modo de solo búsqueda de Wi-Fi
Al intentar identificar la ubicación del usuario, Android puede usar Wi-Fi para ayudar a determinar la ubicación escaneando los puntos de acceso cercanos. Sin embargo, los usuarios suelen mantener el Wi-Fi desactivado para ahorran batería, lo que genera datos de ubicación menos precisos. Android ahora incluye modo de solo búsqueda que permite que el Wi-Fi del dispositivo busque puntos de acceso para ayudar a obtener la ubicación sin conectarse a un punto de acceso, lo que reduce en gran medida el uso de la batería.
Si quieres obtener la ubicación del usuario, pero la conexión Wi-Fi está desactivada actualmente, puedes solicitar la ubicación
usuario para habilitar el modo de solo búsqueda de Wi-Fi llamando a startActivity()
con la acción ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE
.
Configuración de Wi-Fi
Las nuevas APIs de WifiEnterpriseConfig
permiten que los servicios orientados a empresas puedan
automatizar la configuración de Wi-Fi para dispositivos administrados.
Respuesta rápida para llamadas entrantes
A partir de Android 4.0, se incluye una función llamada "Respuesta rápida" permite que los usuarios respondan a los mensajes
llamadas con un mensaje de texto inmediato sin necesidad de atender la llamada o desbloquear el dispositivo.
Hasta ahora, la app de mensajería predeterminada siempre se encargaba de estos mensajes rápidos. Cualquier app
puede declarar su capacidad de manejar estos mensajes creando un Service
con un filtro de intents para ACTION_RESPOND_VIA_MESSAGE
.
Cuando el usuario responde una llamada entrante con una respuesta rápida, la app de Teléfono envía
el intent ACTION_RESPOND_VIA_MESSAGE
con un URI
que describen el destinatario (el emisor) y el EXTRA_TEXT
adicional
con el mensaje que el usuario desea enviar. Cuando tu servicio recibe el intent, debe entregar
el mensaje y se detiene de inmediato (tu app no debería mostrar una actividad).
Para recibir este intent, debes declarar el permiso SEND_RESPOND_VIA_MESSAGE
.
Multimedia
Mejoras de MediaExtractor y MediaCodec
Android ahora te permite escribir tu propio diseño de Dynamic Adaptive
a través de reproductores HTTP (DASH) de acuerdo con el estándar ISO/IEC 23009-1,
con las APIs existentes en MediaCodec
y MediaExtractor
. El framework subyacente a estas APIs se actualizó para admitir
Análisis de archivos MP4 fragmentados, pero tu app sigue siendo responsable de analizar los metadatos MPD
y pasa las transmisiones individuales a MediaExtractor
.
Si quieres usar DASH con contenido encriptado, ten en cuenta que el método getSampleCryptoInfo()
muestra los metadatos MediaCodec.CryptoInfo
que describen la estructura de cada contenido multimedia encriptado
muestra. Además, se agregó el método getPsshInfo()
MediaExtractor
para que puedas acceder a los metadatos PSSH de los medios DASH.
Este método muestra un mapa de objetos UUID
a bytes, con el
UUID
, que especifica el esquema criptográfico, y los bytes que corresponden a los datos específicos
a ese esquema.
DRM de contenido multimedia
La nueva clase MediaDrm
proporciona una solución modular para los derechos digitales.
administración de contenido multimedia (DRM) con el contenido multimedia. Para ello, separa las cuestiones de DRM de la reproducción de contenido multimedia. Para
Esta separación de API te permite reproducir contenido encriptado con Widevine sin tener
para usar el formato Widevine. Esta solución DRM también admite la encriptación común DASH, por lo que
puedes usar diversos esquemas DRM con tu contenido de transmisión.
Puedes usar MediaDrm
para obtener mensajes de solicitud de clave opacos y procesos
mensajes de clave-respuesta del servidor para la adquisición y el aprovisionamiento de licencias. Tu app es
responsable de manejar la comunicación de red con los servidores; La clase MediaDrm
solo proporciona la capacidad de generar y procesar los mensajes.
Las APIs de MediaDrm
están diseñadas para usarse junto con el
Las APIs de MediaCodec
que se introdujeron en Android 4.1 (nivel de API 16)
que incluye MediaCodec
para codificar y decodificar tu contenido, MediaCrypto
para manejar contenido encriptado y MediaExtractor
para extraer y demuxar tu contenido.
Primero debes construir MediaExtractor
y
MediaCodec
. Luego, puedes acceder al esquema de DRM de
UUID
, por lo general, a partir de los metadatos del contenido, y usarla para construir un
de un objeto MediaDrm
con su constructor.
Codificación de video desde una superficie
Android 4.1 (nivel de API 16) agregó la clase MediaCodec
para aplicaciones
a codificar y decodificar contenido multimedia. Al codificar videos, Android 4.1 requería que proporcionaras
el contenido multimedia con un array ByteBuffer
, pero Android 4.3 ahora te permite usar un Surface
como entrada para un codificador. Por ejemplo, esto te permite codificar
a partir de un archivo de video existente o con fotogramas generados a partir de OpenGL ES.
Si quieres usar un objeto Surface
como entrada para el codificador, primero llama a configure()
para tu MediaCodec
.
Luego, llama a createInputSurface()
para recibir el Surface
sobre el cual puedes transmitir tu contenido multimedia.
Por ejemplo, puedes usar el Surface
determinado como ventana para una ventana de OpenGL.
el contexto pasándolo a eglCreateWindowSurface()
. Luego, mientras renderizas la superficie, llama a eglSwapBuffers()
para pasar el marco a MediaCodec
.
Para comenzar a codificar, llama a start()
en MediaCodec
. Cuando termines, llama a signalEndOfInputStream()
para finalizar la codificación y llama a release()
en el
Surface
Combinación de contenido multimedia
La nueva clase MediaMuxer
permite la multiplexación entre una transmisión de audio
y una transmisión de video por Internet. Estas APIs funcionan como una contraparte de MediaExtractor
.
agregada en Android 4.2 para la demultiplexación (demuxing) del contenido multimedia.
Los formatos de salida compatibles se definen en MediaMuxer.OutputFormat
. Actualmente,
MP4 es el único formato de salida que se admite y MediaMuxer
es compatible actualmente.
solo una reproducción de audio o una transmisión de video a la vez.
MediaMuxer
está diseñado principalmente para funcionar con MediaCodec
.
para realizar el procesamiento del video con MediaCodec
y, luego, guardar el
salida a un archivo MP4 a través de MediaMuxer
. También puedes usar MediaMuxer
junto con MediaExtractor
para realizar
editar contenido multimedia sin codificar ni decodificar.
Progreso de la reproducción y arrastre de RemoteControlClient
En Android 4.0 (nivel de API 14), se agregó RemoteControlClient
a
Habilita los controles de reproducción multimedia desde clientes de control remoto, como los controles disponibles en la
pantalla de bloqueo. Android 4.3 ahora permite que esos controles muestren la reproducción
y los controles para arrastrar la reproducción. Si habilitaste el control remoto para tu
app de música con las APIs de RemoteControlClient
, puedes permitir la reproducción
depurar mediante la implementación de dos interfaces nuevas.
Primero, debes habilitar la marca FLAG_KEY_MEDIA_POSITION_UPDATE
pasándola a
setTransportControlsFlags()
Luego, implementa las siguientes dos interfaces nuevas:
RemoteControlClient.OnGetPlaybackPositionListener
- Esto incluye la devolución de llamada
onGetPlaybackPosition()
, que solicita la posición actual. de tu contenido multimedia cuando el control remoto necesita actualizar el progreso en su IU. RemoteControlClient.OnPlaybackPositionUpdateListener
- Esto incluye la devolución de llamada
onPlaybackPositionUpdate()
, que le indica a tu app el nuevo código de tiempo de tu contenido multimedia cuando el usuario arrastra la reproducción con el IU de control remoto.Una vez que actualices la reproducción con la nueva posición, llama a
setPlaybackState()
para indicar nuevo estado, posición y velocidad de reproducción.
Con estas interfaces definidas, puedes establecerlas para tu RemoteControlClient
llamando a setOnGetPlaybackPositionListener()
y
setPlaybackPositionUpdateListener()
, respectivamente.
Gráficos
Compatibilidad con OpenGL ES 3.0
Android 4.3 agrega interfaces Java y compatibilidad nativa con OpenGL ES 3.0. Nueva funcionalidad clave que se proporciona en OpenGL ES 3.0 incluye lo siguiente:
- Aceleración de efectos visuales avanzados
- Compresión de texturas ETC2/EAC de alta calidad como función estándar
- Una nueva versión del lenguaje de sombreado GLSL ES compatible con números enteros y punto flotante de 32 bits.
- Renderización avanzada de texturas
- Estandarización más amplia del tamaño de las texturas y los formatos de búfer de renderización
La interfaz Java para OpenGL ES 3.0 en Android se proporciona con GLES30
.
Al usar OpenGL ES 3.0, asegúrate de declararlo en tu archivo de manifiesto con el
<uses-feature>
y el atributo android:glEsVersion
. Por ejemplo:
<manifest> <uses-feature android:glEsVersion="0x00030000" /> ... </manifest>
Recuerda especificar el contexto de OpenGL ES llamando a setEGLContextClientVersion()
,
y pasa 3
como la versión.
Para obtener más información sobre el uso de OpenGL ES, incluido cómo comprobar la compatibilidad del dispositivo Para ver la versión de OpenGL ES durante el tiempo de ejecución, consulta la guía de la API de OpenGL ES.
Asignación de mip para elementos de diseño
Usar un mipmap como fuente de tu mapa de bits o elemento de diseño es una manera sencilla de proporcionar un y varias escalas de imagen, lo que puede ser muy útil si esperas que tu para escalar durante una animación.
Android 4.2 (nivel de API 17) agregó compatibilidad con mipmaps en la Bitmap
Android cambia las imágenes mip en tu Bitmap
cuando
proporcionaron una fuente mipmap y habilitaron setHasMipMap()
. Ahora, en Android 4.3, también puedes habilitar mipmaps para un objeto BitmapDrawable
proporcionando un recurso de mipmap y
Configurando el atributo android:mipMap
en un archivo de recursos de mapas de bits o llamando a hasMipMap()
.
Interfaz de usuario
Superposición de objetos View
La nueva clase ViewOverlay
proporciona una capa transparente sobre
un elemento View
en el que puedes agregar contenido visual y que no afecta
la jerarquía de diseño. Puedes obtener un ViewOverlay
para cualquier View
llamando a getOverlay()
. La superposición
siempre tenga el mismo tamaño y posición que su vista de host (la vista desde la que se creó),
lo que permite agregar contenido que aparece frente a la vista del host, pero que no se puede extender
los límites de esa vista del host.
El uso de un objeto ViewOverlay
es particularmente útil cuando quieres crear
animaciones, como deslizar una vista fuera de su contenedor o mover elementos por la pantalla
sin afectar la jerarquía de vistas. Sin embargo, debido a que el área utilizable de una superposición no
restringida a la misma área que su vista de host, si deseas animar una vista que se mueva hacia afuera
en su posición en el diseño, debes usar una superposición de una vista superior que tenga los elementos
límites de diseño.
Cuando creas una superposición para una vista de widget, como un Button
,
puedes agregar objetos Drawable
a la superposición llamando
add(Drawable)
Si llamas a getOverlay()
para una vista de diseño, como RelativeLayout
,
el objeto que se muestra es una ViewGroupOverlay
. El
La clase ViewGroupOverlay
es una subclase
de ViewOverlay
que también te permite agregar View
llamando a add(View)
.
Nota: Todos los elementos de diseño y las vistas que agregas a una superposición son solo visuales. No pueden recibir eventos de enfoque ni de entrada.
Por ejemplo, el siguiente código anima una vista que se desliza hacia la derecha colocando la vista en la superposición de la vista principal y, a continuación, realiza una animación de traducción en esa vista:
Kotlin
val view: View? = findViewById(R.id.view_to_remove) val container: ViewGroup? = view?.parent as ViewGroup container?.apply { overlay.add(view) ObjectAnimator.ofFloat(view, "translationX", right.toFloat()) .start() }
Java
View view = findViewById(R.id.view_to_remove); ViewGroup container = (ViewGroup) view.getParent(); container.getOverlay().add(view); ObjectAnimator anim = ObjectAnimator.ofFloat(view, "translationX", container.getRight()); anim.start();
Diseño de límites ópticos
Para las vistas que contienen imágenes de fondo nine-patch, ahora puedes especificar estar alineadas con las vistas vecinas según el modelo “óptico” límites de la imagen de fondo en lugar que el “clip” límites de la vista.
Por ejemplo, las figuras 1 y 2 muestran el mismo diseño, pero la versión de la figura 1 es con límites de recorte (el comportamiento predeterminado), mientras que la figura 2 usa límites ópticos. Debido a que el las imágenes de nine-patch usadas para el botón y el marco de fotos incluyen relleno alrededor de los bordes, no parecen alinearse entre sí o con el texto cuando se utilizan límites de recorte.
Nota: La captura de pantalla de las figuras 1 y 2 tiene el mensaje "Mostrar límites de diseño" parámetro de configuración para desarrolladores habilitado. Para cada vista, las líneas rojas indican la capa límites, las líneas azules indican los límites de recorte y el rosa indica los márgenes.
![](https://developer.android.com/static/images/tools/clipbounds_2x.png?authuser=6&hl=es-419)
Figura 1: Diseño con límites de recorte (predeterminado).
![](https://developer.android.com/static/images/tools/opticalbounds_2x.png?authuser=6&hl=es-419)
Figura 2: El diseño usa límites ópticos.
Para alinear las vistas en función de sus límites ópticos, establece el atributo android:layoutMode
en "opticalBounds"
en uno de los diseños de nivel superior. Por ejemplo:
<LinearLayout android:layoutMode="opticalBounds" ... >
![](https://developer.android.com/static/images/tools/ninepatch_opticalbounds_2x.png?authuser=6&hl=es-419)
Figura 3: Vista con zoom del nine-patch del botón Holo con límites ópticos.
Para que esto funcione, las imágenes nine-patch aplicadas en el fondo de las vistas deben especificar los límites ópticos utilizando líneas rojas en la parte inferior y derecha del archivo nine-patch (como como se muestra en la figura 3). Las líneas rojas indican la región que se debe restar de los límites de recorte y deja los límites ópticos de la imagen.
Cuando habilitas los límites ópticos para una ViewGroup
en tu diseño, todo
las vistas descendentes heredan el modo de diseño de límites ópticos, a menos que lo anules para un grupo por
estableciendo android:layoutMode
en "clipBounds"
. Todos los elementos de diseño también respetan el
límites ópticos de sus vistas secundarias, adaptando sus propios límites en función de los límites ópticos de
las vistas en ellos. Sin embargo, los elementos de diseño (subclases de ViewGroup
)
actualmente no admiten los límites ópticos para imágenes nine-patch aplicados a su propio fondo.
Si creas una vista personalizada mediante la subclasificación de View
, ViewGroup
o cualquier subclase de estos, tu vista heredará estos comportamientos de vinculación óptica.
Nota: Se actualizaron todos los widgets compatibles con el tema Holo.
con límites ópticos, incluidos Button
, Spinner
,
EditText
y otras. Así que puedes beneficiarte
de inmediato con la configuración
El atributo android:layoutMode
a "opticalBounds"
si tu app aplica un tema Holo
(Theme.Holo
, Theme.Holo.Light
, etc.).
Para especificar límites ópticos para tus propias imágenes nine-patch con la herramienta Draw 9-patch, mantén presionado Control cuando haciendo clic en los píxeles del borde.
Animación para valores Rect
Ahora puedes animar entre dos valores de Rect
con el nuevo RectEvaluator
. Esta clase nueva es una implementación de TypeEvaluator
que puedes pasar a ValueAnimator.setEvaluator()
.
Objeto de escucha de aplicación y enfoque de ventanas
Anteriormente, si querías escuchar cuando tu vista se adjuntaba o desconectaba de la ventana o
cuando cambiaba su enfoque, debías anular la clase View
para
implementar onAttachedToWindow()
y onDetachedFromWindow()
o onWindowFocusChanged()
, respectivamente.
Ahora, para recibir eventos de conexión y desconexión, puedes implementar ViewTreeObserver.OnWindowAttachListener
y configurarlo en una vista con
addOnWindowAttachListener()
Y para recibir eventos de enfoque, puedes implementar ViewTreeObserver.OnWindowFocusChangeListener
y configurarlo en una vista con
addOnWindowFocusChangeListener()
Compatibilidad con el sobrebarrido de TV
Para asegurarte de que tu app ocupe toda la pantalla de todos los televisores, ahora puedes habilitar el sobrebarrido
para el diseño de tu aplicación. El modo de sobrebarrido se determina con la marca FLAG_LAYOUT_IN_OVERSCAN
, que puedes habilitar con temas de plataforma, como
Theme_DeviceDefault_NoActionBar_Overscan
o habilitando
Estilo windowOverscan
en un tema personalizado
Orientación de la pantalla
La <activity>
screenOrientation
de la etiqueta
ahora admite valores adicionales para respetar la preferencia del usuario con respecto a la rotación automática:
"userLandscape"
- Se comporta igual que
"sensorLandscape"
, excepto si el usuario inhabilita la opción de girar automáticamente. se bloquea en la orientación horizontal normal y no se voltea. "userPortrait"
- Se comporta igual que
"sensorPortrait"
, excepto si el usuario inhabilita la opción de girar automáticamente. se traba en la orientación vertical normal y no se voltea. "fullUser"
- Se comporta de la misma manera que
"fullSensor"
y permite la rotación en las cuatro direcciones, excepto Si el usuario inhabilita la rotación automática, se bloquea en la orientación que prefiera el usuario.
Además, ahora también puedes declarar "locked"
para bloquear la orientación de tu app en
la orientación actual de la pantalla.
Animaciones de rotación
El nuevo campo rotationAnimation
en
WindowManager
te permite seleccionar una de las tres animaciones que
usar cuando el sistema cambie las orientaciones de la pantalla. Las tres animaciones son:
Nota: Estas animaciones están disponibles solo si configuraste tu actividad para que use "pantalla completa". que puedes habilitar con temas como Theme.Holo.NoActionBar.Fullscreen
.
Por ejemplo, así es como puedes habilitar el "encadenado" animación:
Kotlin
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val params: WindowManager.LayoutParams = window.attributes params.rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE window.attributes = params ... }
Java
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); WindowManager.LayoutParams params = getWindow().getAttributes(); params.rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE; getWindow().setAttributes(params); ... }
Entrada del usuario
Tipos de sensores nuevos
El nuevo sensor TYPE_GAME_ROTATION_VECTOR
te permite detectar las rotaciones del dispositivo sin preocuparte por las interferencias magnéticas. A diferencia del sensor TYPE_ROTATION_VECTOR
, el TYPE_GAME_ROTATION_VECTOR
no se basa en el norte magnético.
Los nuevos sensores TYPE_GYROSCOPE_UNCALIBRATED
y TYPE_MAGNETIC_FIELD_UNCALIBRATED
proporcionan datos de sensores sin procesar
para las estimaciones de sesgo. Es decir, los valores existentes de TYPE_GYROSCOPE
y TYPE_MAGNETIC_FIELD
los sensores proporcionan datos de sensores que tienen en cuenta el sesgo estimado del giro a la deriva y el hierro duro
del dispositivo, respectivamente. Mientras que el nuevo modelo "descalibrado" de estos sensores ofrecen en cambio
los datos sin procesar del sensor y ofrecer los valores de sesgo estimados por separado. Estos sensores te permiten
proporcionar tu propia calibración personalizada para los datos del sensor, ya que mejora el sesgo estimado con
datos externos.
Notificaciones del objeto de escucha
Android 4.3 agrega una nueva clase de servicio, NotificationListenerService
, que permite que tu app reciba información sobre notificaciones nuevas a medida que el sistema las publica.
Si tu app actualmente usa las APIs de servicios de accesibilidad para acceder a las notificaciones del sistema, debes actualizarla para que use estas APIs.
Proveedor de contactos
Consulta sobre “contactos”
La nueva consulta del proveedor de contactos, Contactables.CONTENT_URI
, proporciona una manera eficiente de obtener un Cursor
que contiene todas las direcciones de correo electrónico y los números de teléfono de todos los contactos que coinciden con la búsqueda especificada.
Consulta deltas de contactos
Se agregaron nuevas APIs al proveedor de contactos que te permiten consultar de manera eficiente los cambios recientes en los datos de los contactos. Anteriormente, tu app podía recibir una notificación cuando cambiaba algo en los datos de los contactos, pero no sabías con exactitud qué cambió y necesitarías recuperar todos los contactos y, luego, iterarlos para descubrir el cambio.
Para hacer un seguimiento de los cambios en las inserciones y las actualizaciones, ahora puedes incluir el parámetro CONTACT_LAST_UPDATED_TIMESTAMP
con tu selección para consultar solo los contactos que cambiaron desde la última vez que consultaste al proveedor.
Para realizar un seguimiento de los contactos que se eliminaron, la nueva tabla ContactsContract.DeletedContacts
proporciona un registro de los contactos que se eliminaron (pero cada contacto borrado se conserva en esta tabla por un tiempo limitado). Al igual que con CONTACT_LAST_UPDATED_TIMESTAMP
, puedes usar el nuevo parámetro de selección, CONTACT_DELETED_TIMESTAMP
, para verificar qué contactos se borraron desde la última vez que consultaste al proveedor. La tabla también contiene la constante DAYS_KEPT_MILLISECONDS
, que incluye la cantidad de días (en milisegundos) que se conservará el registro.
Además, el proveedor de contactos ahora transmite la acción CONTACTS_DATABASE_CREATED
cuando el usuario
borra el almacenamiento de contactos a través del menú de configuración del sistema, lo que recrea efectivamente la
Base de datos del proveedor de contactos. Está diseñada para indicar a las apps que deben quitar todos los contactos
información que tiene almacenada y la vuelve a cargar con una nueva consulta.
Si deseas obtener un ejemplo de código que usa estas APIs para comprobar si hay cambios en los contactos, consulta la documentación de muestra disponible en la descarga de Muestras de SDK.
Localización
Se mejoró la compatibilidad con texto bidireccional.
Las versiones anteriores de Android admiten idiomas y diseño con escritura de derecha a izquierda (RTL).
pero a veces no manejan
adecuadamente texto con direcciones mixtas. Por lo tanto, Android 4.3 agrega las APIs de BidiFormatter
que te ayudan a formatear correctamente el texto con dirección opuesta.
sin desordenar ninguna parte de él.
Por ejemplo, cuando quieres crear una oración con una variable de cadena, como "¿Quisiste decir...?
15 Bay Street, Laurel, CA?", normalmente, pasas un recurso de cadenas localizado y la variable a
String.format()
:
Kotlin
val suggestion = String.format(resources.getString(R.string.did_you_mean), address)
Java
Resources res = getResources(); String suggestion = String.format(res.getString(R.string.did_you_mean), address);
Sin embargo, si la configuración regional es hebreo, la cadena con formato se verá así:
האם התכוונת ל 15 Bay Street, Laurel, CA?
Eso es incorrecto, ya que el número "15" debería estar a la izquierda de "Bay Street". La solución es usar BidiFormatter
y su método unicodeWrap()
. Por ejemplo, el código anterior se convierte en lo siguiente:
Kotlin
val bidiFormatter = BidiFormatter.getInstance() val suggestion = String.format( resources.getString(R.string.did_you_mean), bidiFormatter.unicodeWrap(address) )
Java
Resources res = getResources(); BidiFormatter bidiFormatter = BidiFormatter.getInstance(); String suggestion = String.format(res.getString(R.string.did_you_mean), bidiFormatter.unicodeWrap(address));
De forma predeterminada, unicodeWrap()
usa el elemento
primera heurística de estimación direccional fuerte, que puede equivocarse si la primera
La señal de dirección del texto no representa la dirección adecuada para el contenido en su conjunto.
Si es necesario, puedes especificar una heurística diferente pasando una de las constantes TextDirectionHeuristic
de TextDirectionHeuristics
.
a unicodeWrap()
.
Nota: Estas APIs nuevas también están disponibles para versiones anteriores.
de Android mediante la Compatibilidad con Android
Biblioteca, con la clase BidiFormatter
y las APIs relacionadas.
Servicios de accesibilidad
Cómo controlar eventos clave
Un AccessibilityService
ahora puede recibir una devolución de llamada para
eventos de entrada clave con el método de devolución de llamada onKeyEvent()
. Esto permite que tu servicio de accesibilidad controle la entrada para
dispositivos de entrada basados en teclas, como un teclado, y traducir esos eventos en acciones especiales que
antes solo hubiera sido posible con la entrada táctil o el mando de dirección del dispositivo.
Seleccionar texto y copiarlo y pegarlo
AccessibilityNodeInfo
ahora proporciona APIs que permiten
Un AccessibilityService
para seleccionar, cortar, copiar y pegar
texto en un nodo.
Para especificar la selección de texto que deseas cortar o copiar, tu servicio de accesibilidad puede usar la nueva función
acción, ACTION_SET_SELECTION
, pasando
con la posición de inicio y finalización de la selección con ACTION_ARGUMENT_SELECTION_START_INT
y ACTION_ARGUMENT_SELECTION_END_INT
.
También puedes seleccionar texto manipulando la posición del cursor con el
acción, ACTION_NEXT_AT_MOVEMENT_GRANULARITY
(antes solo para mover la posición del cursor) y agregar el argumento ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
.
Luego, puedes cortar o copiar con ACTION_CUT
.
ACTION_COPY
y, luego, pegarlo con
ACTION_PASTE
Nota: Estas APIs nuevas también están disponibles para versiones anteriores.
de Android mediante la Compatibilidad con Android
Biblioteca, con AccessibilityNodeInfoCompat
.
Declara las funciones de accesibilidad
A partir de Android 4.3, un servicio de accesibilidad debe declarar capacidades de accesibilidad.
en su archivo de metadatos para usar ciertas funciones de accesibilidad. Si la función no es
solicitado en el archivo de metadatos, la función no funcionará. Para declarar la política
accesibilidad, debes usar atributos XML que correspondan a los diversos
"capacidad" constantes en AccessibilityServiceInfo
.
Por ejemplo, si un servicio no solicita la capacidad flagRequestFilterKeyEvents
,
no recibirá eventos clave.
Pruebas y depuración
Pruebas automatizadas de la IU
La nueva clase UiAutomation
proporciona APIs que te permiten simular la experiencia
para la automatización de pruebas. Mediante las APIs de AccessibilityService
de la plataforma, la función UiAutomation
Las APIs te permiten inspeccionar el contenido de la pantalla y, además, insertar eventos táctiles y de teclado arbitrarios.
Para obtener una instancia de UiAutomation
, llama a Instrumentation.getUiAutomation()
. En orden
Para que esto funcione, debes proporcionar la opción -w
con el comando instrument
cuando se ejecuta tu InstrumentationTestCase
desde adb shell
Con la instancia UiAutomation
, puedes ejecutar eventos arbitrarios para probar
tu app llamando a executeAndWaitForEvent()
, pasándole un Runnable
para que realice, un tiempo de espera
el período de la operación y una implementación de la interfaz UiAutomation.AccessibilityEventFilter
. Recibirás una llamada dentro de tu implementación de UiAutomation.AccessibilityEventFilter
que te permite filtrar los eventos que te interesan y determinar si
la falla de un caso de prueba determinado.
Para observar todos los eventos durante una prueba, crea una implementación de UiAutomation.OnAccessibilityEventListener
y pásala a setOnAccessibilityEventListener()
.
Luego, la interfaz del objeto de escucha recibe una llamada a onAccessibilityEvent()
.
cada vez que ocurre un evento, recibir un objeto AccessibilityEvent
que describe el evento.
Existe una variedad de otras operaciones que exponen las APIs de UiAutomation
en un nivel muy bajo para fomentar el desarrollo de herramientas de prueba de IU, como uiautomator. Por ejemplo:
UiAutomation
también puede hacer lo siguiente:
- Cómo insertar eventos de entrada
- Cómo cambiar la orientación de la pantalla
- Cómo tomar capturas de pantalla
Y lo más importante para las herramientas de prueba de IU, las APIs de UiAutomation
funcionan
más allá de los límites de las aplicaciones, a diferencia de los de Instrumentation
.
Eventos de Systrace para apps
Android 4.3 agrega la clase Trace
con dos métodos estáticos:
beginSection()
y endSection()
,
que te permiten definir bloques de código para incluir en el informe de Systrace. Creando
de código rastreable en tu app, los registros de Systrace ofrecen una explicación
un análisis de dónde se produce la ralentización en tu app.
Para obtener información sobre cómo usar la herramienta Systrace, consulta Cómo analizar la visualización y el rendimiento con Systrace.
Seguridad
Tienda de claves de Android para claves privadas de apps
Android ahora ofrece un proveedor de seguridad de Java personalizado en KeyStore
llamado Android Key Store, que te permite generar y guardar claves privadas que
los usuarios solo puedan ver y usar tu app. Para cargar Android Key Store, pasa
"AndroidKeyStore"
a KeyStore.getInstance()
.
Para administrar las credenciales privadas de tu app en Android Key Store, genera una clave nueva con
KeyPairGenerator
con KeyPairGeneratorSpec
. Nombre
Obtén una instancia de KeyPairGenerator
llamando a getInstance()
. Luego, llama
initialize()
, pasando una instancia de
KeyPairGeneratorSpec
, que puedes obtener usando
KeyPairGeneratorSpec.Builder
Por último, llama a generateKeyPair()
para obtener tu KeyPair
.
Almacenamiento de credenciales de hardware
Android ahora también admite almacenamiento con copia de seguridad en hardware para tu KeyChain
credenciales, lo que brinda más seguridad, ya que hace que las claves no estén disponibles para la extracción. Es decir, una vez
se encuentran en un almacén de claves respaldado en hardware (Elemento seguro, TPM o TrustZone), se pueden usar para
operaciones criptográficas, pero el material de clave privada no se puede exportar. Incluso el kernel del SO
no puede acceder al material de claves. Si bien no todos los dispositivos con Android admiten el almacenamiento en
puedes comprobar durante el tiempo de ejecución si el almacenamiento con copia de seguridad en hardware está disponible llamando
KeyChain.IsBoundKeyAlgorithm()
Declaraciones de manifiesto
Funciones requeridas declarables
Ahora se admiten los siguientes valores en <uses-feature>
para garantizar que tu app se instale solo en dispositivos que ofrezcan las funciones
necesita tu app.
FEATURE_APP_WIDGETS
- Declara que tu app proporciona un widget de app y debe instalarse solo en dispositivos que tengan las siguientes características:
incluir una pantalla principal o una ubicación similar donde los usuarios puedan incorporar widgets de apps.
Ejemplo:
<uses-feature android:name="android.software.app_widgets" android:required="true" />
FEATURE_HOME_SCREEN
- Declara que tu app se comporta como un reemplazo de la pantalla principal y solo debe instalarse en
dispositivos compatibles con la pantalla principal de terceros.
Ejemplo:
<uses-feature android:name="android.software.home_screen" android:required="true" />
FEATURE_INPUT_METHODS
- Declara que tu app proporciona un método de entrada personalizado (un teclado compilado con
InputMethodService
) y debe instalarse solo en dispositivos que tengan las siguientes características: admiten métodos de entrada de terceros. Ejemplo:<uses-feature android:name="android.software.input_methods" android:required="true" />
FEATURE_BLUETOOTH_LE
- Declara que tu app usa APIs de Bluetooth de bajo consumo y debe instalarse solo en dispositivos.
que puedan comunicarse con otros dispositivos mediante Bluetooth de bajo consumo.
Ejemplo:
<uses-feature android:name="android.software.bluetooth_le" android:required="true" />
Permisos del usuario
Ahora se admiten los siguientes valores en <uses-permission>
para declarar la
los permisos que tu app requiere para acceder a determinadas APIs.
BIND_NOTIFICATION_LISTENER_SERVICE
- Obligatorio para usar las nuevas APIs de
NotificationListenerService
. SEND_RESPOND_VIA_MESSAGE
- Obligatorio para recibir la
ACTION_RESPOND_VIA_MESSAGE
.
Para obtener una vista detallada de todos los cambios de API en Android 4.3, consulta la Informe de diferencias de las APIs.