API de Android 4.0

Nivel de API: 14

Android 4.0 (ICE_CREAM_SANDWICH) es una actualización importante de la plataforma que agrega una variedad de funciones nuevas para usuarios y desarrolladores de apps. Además de todas las funciones y APIs nuevas que se analizan a continuación, Android 4.0 es una versión de la plataforma importante porque incluye el amplio conjunto de API y temas holográficos de Android 3.x en pantallas más pequeñas. Como desarrollador de apps, ahora tienes una sola plataforma y un framework de API unificado que te permite desarrollar y publicar tu aplicación con un solo APK que proporciona una experiencia del usuario optimizada para teléfonos celulares, tablets y más, cuando se ejecuta la misma versión de Android a Android 4.0 (nivel de API 14) o versiones posteriores.

Para los desarrolladores, la plataforma Android 4.0 está disponible como un componente descargable del SDK de Android. La plataforma descargable incluye una imagen del sistema y una biblioteca de Android, así como un conjunto de máscaras de emulador y mucho más. Para comenzar a desarrollar o probar Android 4.0, usa Android SDK Manager para descargar la plataforma en tu SDK.

Descripción general de la API

En las siguientes secciones, se proporciona una descripción general técnica de las nuevas API en Android 4.0.

APIs sociales en el proveedor de contactos

Las APIs de contacto definidas por el proveedor de ContactsContract se extendieron para admitir nuevas funciones sociales, como un perfil personal para el propietario del dispositivo y la capacidad de los usuarios de invitar contactos individuales a las redes sociales que están instaladas en el dispositivo.

Perfil de usuario

Android ahora incluye un perfil personal que representa al propietario del dispositivo, como se define en la tabla ContactsContract.Profile. Las apps sociales que mantienen la identidad de un usuario pueden contribuir a los datos de su perfil mediante la creación de una nueva entrada ContactsContract.RawContacts en ContactsContract.Profile. Es decir, los contactos sin procesar que representan al usuario del dispositivo no pertenecen a la tabla tradicional de contactos sin procesar definida por el URI ContactsContract.RawContacts. En su lugar, debes agregar un contacto sin procesar de perfil en la tabla en CONTENT_RAW_CONTACTS_URI. Los contactos sin procesar de esta tabla se agregan en el perfil único visible para el usuario etiquetado como “Yo”.

Para agregar un nuevo contacto sin procesar al perfil, se requiere el permiso android.Manifest.permission#WRITE_PROFILE. Del mismo modo, para leer desde la tabla de perfiles, debes solicitar el permiso android.Manifest.permission#READ_PROFILE. Sin embargo, la mayoría de las apps no deberían necesitar leer el perfil del usuario, incluso cuando se aportan datos al perfil. La lectura del perfil del usuario es un permiso sensible y debes esperar que los usuarios sean escépticos con respecto a las apps que lo solicitan.

Intent de invitación

La acción de intent INVITE_CONTACT permite que una app invoque una acción que indica que el usuario desea agregar un contacto a una red social. La app que recibe la app la usa para invitar al contacto especificado a esa red social. La mayoría de las apps se encuentran en el extremo receptor de esta operación. Por ejemplo, la app de Personas integrada invoca el intent de invitación cuando el usuario selecciona "Agregar conexión" para una app social específica que aparece en los detalles de contacto de una persona.

Para que tu app sea visible como en la lista "Agregar conexión", esta debe proporcionar un adaptador de sincronización para sincronizar la información de contacto de tu red social. Luego, debes indicar al sistema que tu app responde al intent INVITE_CONTACT. Para ello, agrega el atributo inviteContactActivity al archivo de configuración de sincronización de tu app, con un nombre completo de la actividad que el sistema debe iniciar cuando envía el intent de invitación. Luego, la actividad que se inicia puede recuperar el URI del contacto en cuestión de los datos del intent y realizar el trabajo necesario para invitar a ese contacto a la red o agregar a la persona a las conexiones del usuario.

Fotos grandes

Android ahora admite fotos de alta resolución para los contactos. Ahora, cuando envías una foto al registro de un contacto, el sistema la procesa en una miniatura de 96 x 96 (como lo hacía antes) y una "foto visible" de 256 x 256 que se almacena en una nueva tienda de fotos basada en archivos (las dimensiones exactas que elija el sistema pueden variar en el futuro). Para agregar una foto grande a un contacto, coloca una foto grande en la columna PHOTO habitual de una fila de datos, que el sistema procesará para la miniatura adecuada y mostrará los registros de fotos.

Comentarios sobre el uso del contacto

Las nuevas APIs de ContactsContract.DataUsageFeedback te permiten hacer un seguimiento de la frecuencia con la que el usuario utiliza métodos específicos para comunicarse con las personas, como la frecuencia con la que utiliza cada número de teléfono o dirección de correo electrónico. Esta información ayuda a mejorar la clasificación de cada método de contacto asociado con cada persona y proporciona mejores sugerencias para comunicarse con cada una de ellas.

Proveedor de calendario

Las nuevas APIs de calendario te permiten leer, agregar, modificar y borrar calendarios, eventos, asistentes, recordatorios y alertas, que se almacenan en el Proveedor de calendario.

Varias apps y widgets pueden usar estas APIs para leer y modificar eventos de calendario. Sin embargo, algunos de los casos de uso más convincentes son los adaptadores de sincronización que sincronizan el calendario del usuario de otros servicios de calendario con el proveedor de calendario a fin de ofrecer una ubicación unificada para todos los eventos del usuario. Por ejemplo, el adaptador de sincronización del Calendario de Google sincroniza los eventos del Calendario de Google con el proveedor de calendario, lo que permite que estos eventos se vean con la app de Calendario integrada de Android.

CalendarContract define el modelo de datos para los calendarios y la información relacionada con los eventos en el Proveedor de calendario. Todos los datos del calendario del usuario se almacenan en una serie de tablas definidas por diversas subclases de CalendarContract:

  • La tabla CalendarContract.Calendars contiene la información específica del calendario. Cada fila de la tabla contiene los detalles de un solo calendario, como el nombre, el color, la información de sincronización, etcétera.
  • La tabla CalendarContract.Events contiene información específica del evento. Cada fila de esta tabla contiene la información de un solo evento, como el título, la ubicación, la hora de inicio y la hora de finalización, entre otros datos. El evento puede ocurrir una vez o repetirse varias veces. Los asistentes, los recordatorios y las propiedades extendidas se almacenan en tablas separadas y usan el _ID del evento para vincularlos con este.
  • La tabla CalendarContract.Instances contiene la hora de inicio y finalización de los casos de un evento. Cada fila de esta tabla representa un solo caso. Para los eventos únicos, hay una asignación uno a uno de instancias a eventos. En el caso de los eventos recurrentes, se generan automáticamente varias filas para que coincidan con los distintos casos de ese evento.
  • La tabla CalendarContract.Attendees contiene la información del asistente al evento o del invitado. Cada fila representa un solo invitado a un evento. Especifica el tipo de invitado que tiene la persona y su respuesta al evento.
  • La tabla CalendarContract.Reminders contiene los datos de alerta/notificación. Cada fila representa una sola alerta para un evento. Un evento puede tener múltiples recordatorios. La cantidad de recordatorios por evento se especifica en MAX_REMINDERS, que se establece mediante el adaptador de sincronización al que pertenece el calendario determinado. Los recordatorios se especifican en la cantidad de minutos antes de la programación del evento y se establece un método de alarma, como usar una alerta, un correo electrónico o un SMS para recordarle al usuario.
  • La tabla CalendarContract.ExtendedProperties contiene campos de datos opacos que usa el adaptador de sincronización. El proveedor no realiza ninguna acción con los elementos de esta tabla, excepto borrarlos cuando se borran sus eventos relacionados.

Para acceder a los datos del calendario de un usuario con el proveedor de calendario, tu aplicación debe solicitar el permiso READ_CALENDAR (para acceso de lectura) y WRITE_CALENDAR (para acceso de escritura).

Intent del evento

Si lo único que deseas hacer es agregar un evento al calendario del usuario, puedes usar un intent ACTION_INSERT con los datos definidos por Events.CONTENT_URI para iniciar una actividad en la app de Calendario que cree eventos nuevos. El uso del intent no requiere ningún permiso, y puedes especificar los detalles del evento con los siguientes extras:

Proveedor de buzón de voz

El nuevo proveedor de buzón de voz permite que las aplicaciones agreguen mensajes de voz al dispositivo para presentar todos los mensajes de voz del usuario en una sola presentación visual. Por ejemplo, es posible que un usuario tenga varias fuentes de buzón de voz, como una del proveedor de servicios del teléfono y otra de VoIP o algún otro servicio de voz alternativo. Estas apps pueden usar las API de Buzón de voz para agregar los mensajes de voz al dispositivo. Luego, la aplicación de teléfono integrada presenta todos los mensajes de voz al usuario en una presentación unificada. Si bien la aplicación de teléfono del sistema es la única que puede leer todos los mensajes de voz, cada aplicación que proporciona mensajes de voz puede leer aquellos que haya agregado al sistema (pero no puede leer mensajes de voz de otros servicios).

Debido a que, por el momento, las APIs no permiten que las apps de terceros lean todos los mensajes de voz del sistema, las únicas apps de terceros que deben usar las APIs de buzón de voz son aquellas que tienen buzón de voz para entregar al usuario.

La clase VoicemailContract define el proveedor de contenido para el proveedor del buzón de voz. Las subclases VoicemailContract.Voicemails y VoicemailContract.Status proporcionan tablas en las que las apps pueden insertar datos del buzón de voz para almacenarlos en el dispositivo. Para ver un ejemplo de una app proveedora de buzón de voz, consulta la Demostración del proveedor de buzón de voz.

Multimedia

Android 4.0 agrega varias API nuevas para aplicaciones que interactúan con contenido multimedia, como fotos, videos y música.

Efectos multimedia

Un nuevo framework de efectos multimedia te permite aplicar una variedad de efectos visuales a imágenes y videos. Por ejemplo, los efectos de imagen te permiten corregir fácilmente los ojos rojos, convertir una imagen a escala de grises, ajustar el brillo, ajustar la saturación, rotar una imagen, aplicar un efecto de ojo de pez y mucho más. El sistema realiza todos los procesamientos de efectos en la GPU para obtener el máximo rendimiento.

Para obtener el máximo rendimiento, los efectos se aplican directamente a las texturas de OpenGL, por lo que tu aplicación debe tener un contexto OpenGL válido antes de poder usar las APIs de efectos. Las texturas a las que aplicas efectos pueden ser de mapas de bits, videos o incluso la cámara. Sin embargo, existen ciertas restricciones que deben cumplir las texturas:

  1. Deben vincularse a una imagen de textura GL_TEXTURE_2D.
  2. Deben contener al menos un nivel de mipmap

Un objeto Effect define un solo efecto multimedia que puedes aplicar a un marco de imagen. El flujo de trabajo básico para crear un Effect es el siguiente:

  1. Llama a EffectContext.createWithCurrentGlContext() desde tu contexto de OpenGL ES 2.0.
  2. Usa el objeto EffectContext que se muestra para llamar a EffectContext.getFactory(), que muestra una instancia de EffectFactory.
  3. Llama a createEffect() y pásale un nombre de efecto desde @link android.media.effect.EffectFactory}, como EFFECT_FISHEYE o EFFECT_VIGNETTE.

Para ajustar los parámetros de un efecto, llama a setParameter() y pasa el nombre y el valor del parámetro. Cada tipo de efecto acepta diferentes parámetros, que se documentan con el nombre del efecto. Por ejemplo, EFFECT_FISHEYE tiene un parámetro para la scale de la distorsión.

Para aplicar un efecto en una textura, llama a apply() en Effect y pasa la textura de entrada, su ancho y alto, y la textura de salida. La textura de entrada debe vincularse a una imagen de textura GL_TEXTURE_2D (por lo general, se realiza mediante una llamada a la función glTexImage2D()). Puedes proporcionar varios niveles de mipmap. Si la textura de salida no se vinculó a una imagen de textura, el efecto la vinculará automáticamente como un elemento GL_TEXTURE_2D y con un nivel de mipmap (0), que tendrá el mismo tamaño que la entrada.

Se garantiza la compatibilidad con todos los efectos enumerados en EffectFactory. Sin embargo, algunos efectos adicionales disponibles de bibliotecas externas no son compatibles con todos los dispositivos, por lo que primero debes verificar si el efecto deseado de la biblioteca externa es compatible llamando a isEffectSupported().

Cliente de control remoto

El nuevo RemoteControlClient permite que los reproductores multimedia habiliten los controles de reproducción desde clientes de control remoto, como la pantalla de bloqueo del dispositivo. Los reproductores multimedia también pueden mostrar información sobre el contenido multimedia que se está reproduciendo para mostrar en el control remoto, como la información de la pista y la imagen del álbum.

Si quieres habilitar los clientes de control remoto para tu reproductor multimedia, crea una instancia de RemoteControlClient con su constructor y pásale un PendingIntent que transmita ACTION_MEDIA_BUTTON. El intent también debe declarar el componente BroadcastReceiver explícito en tu app que controla el evento ACTION_MEDIA_BUTTON.

Para declarar qué entradas de control de contenido multimedia puede procesar tu reproductor, debes llamar a setTransportControlFlags() en tu RemoteControlClient y pasar un conjunto de marcas FLAG_KEY_MEDIA_*, como FLAG_KEY_MEDIA_PREVIOUS y FLAG_KEY_MEDIA_NEXT.

Luego, debes registrar tu RemoteControlClient pasándolo a MediaManager.registerRemoteControlClient(). Una vez registrado, el receptor de emisión que declaraste cuando creaste una instancia de RemoteControlClient recibirá eventos ACTION_MEDIA_BUTTON cuando se presione un botón desde un control remoto. El intent que recibes incluye el KeyEvent para la tecla multimedia presionada, que puedes recuperar del intent con getParcelableExtra(Intent.EXTRA_KEY_EVENT).

Para mostrar información en el control remoto sobre el contenido multimedia que se está reproduciendo, llama a editMetaData() y agrega metadatos al RemoteControlClient.MetadataEditor que se muestra. Puedes proporcionar un mapa de bits para el material gráfico multimedia, información numérica (como el tiempo transcurrido) e información de texto (como el título de la pista). Para obtener información sobre las claves disponibles, consulta las marcas METADATA_KEY_* en MediaMetadataRetriever.

Para ver una muestra de implementación, consulta el Reproductor de música aleatorio, que proporciona una lógica de compatibilidad de modo que habilita el cliente de control remoto en dispositivos Android 4.0 sin dejar de admitir dispositivos con Android 2.1.

Reproductor multimedia

  • La transmisión de contenido multimedia en línea desde MediaPlayer ahora requiere el permiso INTERNET. Si usas MediaPlayer para reproducir contenido de Internet, asegúrate de agregar el permiso INTERNET a tu manifiesto. De lo contrario, la reproducción de contenido multimedia no funcionará a partir de Android 4.0.
  • setSurface() te permite definir un Surface para que se comporte como el receptor de video.
  • setDataSource() te permite enviar encabezados HTTP adicionales con tu solicitud, lo que puede ser útil para la transmisión en vivo HTTP(S)
  • La transmisión en vivo HTTP(S) ahora respeta las cookies HTTP en las solicitudes

Tipos de medios

Android 4.0 incorpora compatibilidad con lo siguiente:

  • Versión 3 del protocolo de transmisión en vivo HTTP/HTTPS
  • Codificación de audio AAC sin procesar ADTS
  • Imágenes WEBP
  • Video de Matroska

Para obtener más información, consulta los Formatos de medios compatibles.

Cámara

La clase Camera ahora incluye APIs para detectar rostros y controlar las áreas de enfoque y medición.

Detección de rostro

Las apps de cámara ahora pueden mejorar sus capacidades con las APIs de detección de rostro de Android, que no solo detectan el rostro de un sujeto, sino también rasgos faciales específicos, como los ojos y la boca.

Para detectar rostros en tu aplicación de cámara, debes registrar un Camera.FaceDetectionListener llamando a setFaceDetectionListener(). Luego, puedes iniciar la superficie de la cámara y comenzar a detectar rostros llamando a startFaceDetection().

Cuando el sistema detecta uno o más rostros en la escena de la cámara, llama a la devolución de llamada onFaceDetection() en tu implementación de Camera.FaceDetectionListener, que incluye un array de objetos Camera.Face.

Una instancia de la clase Camera.Face proporciona información variada sobre el rostro detectado, incluida la siguiente:

  • Un objeto Rect que especifica los límites del rostro en relación con el campo visual actual de la cámara
  • Un número entero entre 1 y 100 que indica la confianza del sistema en que el objeto es un rostro humano.
  • Un ID único que te permite hacer el seguimiento de varios rostros
  • Varios objetos Point que indican dónde se encuentran los ojos y la boca

Nota: Es posible que la detección de rostro no sea compatible con algunos dispositivos, por lo que debes llamar a getMaxNumDetectedFaces() para verificarlo y asegurarte de que el valor que se muestra sea mayor que cero. Además, es posible que algunos dispositivos no admitan la identificación de ojos y boca. En ese caso, esos campos del objeto Camera.Face serán nulos.

Áreas de enfoque y medición

Las apps de cámara ahora pueden controlar las áreas que la cámara usa para el enfoque y para medir el balance de blancos y la exposición automática. Ambas funciones usan la nueva clase Camera.Area para especificar la región de la vista actual de la cámara que se debe medir o enfocar. Una instancia de la clase Camera.Area define los límites del área con un objeto Rect y el peso del área, que representa el nivel de importancia de esa área, en relación con otras áreas en consideración, con un número entero.

Antes de establecer un área de enfoque o un área de medición, primero debes llamar a getMaxNumFocusAreas() o getMaxNumMeteringAreas(), respectivamente. Si muestran cero, el dispositivo no admite la función correspondiente.

Para especificar las áreas de enfoque o medición que se usarán, simplemente llame a setFocusAreas() o setMeteringAreas(). Cada una toma una List de objetos Camera.Area que indican las áreas que se deben tener en cuenta para el enfoque o la medición. Por ejemplo, puedes implementar una función que permita al usuario establecer el área de enfoque tocando un área de la vista previa, que luego traducirás a un objeto Camera.Area y solicitará que la cámara enfoque esa área de la escena. El enfoque o la exposición de esa área se actualizarán continuamente a medida que cambie el ambiente de la zona.

Enfoque automático continuo para fotos

Ahora puedes habilitar el enfoque automático continuo (CAF) al tomar fotos. Para habilitar el CAF en tu app de cámara, pasa FOCUS_MODE_CONTINUOUS_PICTURE a setFocusMode(). Cuando estés listo para tomar una foto, llama a autoFocus(). Tu Camera.AutoFocusCallback recibe una devolución de llamada de inmediato para indicar si se logró el enfoque. Para reanudar el CAF después de recibir la devolución de llamada, debes llamar a cancelAutoFocus().

Nota: El enfoque automático continuo también es compatible cuando se captura video con FOCUS_MODE_CONTINUOUS_VIDEO, que se agregó en el nivel de API 9.

Otras funciones de la cámara

  • Mientras grabas un video, ahora puedes llamar a takePicture() para guardar una foto sin interrumpir la sesión de video. Antes de hacerlo, debes llamar a isVideoSnapshotSupported() para asegurarte de que el hardware sea compatible.
  • Ahora puedes bloquear la exposición automática y el balance de blancos con setAutoExposureLock() y setAutoWhiteBalanceLock() para evitar que cambien estas propiedades.
  • Ahora puedes llamar a setDisplayOrientation() mientras se ejecuta la vista previa de la cámara. Anteriormente, solo podías llamar a este método antes de comenzar la vista previa, pero ahora puedes cambiar la orientación en cualquier momento.

Intents de transmisión de la cámara

  • Camera.ACTION_NEW_PICTURE: Indica que el usuario capturó una foto nueva. La app de cámara integrada invoca esta emisión después de que se captura una foto, y las apps de cámara de terceros también deben transmitir este intent después de tomar una foto.
  • Camera.ACTION_NEW_VIDEO: Indica que el usuario capturó un video nuevo. La app de cámara integrada invoca esta transmisión después de que se graba un video, y las apps de cámara de terceros también deben transmitir este intent después de capturar un video.

Android Beam (NDEF Push con NFC)

Android Beam es una nueva función NFC que te permite enviar mensajes NDEF de un dispositivo a otro (un proceso también conocido como "NDEF Push"). La transferencia de datos se inicia cuando dos dispositivos Android compatibles con Android Beam se encuentran cerca (alrededor de 4 cm), por lo general, con la parte posterior en contacto. Los datos dentro del mensaje NDEF pueden contener cualquier dato que desees compartir entre dispositivos. Por ejemplo, la app de Personas comparte contactos, YouTube comparte videos y el navegador comparte URLs con Android Beam.

Para transmitir datos entre dispositivos con Android Beam, debes crear un NdefMessage que contenga la información que deseas compartir mientras tu actividad está en primer plano. Luego, debes pasar el NdefMessage al sistema de una de dos maneras:

En caso de que desees ejecutar algún código específico una vez que el sistema haya entregado correctamente tu mensaje NDEF al otro dispositivo, puedes implementar NfcAdapter.OnNdefPushCompleteCallback y configurarlo con setNdefPushCompleteCallback(). Luego, el sistema llamará a onNdefPushComplete() cuando se entregue el mensaje.

En el dispositivo receptor, el sistema envía mensajes push NDEF de manera similar a las etiquetas NFC normales. El sistema invoca un intent con la acción ACTION_NDEF_DISCOVERED para iniciar una actividad, con una URL o un tipo de MIME configurado según el primer NdefRecord de NdefMessage. En la actividad a la que deseas responder, puedes declarar filtros de intents para las URLs o los tipos de MIME que son importantes para tu app. Para obtener más información sobre el envío de etiquetas, consulta la guía para desarrolladores de NFC.

Si quieres que tu NdefMessage lleve un URI, ahora puedes usar el método útil createUri para construir un nuevo NdefRecord basado en una cadena o en un objeto Uri. Si el URI es un formato especial que quieres que tu aplicación también reciba durante un evento de Android Beam, debes crear un filtro de intents para tu actividad mediante el uso del mismo esquema de URI a fin de recibir el mensaje NDEF entrante.

También debes pasar un "registro de aplicación para Android" con tu NdefMessage a fin de garantizar que tu aplicación controle el mensaje NDEF entrante, incluso si otras aplicaciones filtran la misma acción de intent. Si deseas crear un registro de aplicación para Android, llama a createApplicationRecord() y pásale el nombre del paquete de tu aplicación. Cuando el otro dispositivo recibe el mensaje NDEF con el registro de la aplicación y varias aplicaciones contienen actividades que manejan el intent especificado, el sistema siempre entrega el mensaje a la actividad de tu aplicación (en función del registro de aplicación coincidente). Si el dispositivo de destino no tiene instalada tu aplicación actualmente, el sistema utiliza el registro de la aplicación para Android a fin de iniciar Google Play y llevar al usuario a la aplicación a fin de instalarla.

Si tu aplicación no usa APIs de NFC para realizar mensajes push NDEF, Android proporciona un comportamiento predeterminado: cuando tu aplicación está en primer plano en un dispositivo y Android Beam se invoca con otro dispositivo Android, el otro dispositivo recibe un mensaje NDEF con un registro de aplicación para Android que identifica tu aplicación. Si el dispositivo receptor tiene la aplicación instalada, el sistema la inicia. Si no está instalada, Google Play se abre y lleva al usuario a tu aplicación para instalarla.

Puedes obtener más información sobre Android Beam y otras funciones de NFC en la guía para desarrolladores de Conceptos básicos de NFC. Para ver código de ejemplo con Android Beam, consulta la demostración de Android Beam.

P2P Wi-Fi

Android ahora admite conexiones Wi-Fi entre pares (P2P) entre dispositivos con Android y otros tipos de dispositivos (de acuerdo con el programa de certificación Wi-Fi DirectTM de Wi-Fi Alliance) sin un hotspot ni una conexión a Internet. El framework de Android proporciona un conjunto de APIs de P2P de Wi-Fi que te permiten descubrir otros dispositivos y conectarte a ellos cuando cada uno admite Wi-Fi P2P. Luego, se comunica a través de una conexión rápida a distancias mucho más largas que una conexión Bluetooth.

Un paquete nuevo, android.net.wifi.p2p, contiene todas las APIs para realizar conexiones entre pares con Wi-Fi. La clase principal con la que debes trabajar es WifiP2pManager, que puedes adquirir llamando a getSystemService(WIFI_P2P_SERVICE). WifiP2pManager incluye APIs que te permiten hacer lo siguiente:

  • Inicializa tu aplicación para conexiones P2P llamando a initialize()
  • Llama a discoverPeers() para descubrir dispositivos cercanos
  • Inicia una conexión P2P llamando a connect()
  • Y mucho más

También se necesitan varias interfaces y clases adicionales, como las siguientes:

  • La interfaz WifiP2pManager.ActionListener te permite recibir devoluciones de llamada cuando una operación, como descubrir pares o conectarte a ellos, es correcta o falla.
  • La interfaz WifiP2pManager.PeerListListener te permite recibir información sobre los pares detectados. La devolución de llamada proporciona un WifiP2pDeviceList, desde el cual puedes recuperar un objeto WifiP2pDevice para cada dispositivo que esté dentro del rango y obtener información como el nombre, la dirección, el tipo de dispositivo y las configuraciones de WPS que admite el dispositivo, entre otros.
  • La interfaz WifiP2pManager.GroupInfoListener te permite recibir información sobre un grupo P2P. La devolución de llamada proporciona un objeto WifiP2pGroup, que brinda información del grupo, como el propietario, el nombre de la red y la frase de contraseña.
  • WifiP2pManager.ConnectionInfoListener te permite recibir información sobre la conexión actual. La devolución de llamada proporciona un objeto WifiP2pInfo, que contiene información como si se formó un grupo y quién es el propietario.

Para usar las APIs de P2P Wi-Fi, tu app debe solicitar los siguientes permisos de usuario:

El sistema Android también transmite varias acciones diferentes durante ciertos eventos P2P Wi-Fi:

Consulta la documentación de WifiP2pManager para obtener más información. Observa también la aplicación de ejemplo de Demostración de P2P Wi-Fi.

Dispositivos Bluetooth de salud

Android ahora admite dispositivos de perfil de salud Bluetooth, por lo que puedes crear aplicaciones que utilizan Bluetooth para comunicarse con dispositivos de salud compatibles con Bluetooth, como monitores de frecuencia cardíaca, medidores de sangre, termómetros y balanzas.

Al igual que con los dispositivos de perfil A2DP y de auriculares normales, debes llamar a getProfileProxy() con un BluetoothProfile.ServiceListener y el tipo de perfil HEALTH para establecer una conexión con el objeto de proxy de perfil.

Una vez que adquieras el proxy de perfiles de salud (el objeto BluetoothHealth), la conexión con dispositivos de salud vinculados y la comunicación con ellos implica las siguientes clases de Bluetooth nuevas:

  • BluetoothHealthCallback: Debes extender esta clase e implementar los métodos de devolución de llamada para recibir actualizaciones sobre los cambios en el estado de registro de la aplicación y el estado del canal de Bluetooth.
  • BluetoothHealthAppConfiguration: Durante las devoluciones de llamada a tu BluetoothHealthCallback, recibirás una instancia de este objeto, que proporciona información de configuración sobre el dispositivo de estado Bluetooth disponible, que debes usar para realizar varias operaciones, como iniciar y finalizar conexiones con las APIs de BluetoothHealth.

Para obtener más información sobre el uso del perfil de estado de Bluetooth, consulta la documentación de BluetoothHealth.

Accesibilidad

Android 4.0 mejora la accesibilidad para los usuarios con discapacidad visual con el nuevo modo de exploración táctil y las APIs extendidas que te permiten proporcionar más información sobre el contenido de las vistas o desarrollar servicios de accesibilidad avanzados.

Modo de exploración táctil

Los usuarios con pérdida de la visión ahora pueden explorar la pantalla tocando y arrastrando un dedo por la pantalla para escuchar las descripciones de voz del contenido. Debido a que el modo de exploración táctil funciona como un cursor virtual, permite que los lectores de pantalla identifiquen el texto descriptivo de la misma manera que los lectores de pantalla cuando el usuario navega con un pad direccional o una bola de seguimiento: con la lectura de la información que proporcionan android:contentDescription y setContentDescription() en un evento "desplazamiento" simulado. Por lo tanto, ten en cuenta que este es un recordatorio de que debes proporcionar texto descriptivo para las vistas de tu aplicación, en especial para ImageButton, EditText, ImageView y otros widgets que podrían no contener texto descriptivo naturalmente.

Accesibilidad de las vistas

Para mejorar la información disponible para los servicios de accesibilidad, como los lectores de pantalla, puedes implementar nuevos métodos de devolución de llamada para eventos de accesibilidad en tus componentes View personalizados.

Es importante tener en cuenta que el comportamiento del método sendAccessibilityEvent() cambió en Android 4.0. Al igual que con la versión anterior de Android, cuando el usuario habilita los servicios de accesibilidad en el dispositivo y se produce un evento de entrada, como un clic o un desplazamiento, se notifica a la vista respectiva con una llamada a sendAccessibilityEvent(). Anteriormente, la implementación de sendAccessibilityEvent() inicializaba un AccessibilityEvent y lo enviaba a AccessibilityManager. El nuevo comportamiento incluye algunos métodos de devolución de llamada adicionales que permiten que la vista y sus elementos superiores agreguen más información contextual al evento:

  1. Cuando se invocan, los métodos sendAccessibilityEvent() y sendAccessibilityEventUnchecked() difieren a onInitializeAccessibilityEvent().

    Es posible que las implementaciones personalizadas de View quieran implementar onInitializeAccessibilityEvent() para adjuntar información de accesibilidad adicional a AccessibilityEvent, pero también deben llamar a la superimplementación para proporcionar información predeterminada, como la descripción de contenido estándar, el índice de elementos, etc. Sin embargo, no debes agregar contenido de texto adicional en esta devolución de llamada, ya que eso sucede a continuación.

  2. Una vez inicializado, si el evento es uno de los varios tipos que deben propagarse con información de texto, la vista recibe una llamada a dispatchPopulateAccessibilityEvent(), que difiere de la devolución de llamada onPopulateAccessibilityEvent().

    Por lo general, las implementaciones personalizadas de View deben implementar onPopulateAccessibilityEvent() para agregar contenido de texto adicional a AccessibilityEvent si falta el texto android:contentDescription o si es insuficiente. Para agregar más descripciones de texto a AccessibilityEvent, llama a getText().add().

  3. En este punto, View pasa el evento por la jerarquía de vistas llamando a requestSendAccessibilityEvent() en la vista superior. Cada vista superior tiene la oportunidad de aumentar la información de accesibilidad agregando un AccessibilityRecord hasta llegar a la vista raíz, que envía el evento al AccessibilityManager con sendAccessibilityEvent().

Además de los métodos nuevos anteriores, que son útiles cuando se extiende la clase View, también puedes interceptar estas devoluciones de llamada de eventos en cualquier View extendiendo AccessibilityDelegate y configurándolo en la vista con setAccessibilityDelegate(). Cuando lo haces, cada método de accesibilidad de la vista aplaza la llamada al método correspondiente en el delegado. Por ejemplo, cuando la vista recibe una llamada a onPopulateAccessibilityEvent(), la pasa al mismo método en View.AccessibilityDelegate. Cualquier método que no controle el delegado se devuelve directamente a la vista para obtener el comportamiento predeterminado. Esto te permite anular solo los métodos necesarios para cualquier vista determinada sin extender la clase View.

Si quieres mantener la compatibilidad con versiones de Android anteriores a la 4.0 y, al mismo tiempo, admitir las nuevas APIs de accesibilidad, puedes hacerlo con la versión más reciente de la biblioteca de compatibilidad v4 (en Paquete de compatibilidad, r4) mediante un conjunto de clases de utilidades que proporcionen las nuevas APIs de accesibilidad en un diseño retrocompatible.

Servicios de accesibilidad

Si estás desarrollando un servicio de accesibilidad, la información sobre varios eventos de accesibilidad se expandió significativamente a fin de habilitar comentarios sobre accesibilidad más avanzados para los usuarios. En particular, los eventos se generan según la composición de las vistas, lo que proporciona mejor información de contexto y permite que los servicios de accesibilidad recorran jerarquías de vistas para obtener información de vistas adicional y manejar casos especiales.

Si estás desarrollando un servicio de accesibilidad (como un lector de pantalla), puedes acceder a información adicional de contenido y recorrer jerarquías de vistas con el siguiente procedimiento:

  1. Cuando recibas un AccessibilityEvent de una aplicación, llama a AccessibilityEvent.getRecord() para recuperar un AccessibilityRecord específico (puede haber varios registros adjuntos al evento).
  2. Desde AccessibilityEvent o un AccessibilityRecord individual, puedes llamar a getSource() para recuperar un objeto AccessibilityNodeInfo.

    Un AccessibilityNodeInfo representa un nodo único del contenido de la ventana en un formato que te permite consultar información de accesibilidad sobre ese nodo. El objeto AccessibilityNodeInfo que muestra AccessibilityEvent describe la fuente del evento, mientras que la fuente de una AccessibilityRecord describe el predecesor de la fuente del evento.

  3. Con la AccessibilityNodeInfo, puedes consultar información sobre ella, llamar a getParent() o getChild() para desviar la jerarquía de vistas o incluso agregar vistas secundarias al nodo.

Para que tu aplicación se publique en el sistema como un servicio de accesibilidad, debe declarar un archivo de configuración XML que corresponda a AccessibilityServiceInfo. Si quieres obtener más información sobre cómo crear un servicio de accesibilidad, consulta AccessibilityService y SERVICE_META_DATA para obtener información sobre la configuración de XML.

Otras APIs de accesibilidad

Si te interesa el estado de accesibilidad del dispositivo, AccessibilityManager tiene algunas APIs nuevas, como las siguientes:

Servicios de corrector ortográfico

Un nuevo framework del corrector ortográfico permite que las apps creen correctores ortográficos de manera similar al framework del método de entrada (para IME). Para crear un nuevo corrector ortográfico, debes implementar un servicio que extienda SpellCheckerService y extender la clase SpellCheckerService.Session para proporcionar sugerencias ortográficas basadas en el texto proporcionado por los métodos de devolución de llamada de la interfaz. En los métodos de devolución de llamada SpellCheckerService.Session, debes mostrar las sugerencias de ortografía como objetos SuggestionsInfo.

Las aplicaciones con un servicio de corrector ortográfico deben declarar el permiso BIND_TEXT_SERVICE según lo requiera el servicio. El servicio también debe declarar un filtro de intents con <action android:name="android.service.textservice.SpellCheckerService" /> como la acción del intent, y debe incluir un elemento <meta-data> que declare la información de configuración del corrector ortográfico.

Consulta la app de muestra del Servicio del corrector ortográfico y la del Cliente del corrector ortográfico para ver el código de ejemplo.

Motores de texto a voz

Las APIs de texto a voz (TTS) de Android se extendieron de manera significativa para permitir que las aplicaciones implementen motores de TTS personalizados con mayor facilidad, mientras que las aplicaciones que desean usar un motor de TTS tienen un par de APIs nuevas para seleccionar un motor.

Cómo usar motores de texto a voz

En versiones anteriores de Android, podías usar la clase TextToSpeech para realizar operaciones de texto a voz (TTS) con el motor de TTS proporcionado por el sistema o configurar un motor personalizado con setEngineByPackageName(). En Android 4.0, el método setEngineByPackageName() dejó de estar disponible y ahora puedes especificar el motor para usar con un nuevo constructor TextToSpeech que acepte el nombre del paquete de un motor de TTS.

También puedes consultar los motores de TTS disponibles con getEngines(). Este método muestra una lista de objetos TextToSpeech.EngineInfo, que incluye metadatos, como el ícono, la etiqueta y el nombre del paquete del motor.

Cómo crear motores de texto a voz

Antes, los motores personalizados requerían que el motor se compilara con un archivo de encabezado nativo sin documentar. En Android 4.0, existe un conjunto completo de APIs de framework para compilar motores de TTS.

La configuración básica requiere una implementación de TextToSpeechService que responda al intent INTENT_ACTION_TTS_SERVICE. El trabajo principal de un motor de TTS ocurre durante la devolución de llamada onSynthesizeText(), en un servicio que extiende TextToSpeechService. A este método, el sistema le entrega dos objetos:

  • SynthesisRequest: Contiene varios datos, incluidos el texto que se sintetizará, la configuración regional, la velocidad de voz y el tono de voz.
  • SynthesisCallback: Esta es la interfaz por la que tu motor de TTS entrega los datos de voz resultantes como audio de transmisión. Primero, el motor debe llamar a start() para indicar que está listo para entregar el audio. Luego, debe llamar a audioAvailable() y pasarle los datos de audio en un búfer de bytes. Una vez que el motor pase todo el audio a través del búfer, llama a done().

Ahora que el framework admite una verdadera API para crear motores de TTS, se quitó la compatibilidad con la implementación de código nativo. Busca una entrada de blog sobre una capa de compatibilidad que puedes usar para convertir tus motores de TTS antiguos al nuevo marco de trabajo.

Para ver un ejemplo de motor de TTS con las nuevas APIs, consulta la app de ejemplo Text to Speech Engine.

Uso de red

Android 4.0 brinda a los usuarios una visibilidad precisa de la cantidad de datos de red que usan sus aplicaciones. La app de Configuración proporciona controles que permiten a los usuarios administrar límites establecidos para el uso de datos de red e incluso inhabilitar el uso de datos en segundo plano para apps individuales. Para evitar que los usuarios inhabiliten el acceso de tu app a los datos en segundo plano, debes desarrollar estrategias para usar la conexión de datos de manera eficiente y ajustar tu uso según el tipo de conexión disponible.

Si tu aplicación realiza muchas transacciones de red, debes proporcionar una configuración de usuario que permita a los usuarios controlar los hábitos de datos de tu app, como la frecuencia con la que tu app sincroniza datos, si realiza cargas o descargas solo cuando hay una conexión Wi-Fi, si usa datos con roaming, etc. Con estos controles a su disposición, es mucho menos probable que los usuarios inhabiliten el acceso de tu app a los datos cuando se acercan a sus límites, ya que pueden, en cambio, usar la app con precisión. Si proporcionas una actividad de preferencia con esta configuración, debes incluir en su declaración de manifiesto un filtro de intents para la acción ACTION_MANAGE_NETWORK_USAGE. Por ejemplo:

<activity android:name="DataPreferences" android:label="@string/title_preferences">
    <intent-filter>
       <action android:name="android.intent.action.MANAGE_NETWORK_USAGE" />
       <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

Este filtro de intents le indica al sistema que esta es la actividad que controla el uso de datos de tu aplicación. Por lo tanto, cuando el usuario inspecciona cuántos datos usa tu app desde la app de Configuración, aparece un botón "Ver la configuración de la aplicación" que inicia tu actividad de preferencias para que el usuario pueda definir mejor cuántos datos usa tu app.

Además, ten en cuenta que getBackgroundDataSetting() ahora es obsoleto y siempre muestra un valor verdadero; en su lugar, usa getActiveNetworkInfo(). Antes de intentar realizar cualquier transacción de red, siempre debes llamar a getActiveNetworkInfo() para obtener el NetworkInfo que representa la red actual y consultar isConnected() para verificar si el dispositivo tiene conexión. Luego, puedes verificar otras propiedades de la conexión, como si el dispositivo está en roaming o conectado a Wi-Fi.

Enterprise

Android 4.0 expande las capacidades de las aplicaciones empresariales con las siguientes funciones.

Servicios de VPN

La nueva VpnService permite que las aplicaciones compilen su propia VPN (red privada virtual), que se ejecuta como Service. Un servicio de VPN crea una interfaz para una red virtual con su propia dirección y reglas de enrutamiento, y realiza toda la lectura y escritura con un descriptor de archivo.

Para crear un servicio de VPN, usa VpnService.Builder, que te permite especificar la dirección de red, el servidor DNS, la ruta de red y mucho más. Cuando termines, podrás establecer la interfaz llamando a establish(), que muestra un ParcelFileDescriptor.

Debido a que un servicio de VPN puede interceptar paquetes, existen implicaciones de seguridad. Por lo tanto, si implementas VpnService, tu servicio debe requerir el BIND_VPN_SERVICE para garantizar que solo el sistema pueda vincularse a él (solo al sistema se le otorga este permiso; las apps no pueden solicitarlo). Para luego usar tu servicio de VPN, los usuarios deben habilitarlo manualmente en la configuración del sistema.

Políticas de dispositivo

Las aplicaciones que administran las restricciones del dispositivo ahora pueden inhabilitar la cámara usando setCameraDisabled() y la propiedad USES_POLICY_DISABLE_CAMERA (aplicada con un elemento <disable-camera /> en el archivo de configuración de políticas).

Administración de certificados

La nueva clase KeyChain proporciona APIs que te permiten importar certificados en el almacén de claves del sistema y acceder a ellos. Los certificados optimizan la instalación de los certificados de cliente (para validar la identidad del usuario) y de los certificados de autoridad certificadora (para verificar la identidad del servidor). Las aplicaciones como navegadores web o clientes de correo electrónico pueden acceder a los certificados instalados para autenticar a los usuarios en los servidores. Consulta la documentación de KeyChain para obtener más información.

Sensores de dispositivos

En Android 4.0, se agregaron dos tipos de sensores nuevos:

  • TYPE_AMBIENT_TEMPERATURE: Un sensor de temperatura que proporciona la temperatura ambiente (de la habitación) en grados Celsius.
  • TYPE_RELATIVE_HUMIDITY: Es un sensor de humedad que proporciona la humedad relativa del ambiente (habitación) en forma de porcentaje.

Si un dispositivo tiene sensores TYPE_AMBIENT_TEMPERATURE y TYPE_RELATIVE_HUMIDITY, puedes usarlos para calcular el punto de condensación y la humedad absoluta.

El sensor de temperatura anterior, TYPE_TEMPERATURE, dejó de estar disponible. En su lugar, debes usar el sensor TYPE_AMBIENT_TEMPERATURE.

Además, se mejoraron mucho los tres sensores sintéticos de Android, por lo que ahora tienen una latencia más baja y resultados más fluidos. Estos sensores incluyen el sensor de gravedad (TYPE_GRAVITY), el sensor del vector de rotación (TYPE_ROTATION_VECTOR) y el sensor de aceleración lineal (TYPE_LINEAR_ACCELERATION). Los sensores mejorados dependen del sensor del giroscopio para mejorar su salida, de modo que solo aparecen en dispositivos que tienen giroscopio.

Barra de acciones

Se actualizó ActionBar para admitir varios comportamientos nuevos. Lo más importante es que el sistema administra correctamente el tamaño y la configuración de la barra de acciones cuando se ejecuta en pantallas más pequeñas para proporcionar una experiencia del usuario óptima en todos los tamaños de pantalla. Por ejemplo, cuando la pantalla es angosta (como cuando el teléfono está en orientación vertical), las pestañas de navegación de la barra de acciones aparecen en una "barra apilada", que aparece directamente debajo de la barra de acciones principal. También puedes habilitar una "barra de acciones dividida", que ubica todos los elementos de acción en una barra independiente en la parte inferior de la pantalla cuando la pantalla está angosta.

Barra de acciones dividida

Si la barra de acciones incluye varios elementos de acción, no todos entrarán en la barra de acciones en una pantalla estrecha, por lo que el sistema colocará más elementos en el menú ampliado. Sin embargo, Android 4.0 te permite habilitar la "barra de acciones dividida" para que puedan aparecer más elementos de acción en la pantalla en una barra separada en la parte inferior. Para habilitar la barra de acciones dividida, agrega android:uiOptions con "splitActionBarWhenNarrow" a la etiqueta <application> o a las etiquetas <activity> individuales en el archivo de manifiesto. Cuando se habilite, el sistema agregará una barra adicional en la parte inferior de la pantalla para todos los elementos de acción cuando la pantalla esté angosta (no aparecerá ningún elemento de acción en la barra de acciones principal).

Si deseas usar las pestañas de navegación que proporcionan las APIs de ActionBar.Tab, pero no necesitas la barra de acciones principal en la parte superior (solo quieres que las pestañas aparezcan en la parte superior), habilita la barra de acciones dividida como se describió anteriormente y llama a setDisplayShowHomeEnabled(false) para inhabilitar el ícono de la aplicación en la barra de acciones. Cuando no queda nada en la barra de acciones principal, desaparece. Todo lo que queda son las pestañas de navegación en la parte superior y los elementos de acción en la parte inferior de la pantalla.

Estilos de la barra de acciones

Si deseas aplicar un estilo personalizado a la barra de acciones, puedes usar las nuevas propiedades de estilo backgroundStacked y backgroundSplit para aplicar un elemento de diseño o color de fondo a la barra apilada y a la barra dividida, respectivamente. También puedes configurar estos diseños en el tiempo de ejecución con setStackedBackgroundDrawable() y setSplitBackgroundDrawable().

Proveedor de acciones

La nueva clase ActionProvider te permite crear un controlador especializado para los elementos de acción. Un proveedor de acciones puede definir una vista de acción, un comportamiento de acción predeterminado y un submenú para cada elemento de acción al que está asociado. Cuando quieras crear un elemento de acción con comportamientos dinámicos (como una vista de acción variable, una acción predeterminada o un submenú), extender ActionProvider es una buena solución para crear un componente reutilizable, en lugar de controlar las diversas transformaciones de elementos de acción en tu fragmento o actividad.

Por ejemplo, ShareActionProvider es una extensión de ActionProvider que facilita una acción de "compartir" desde la barra de acciones. En lugar de usar un elemento de acción tradicional que invoca el intent ACTION_SEND, puedes usar este proveedor de acciones para presentar una vista de acción con una lista desplegable de aplicaciones que controlan el intent ACTION_SEND. Cuando el usuario selecciona una aplicación para usar en la acción, ShareActionProvider recuerda esa selección y la proporciona en la vista de acción para un acceso más rápido a la acción compartida con esa app.

Si quieres declarar un proveedor de acciones para un elemento de acción, incluye el atributo android:actionProviderClass en el elemento <item> del menú de opciones de tu actividad, con el nombre de clase del proveedor de acciones como valor. Por ejemplo:

<item android:id="@+id/menu_share"
      android:title="Share"
      android:showAsAction="ifRoom"
      android:actionProviderClass="android.widget.ShareActionProvider" />

En el método de devolución de llamada onCreateOptionsMenu() de tu actividad, recupera una instancia del proveedor de acciones desde el elemento de menú y configura el intent:

Kotlin

override fun onCreateOptionsMenu(menu: Menu): Boolean {
    menuInflater.inflate(R.menu.options, menu)
    val shareActionProvider = menu.findItem(R.id.menu_share)?.actionProvider as? ShareActionProvider
    // Set the share intent of the share action provider.
    shareActionProvider?.setShareIntent(createShareIntent())
    ...
    return super.onCreateOptionsMenu(menu)
}

Java

public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.options, menu);
    ShareActionProvider shareActionProvider =
          (ShareActionProvider) menu.findItem(R.id.menu_share).getActionProvider();
    // Set the share intent of the share action provider.
    shareActionProvider.setShareIntent(createShareIntent());
    ...
    return super.onCreateOptionsMenu(menu);
}

Para ver un ejemplo que use ShareActionProvider, consulta ActionBarShareActionProviderActivity en ApiDemos.

Vistas de acciones que se pueden contraer

Los elementos de acción que proporcionan una vista de acción ahora pueden alternar entre su estado de vista de acción y el estado de elemento de acción tradicional. Anteriormente, solo se admitía la contracción SearchView cuando se usaba como vista de acción, pero ahora puedes agregar una vista de acción para cualquier elemento de acción y alternar entre el estado expandido (la vista de acción es visible) y el estado contraído (el elemento de acción es visible).

Para declarar que un elemento de acción que contiene una vista de acción se puede contraer, incluye la marca “collapseActionView" en el atributo android:showAsAction del elemento <item> en el archivo en formato XML del menú.

Para recibir devoluciones de llamada cuando una vista de acción cambia entre expandida y contraída, registra una instancia de MenuItem.OnActionExpandListener con el MenuItem correspondiente llamando a setOnActionExpandListener(). Por lo general, debes hacerlo durante la devolución de llamada onCreateOptionsMenu().

Para controlar una vista de acción que se puede contraer, puedes llamar a collapseActionView() y expandActionView() en el MenuItem correspondiente.

Cuando creas una vista de acción personalizada, también puedes implementar la nueva interfaz CollapsibleActionView para recibir devoluciones de llamada cuando la vista se expande y se contrae.

Otras APIs para la barra de acciones

  • setHomeButtonEnabled() te permite especificar si el ícono o logotipo se comporta como un botón para navegar a la página principal o "hacia arriba" (pasa "true" a fin de que se comporte como un botón).
  • setIcon() y setLogo() te permiten definir el ícono o el logotipo de la barra de acciones durante el tiempo de ejecución.
  • Fragment.setMenuVisibility() te permite habilitar o inhabilitar la visibilidad de los elementos del menú de opciones que declara el fragmento. Esto es útil si el fragmento se agregó a la actividad, pero no es visible, por lo que los elementos de menú deberían estar ocultos.
  • FragmentManager.invalidateOptionsMenu() te permite invalidar el menú de opciones de la actividad durante varios estados del ciclo de vida del fragmento en los que el uso del método equivalente de Activity podría no estar disponible.

Interfaz de usuario y vistas

Android 4.0 presenta una variedad de vistas nuevas y otros componentes de la IU.

GridLayout

GridLayout es un nuevo grupo de vistas que coloca las vistas secundarias en una cuadrícula rectangular. A diferencia de TableLayout, GridLayout se basa en una jerarquía plana y no utiliza vistas intermedias, como filas de tablas, para proporcionar la estructura. En cambio, los elementos secundarios especifican qué filas y columnas deben ocupar (las celdas pueden abarcar varias filas o columnas) y, de forma predeterminada, se disponen de forma secuencial en las filas y columnas de la cuadrícula. La orientación GridLayout determina si los elementos secundarios secuenciales se disponen de forma horizontal o vertical de forma predeterminada. El espacio entre los elementos secundarios se puede especificar mediante instancias de la nueva vista Space o mediante la configuración de los parámetros de margen relevantes en los elementos secundarios.

Consulta ApiDemos para ver ejemplos que usan GridLayout.

Vista de textura

TextureView es una vista nueva que te permite mostrar una transmisión de contenido, como un video o una escena de OpenGL. Aunque es similar a SurfaceView, TextureView es único porque se comporta como una vista normal, en lugar de crear una ventana independiente, por lo que puedes tratarlo como cualquier otro objeto View. Por ejemplo, puedes aplicar transformaciones, animarlas con ViewPropertyAnimator o ajustar su opacidad con setAlpha().

Ten en cuenta que TextureView solo funciona dentro de una ventana acelerada por hardware.

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

Cambiar widget

El nuevo widget Switch es un botón de activación de dos estados que los usuarios pueden arrastrar a un lado o al otro (o simplemente presionarlo) para activar o desactivar una opción entre dos estados.

Puedes usar los atributos android:textOn y android:textOff para especificar el texto que aparecerá en el interruptor cuando esté activada o desactivada. El atributo android:text también te permite colocar una etiqueta junto al interruptor.

Para ver un ejemplo del uso de interruptores, consulta el archivo de diseño switches.xml y la actividad correspondiente de Switches .

Android 3.0 introdujo PopupMenu para crear menús contextuales cortos que aparecen en el punto de anclaje que especificas (por lo general, en el punto del elemento seleccionado). Android 4.0 amplía PopupMenu con algunas funciones útiles:

  • Ahora, puedes aumentar fácilmente el contenido de un menú emergente desde un recurso de menú XML con inflate() y pasarle el ID de recurso de menú.
  • Ahora también puedes crear un PopupMenu.OnDismissListener que reciba una devolución de llamada cuando se descarte el menú.

Preferencias

Una nueva clase abstracta TwoStatePreference sirve de base para las preferencias que proporcionan una opción de selección de dos estados. El nuevo SwitchPreference es una extensión de TwoStatePreference que proporciona un widget de Switch en la vista de preferencias para permitir que los usuarios activen o desactiven un parámetro de configuración sin necesidad de abrir una pantalla o un diálogo de preferencias adicionales. Por ejemplo, la aplicación Configuración usa un SwitchPreference para los ajustes de Wi-Fi y Bluetooth.

Temas del sistema

El tema predeterminado para todas las aplicaciones que se orientan a Android 4.0 (estableciendo targetSdkVersion o minSdkVersion en “14" o una versión posterior) ahora es el tema "predeterminado del dispositivo": Theme.DeviceDefault. Puede ser el tema oscuro de Holo o un tema oscuro diferente definido por el dispositivo específico.

Se garantiza que la familia de temas Theme.Holo no cambiará de un dispositivo a otro cuando se ejecute la misma versión de Android. Si aplicas explícitamente cualquiera de los temas Theme.Holo a tus actividades, puedes estar seguro de que no cambiarán de carácter en diferentes dispositivos dentro de la misma versión de la plataforma.

Si deseas que tu app se integre con el tema general del dispositivo (por ejemplo, cuando diferentes OEM proporcionan diferentes temas predeterminados para el sistema), debes aplicar explícitamente temas de la familia Theme.DeviceDefault.

Botón del menú de opciones

A partir de Android 4.0, notarás que los teléfonos celulares ya no requieren un botón de hardware de menú. Sin embargo, no es necesario que te preocupes por esto si tu aplicación existente proporciona un menú de opciones y espera que haya un botón de menú. Para garantizar que las apps existentes sigan funcionando como se espera, el sistema proporciona un botón de menú en pantalla en las apps diseñadas para versiones anteriores de Android.

Para brindar la mejor experiencia del usuario, las apps nuevas y actualizadas deben usar ActionBar para proporcionar acceso a los elementos de menú y establecer targetSdkVersion en "14" para aprovechar los comportamientos predeterminados más recientes del framework.

Controles para la visibilidad de la IU del sistema

Desde los inicios de Android, el sistema ha administrado un componente de la IU conocido como la barra de estado, que se encuentra en la parte superior de los teléfonos celulares para enviar información, como la señal del proveedor, la hora, las notificaciones, etc. Android 3.0 agregó la barra del sistema para tablets, que se encuentra en la parte inferior de la pantalla para proporcionar controles de navegación del sistema (Inicio, Atrás, etc.) y también una interfaz para elementos que tradicionalmente proporciona la barra de estado. En Android 4.0, el sistema proporciona un nuevo tipo de IU del sistema llamado barra de navegación. Podrías considerar la barra de navegación como una versión reajustada de la barra del sistema diseñada para teléfonos celulares: proporciona controles de navegación para dispositivos que no tienen equivalentes de hardware para navegar por el sistema, pero omite la IU de notificaciones de la barra del sistema y los controles de configuración. Por lo tanto, un dispositivo que proporciona la barra de navegación también tiene la barra de estado en la parte superior.

Hasta el día de hoy, puedes ocultar la barra de estado en los teléfonos celulares mediante la marca FLAG_FULLSCREEN. En Android 4.0, las APIs que controlan la visibilidad de la barra del sistema se actualizaron para reflejar mejor el comportamiento de la barra del sistema y de la barra de navegación:

  • La marca SYSTEM_UI_FLAG_LOW_PROFILE reemplaza a la marca STATUS_BAR_HIDDEN. Cuando se establece, esta marca habilita el modo de "perfil bajo" para la barra del sistema o de navegación. Los botones de navegación se atenúan y también se ocultan otros elementos de la barra del sistema. Habilitar esta opción es útil para crear juegos más envolventes sin distracciones de los botones de navegación del sistema.
  • La marca SYSTEM_UI_FLAG_VISIBLE reemplaza a la marca STATUS_BAR_VISIBLE para solicitar que la barra del sistema o la barra de navegación sean visibles.
  • SYSTEM_UI_FLAG_HIDE_NAVIGATION es una marca nueva que solicita que la barra de navegación se oculte por completo. Ten en cuenta que esta opción solo funciona para la barra de navegación que usan algunos teléfonos celulares (no oculta la barra del sistema en las tablets). La barra de navegación vuelve a visualizarse en cuanto el sistema recibe las entradas del usuario. Por lo tanto, este modo es útil principalmente para la reproducción de video o en otros casos en los que se necesita toda la pantalla, pero no se requiere la entrada del usuario.

Puedes configurar cada una de estas marcas para la barra del sistema y la barra de navegación llamando a setSystemUiVisibility() en cualquier vista de tu actividad. El administrador de ventanas combina (O) todas las marcas de todas las vistas de tu ventana y las aplica a la IU del sistema, siempre que esta tenga foco de entrada. Cuando la ventana pierde el enfoque de entrada (el usuario sale de la app o aparece un diálogo), las marcas dejan de tener efecto. Del mismo modo, si quitas esas vistas de la jerarquía de vistas, sus marcas dejarán de aplicarse.

Para sincronizar otros eventos en tu actividad con cambios de visibilidad en la IU del sistema (por ejemplo, ocultar la barra de acciones o algún otro control de la IU cuando se oculta la IU del sistema), debes registrar un View.OnSystemUiVisibilityChangeListener para recibir una notificación cuando cambie la visibilidad de la barra del sistema o de la barra de navegación.

Consulta la clase OverscanActivity para ver una demostración de las diferentes opciones de IU del sistema.

Framework de entrada

Android 4.0 agrega compatibilidad para eventos de desplazamiento del cursor y nuevos eventos de la pluma stylus y del botón del mouse.

Eventos de colocar el cursor sobre un elemento

La clase View ahora admite eventos de "desplazamiento" para habilitar interacciones más enriquecidas mediante dispositivos de puntero (como un mouse u otros dispositivos que manejan un cursor en pantalla).

Para recibir eventos de colocar el cursor sobre una vista, implementa View.OnHoverListener y regístralo con setOnHoverListener(). Cuando se produce un evento de desplazamiento en la vista, el objeto de escucha recibe una llamada a onHover() y proporciona el View que recibió el evento y un MotionEvent que describe el tipo de evento de desplazamiento que ocurrió. El evento de colocar el cursor sobre un elemento puede ser uno de los siguientes:

Tu View.OnHoverListener debería mostrar un valor verdadero desde onHover() si controla el evento de colocar el cursor sobre él. Si el objeto de escucha muestra el valor "false", el evento de desplazamiento se enviará a la vista superior como de costumbre.

Si tu aplicación usa botones u otros widgets que cambian su apariencia en función del estado actual, ahora puedes usar el atributo android:state_hovered en un elemento de diseño de lista de estados para proporcionar un elemento de diseño en segundo plano diferente cuando un cursor se coloca sobre la vista.

Para ver una demostración de los nuevos eventos de colocar el cursor sobre un elemento, consulta la clase Hover en ApiDemos.

Eventos de la pluma stylus y del botón del mouse

Android ahora proporciona APIs para recibir entradas de un dispositivo de entrada de pluma stylus, como un periférico de tablet digitalizador o una pantalla táctil compatible con la pluma stylus.

La entrada de la pluma stylus funciona de manera similar a la entrada táctil o del mouse. Cuando la pluma stylus está en contacto con el digitalizador, las aplicaciones reciben eventos táctiles del mismo modo que lo harían cuando se usa un dedo para tocar la pantalla. Cuando la pluma stylus se coloca por encima del digitalizador, las aplicaciones reciben eventos de desplazamiento del mismo modo que lo harían cuando se mueve un puntero del mouse por la pantalla cuando no se presiona ningún botón.

Tu aplicación puede distinguir entre la entrada de dedo, mouse, pluma stylus y borrador consultando el "tipo de herramienta" asociado con cada puntero en una MotionEvent mediante getToolType(). Los tipos de herramientas definidos actualmente son: TOOL_TYPE_UNKNOWN, TOOL_TYPE_FINGER, TOOL_TYPE_MOUSE, TOOL_TYPE_STYLUS y TOOL_TYPE_ERASER. Si se consulta el tipo de herramienta, tu aplicación puede elegir controlar la entrada de la pluma stylus de diferentes maneras, desde la entrada con el dedo o el mouse.

Tu aplicación también puede consultar qué botones del mouse o de la pluma stylus se presionan con una consulta del "estado del botón" de un MotionEvent con getButtonState(). Los estados de los botones definidos actualmente son: BUTTON_PRIMARY, BUTTON_SECONDARY, BUTTON_TERTIARY, BUTTON_BACK y BUTTON_FORWARD. Para mayor comodidad, los botones para retroceder y avanzar del mouse se asignan automáticamente a las teclas KEYCODE_BACK y KEYCODE_FORWARD. Tu aplicación puede controlar estas teclas para admitir la navegación hacia atrás y hacia adelante basada en el botón del mouse.

Además de medir con precisión la posición y la presión de un contacto, algunos dispositivos de entrada de la pluma stylus también informan la distancia entre la punta de la pluma stylus y el digitalizador, el ángulo de inclinación y el ángulo de orientación de la pluma stylus. Tu aplicación puede consultar esta información mediante getAxisValue() con los códigos de eje AXIS_DISTANCE, AXIS_TILT y AXIS_ORIENTATION.

Para ver una demostración de los tipos de herramientas, los estados de los botones y los nuevos códigos de eje, consulta la clase TouchPaint en ApiDemos.

Propiedades

La nueva clase Property proporciona una manera rápida, eficiente y fácil de especificar una propiedad en cualquier objeto que permite que los emisores establezcan o obtengan valores de forma genérica en los objetos de destino. También permite la funcionalidad de pasar referencias de campo o método y permite que el código establezca o obtenga valores de la propiedad sin conocer los detalles de los campos o métodos.

Por ejemplo, si deseas establecer el valor del campo bar en el objeto foo, antes harías esto:

Kotlin

foo.bar = value

Java

foo.bar = value;

Si deseas llamar al método set para un campo privado subyacente bar, antes harías lo siguiente:

Kotlin

foo.setBar(value)

Java

foo.setBar(value);

Sin embargo, si deseas pasar la instancia de foo y establecer algún otro código en el valor bar, no hay manera de hacerlo antes de Android 4.0.

Con la clase Property, puedes declarar un objeto Property BAR en la clase Foo de modo que puedas configurar el campo en la instancia foo de la clase Foo de la siguiente manera:

Kotlin

BAR.set(foo, value)

Java

BAR.set(foo, value);

La clase View ahora aprovecha la clase Property para permitirte establecer varios campos, como las propiedades de transformación que se agregaron en Android 3.0 (ROTATION, ROTATION_X, TRANSLATION_X, etcétera).

La clase ObjectAnimator también usa la clase Property, por lo que puedes crear un ObjectAnimator con un Property, que es más rápido, eficiente y seguro que el enfoque basado en strings.

Aceleración de hardware

A partir de Android 4.0, la aceleración de hardware para todas las ventanas está habilitada de forma predeterminada si tu aplicación estableció targetSdkVersion o minSdkVersion en “14" o una versión posterior. Por lo general, la aceleración de hardware da como resultado animaciones y desplazamientos más fluidos, además de un mejor rendimiento y una respuesta a la interacción del usuario en general.

Si es necesario, puedes inhabilitar manualmente la aceleración de hardware con el atributo hardwareAccelerated para elementos <activity> individuales o el elemento <application>. Como alternativa, puedes inhabilitar la aceleración de hardware para vistas individuales llamando a setLayerType(LAYER_TYPE_SOFTWARE).

Para obtener más información sobre la aceleración de hardware, incluida una lista de las operaciones de dibujo no compatibles, consulta el documento Aceleración de hardware.

Cambios de JNI

En versiones anteriores de Android, las referencias locales de JNI no eran controladores indirectos; Android usaba punteros directos. Esto no era un problema siempre que el recolector de elementos no utilizados no moviera objetos, pero parecía funcionar, ya que permitía escribir código con errores. En Android 4.0, el sistema ahora usa referencias indirectas para detectar estos errores.

Los pormenores de las referencias locales de JNI se describen en la sección “Referencias locales y globales” de la sección Sugerencias de JNI. En Android 4.0, CheckJNI se mejoró para detectar estos errores. Mira el Blog para desarrolladores de Android a fin de encontrar una próxima publicación sobre errores comunes con las referencias de JNI y cómo solucionarlos.

Este cambio en la implementación de JNI solo afecta a las apps orientadas a Android 4.0, ya que establece targetSdkVersion o minSdkVersion en “14" o una versión posterior. Si configuraste estos atributos en un valor inferior, las referencias locales de JNI se comportan de la misma manera que en versiones anteriores.

WebKit

  • WebKit se actualizó a la versión 534.30
  • Compatibilidad con fuentes índicas (devanagari, bengalí y tamil, incluida la compatibilidad con caracteres complejos que se necesitan para combinar glifos) en WebView y el navegador integrado
  • Compatibilidad con fuentes etíopes, georgianas y armenias en WebView y en el navegador integrado
  • La compatibilidad con WebDriver te permite probar con mayor facilidad apps que usan WebView

Navegador Android

La aplicación Navegador agrega las siguientes funciones para admitir aplicaciones web:

Permisos

Los siguientes son permisos nuevos:

Funciones del dispositivo

Las siguientes son funciones nuevas del dispositivo:

  • FEATURE_WIFI_DIRECT: Declara que la aplicación usa Wi-Fi para las comunicaciones entre pares.

Para obtener una vista detallada de todos los cambios de la API en Android 4.0 (nivel de API 14), consulta el Informe de diferencias de las APIs.

APIs anteriores

Además de todo lo anterior, Android 4.0 naturalmente admite todas las API de versiones anteriores. Debido a que la plataforma Android 3.x solo está disponible para dispositivos de pantalla grande, si desarrollaste principalmente para teléfonos celulares, es posible que no estés al tanto de todas las APIs agregadas a Android en estas versiones recientes.

A continuación, te mostramos algunas de las APIs más destacadas que quizás te perdiste y que ahora también están disponibles en teléfonos celulares:

Android 3.0
  • Fragment: Es un componente del framework que te permite separar elementos distintos de una actividad en módulos independientes que definen su propia IU y ciclo de vida. Consulta la guía para desarrolladores de Fragments.
  • ActionBar: Es un reemplazo de la barra de título tradicional en la parte superior de la ventana de actividades. Incluye el logotipo de la aplicación en la esquina izquierda y proporciona una nueva interfaz para los elementos de menú. Consulta la guía para desarrolladores sobre la Barra de acciones.
  • Loader: Es un componente del framework que facilita la carga asíncrona de datos en combinación con los componentes de la IU para cargar datos de forma dinámica sin bloquear el subproceso principal. Consulta la guía para desarrolladores sobre cargadores.
  • Portapapeles del sistema: Las aplicaciones pueden copiar y pegar datos (más allá del mero texto) desde y hacia el portapapeles de todo el sistema. Los datos recortados pueden ser texto sin formato, un URI o un intent. Consulta la guía para desarrolladores sobre Copiar y pegar.
  • Arrastrar y soltar: Es un conjunto de APIs integradas en el framework de la vista que facilita las operaciones de arrastrar y soltar. Consulta la guía para desarrolladores sobre Arrastrar y soltar.
  • Un framework de animación flexible nuevo te permite animar propiedades arbitrarias de cualquier objeto (vista, elemento de diseño, fragmento, objeto o cualquier otro) y definir aspectos de animación, como duración, interpolación, repetición y mucho más. El nuevo framework hace que las animaciones de Android sean más fáciles que nunca. Consulta la guía para desarrolladores sobre Animación de propiedades.
  • Gráficos y Compute Engine de RenderScript: RenderScript ofrece una API de procesamiento y renderización de gráficos 3D de alto rendimiento en el nivel nativo, que se escribe en C (estándar C99), lo que proporciona el tipo de rendimiento que esperas de un entorno nativo, sin dejar de ser portátil en varias CPU y GPU. Consulta la guía para desarrolladores de RenderScript.
  • Gráficos 2D acelerados por hardware: Ahora puedes habilitar el procesador OpenGL para tu aplicación configurando {android:hardwareAccelerated="true"} en el elemento <application> del manifiesto o para elementos <activity> individuales. De esta manera, se obtienen animaciones y desplazamientos más fluidos, además de un mejor rendimiento y una respuesta a la interacción del usuario en general.

    Nota: Si configuras minSdkVersion o targetSdkVersion de tu aplicación en "14" o un valor superior, la aceleración de hardware se habilita de forma predeterminada.

  • Y mucho, mucho más. Consulta las notas de la Plataforma Android 3.0 para obtener más información.
Android 3.1
  • APIs de USB: APIs nuevas y potentes para integrar periféricos conectados con aplicaciones para Android Las APIs se basan en una pila USB y en servicios integrados en la plataforma, incluida la compatibilidad con interacciones de dispositivos y hosts USB. Consulta la guía para desarrolladores sobre hosts y accesorios USB.
  • APIs de MTP/PTP: Las aplicaciones pueden interactuar directamente con las cámaras conectadas y otros dispositivos PTP para recibir notificaciones cuando se conectan y quitan dispositivos, administrar archivos y el almacenamiento en esos dispositivos, y transferir archivos y metadatos desde y hacia ellos. La API de MTP implementa el subconjunto de PTP (Protocolo de transferencia de imágenes) de la especificación de MTP (Protocolo de transferencia de medios). Consulta la documentación de android.mtp.
  • APIs de RTP: Android expone una API a su pila de RTP (protocolo de transporte en tiempo real) integrada, que las aplicaciones pueden usar para administrar la transmisión de datos interactiva o a pedido. En particular, las apps que proporcionan VoIP, enviar para hablar, conferencias y transmisión de audio pueden usar la API a fin de iniciar sesiones y transmitir o recibir flujos de datos a través de cualquier red disponible. Consulta la documentación de android.net.rtp.
  • Compatibilidad con joysticks y otras entradas de movimiento genéricas.
  • Consulta las notas de la Plataforma de Android 3.1 para ver muchas más API nuevas.
Android 3.2
  • Las nuevas pantallas admiten APIs que te brindan más control sobre cómo se muestran tus aplicaciones en diferentes tamaños de pantalla. La API extiende el modelo de compatibilidad de pantalla existente con la capacidad de orientarse con precisión a rangos de tamaño de pantalla específicos por dimensiones, medidas en unidades de píxeles independientes de la densidad (como 600 dp o 720 dp de ancho), en lugar de sus tamaños generalizados (como grande o extragrande). Por ejemplo, esto es importante para ayudarte a distinguir entre un dispositivo de 5" y un dispositivo de 7, que tradicionalmente se agruparían como pantallas "grandes". Consulta la entrada de blog New Tools for Managing Screen Sizes.
  • Nuevas constantes para que <uses-feature> declare los requisitos de orientación de pantalla horizontal o vertical.
  • La configuración de "tamaño de pantalla" del dispositivo ahora cambia durante un cambio de orientación de la pantalla. Si tu app está orientada al nivel de API 13 o superior, debes controlar el cambio de configuración de "screenSize" si también deseas controlar el cambio de configuración de "orientation". Consulta android:configChanges para obtener más información.
  • Consulta las notas de la Plataforma Android 3.2 para ver otras APIs nuevas.

Nivel de API

A la API de Android 4.0 se le asigna un identificador de número entero, 14, que se almacena en el propio sistema. Este identificador, denominado "nivel de API", permite que el sistema determine correctamente si una aplicación es compatible con él antes de instalarla.

Para usar las APIs que se introdujeron en Android 4.0 en tu aplicación, deberás compilarla en una plataforma de Android que admita el nivel de API 14 o versiones posteriores. Según tus necesidades, es posible que también debas agregar un atributo android:minSdkVersion="14" al elemento <uses-sdk>.

Para obtener más información, consulta ¿Qué es el nivel de API?