APIs 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 actualización importante de la plataforma porque incluye el amplio conjunto de APIs 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: 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 biblioteca de Android, una imagen del sistema, un conjunto de máscaras de emulador y mucho más. Para comenzar a desarrollar o probar con Android 4.0, usa SDK Manager de Android 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 que los usuarios inviten a 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 una identidad de usuario pueden contribuir a los datos de perfil del usuario creando una nueva entrada ContactsContract.RawContacts dentro de 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 al perfil único visible para el usuario etiquetado como “Yo”.

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

Intención de invitación

La acción de intent INVITE_CONTACT permite que una app invoque una acción que indique 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 integrada de Personas invoca el intent de invitación cuando el usuario selecciona "Agregar conexión" para una app social específica que se muestra 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 completamente calificado de la actividad que el sistema debe iniciar cuando envía el intent de invitación. 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 a un registro de contacto, el sistema la procesa en una miniatura de 96 x 96 (como lo hacía anteriormente) 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 podrían 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.

Comunicarse con los comentarios sobre el uso

Las nuevas APIs de ContactsContract.DataUsageFeedback te permiten hacer un seguimiento de la frecuencia con la que el usuario utiliza métodos particulares 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 a 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 atractivos son los adaptadores de sincronización que sincronizan el calendario del usuario de otros servicios 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 de Calendario de Google sincroniza los eventos de Calendario de Google con el proveedor de calendario, lo que permite que estos eventos se puedan ver con la app de Calendario integrada de Android.

El modelo de datos para calendarios y la información relacionada con eventos en el Proveedor de calendario se define mediante CalendarContract. 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, etcétera. 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 correspondan a los distintos casos de ese evento.
  • La tabla CalendarContract.Attendees contiene la información del asistente al evento o de los invitados. Cada fila representa un solo invitado a un evento. Especifica el tipo de invitado que es la persona y la respuesta de esta 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 establece el adaptador de sincronización propietario del calendario determinado. Los recordatorios se especifican en minutos antes de la programación del evento y también establecen 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 de 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 quieres 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 crea 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 otras de VoIP, o bien otros servicios de voz alternativos. Estas apps pueden usar las APIs de Buzón de voz para agregar sus mensajes de voz al dispositivo. Luego, la aplicación integrada de teléfono 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 aplicación 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 las APIs actualmente 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 las 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. Si quieres ver un ejemplo de una app del proveedor de buzón de voz, consulta la Demostración del proveedor de buzón de voz.

Multimedia

En Android 4.0, se agregan 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 todo el procesamiento 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 mipmaps

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 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 de @link android.media.effect.EffectFactory}, como EFFECT_FISHEYE o EFFECT_VIGNETTE.

Para ajustar los parámetros de un efecto, llama a setParameter() y pasa un nombre y un 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 el scale de la distorsión.

Para aplicar un efecto a 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 mipmaps. Si la textura de salida no se vinculó a una imagen de textura, quedará vinculada automáticamente por el efecto como una 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 en 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 portada 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 una 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 controlar el 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 en el control remoto información 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 implementación de muestra, consulta el reproductor de música aleatorio, que brinda una lógica de compatibilidad de modo que habilita el cliente de control remoto en dispositivos con 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 para 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 Formatos multimedia 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 habilidades 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 la 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, incluido lo 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 qué tan seguro está el sistema de que el objeto es un rostro humano
  • Un ID único para que puedas 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 deberías llamar a getMaxNumDetectedFaces() para verificarlo y asegurarte de que el valor que se muestra sea superior a cero. Además, es posible que algunos dispositivos no admitan la identificación de los ojos y la 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 usa la cámara 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 enfocar o medir. Una instancia de la clase Camera.Area define los límites del área con un valor de Rect y el peso del área, lo 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 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 deseas usar, simplemente llama a setFocusAreas() o setMeteringAreas(). Cada uno 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 en 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 las fotos

Ahora puedes habilitar el enfoque automático continuo (CAF) cuando tomas fotos. Para habilitar el CAF en tu app de cámara, pasa FOCUS_MODE_CONTINUOUS_PICTURE a setFocusMode(). Cuando estés listo para capturar 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. Antes de hacerlo, debes llamar a isVideoSnapshotSupported() para asegurarte de que el hardware lo admita.
  • Ahora puedes bloquear la exposición automática y el balance de blancos con setAutoExposureLock() y setAutoWhiteBalanceLock() para evitar que estas propiedades cambien.
  • 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 transmisió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 capturar 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 con Android que admiten Android Beam se encuentran cerca (aproximadamente 4 cm) y, por lo general, con la parte trasera en contacto. Los datos dentro del mensaje NDEF pueden contener cualquier dato que desees compartir entre dispositivos. Por ejemplo, la app Personas comparte contactos, YouTube comparte videos y el navegador comparte URL 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 estas 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 le interesan a tu app. Para obtener más información sobre el despacho de etiquetas, consulta la guía para desarrolladores de NFC.

Si deseas que tu NdefMessage lleve un URI, ahora puedes usar el método de conveniencia createUri para construir un nuevo NdefRecord basado en una cadena o 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 usando el mismo esquema de URI para recibir el mensaje NDEF entrante.

También debes pasar un "registro de aplicación de Android" con tu NdefMessage para garantizar que tu aplicación controle el mensaje NDEF entrante, incluso si otras aplicaciones filtran la misma acción de intent. Puedes crear un registro de aplicación para Android si llamas a createApplicationRecord() y le pasas 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 (según el registro de la 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 para 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 instalada la aplicación, el sistema la inicia. Si no está instalada, Google Play se abre y dirige 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 algunos ejemplos de código 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 tecnología Android y otros tipos de dispositivos (de conformidad 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 Wi-Fi que te permiten descubrir otros dispositivos y conectarte a ellos cuando cada uno admite Wi-Fi P2P y, luego, comunicarse 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:

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

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

  • La interfaz WifiP2pManager.ActionListener te permite recibir devoluciones de llamada cuando una operación, como descubrir pares o conectarte a ellas, tiene éxito 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, las configuraciones de WPS que admite el dispositivo y mucho más.
  • 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.
  • La interfaz WifiP2pManager.ConnectionInfoListener te permite recibir información sobre la conexión actual. La devolución de llamada proporciona un objeto WifiP2pInfo, que incluye información como si se formó un grupo y quién es su 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 con perfiles de salud Bluetooth, por lo que puedes crear aplicaciones que usan Bluetooth para comunicarse con dispositivos de salud que admiten Bluetooth, como monitores de frecuencia cardíaca, medidores de sangre, termómetros y balanzas.

Al igual que con los dispositivos de perfiles 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 hayas adquirido el proxy del perfil de salud (el objeto BluetoothHealth), la conexión a los 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 salud 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 ella para escuchar las descripciones por 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 pueden hacerlo cuando el usuario navega con un pad direccional o una bola de seguimiento; para ello, lee la información que proporcionan android:contentDescription y setContentDescription() en un evento de desplazamiento simulado. Por lo tanto, ten en cuenta que debes proporcionar texto descriptivo para las vistas de tu aplicación, especialmente para ImageButton, EditText, ImageView y otros widgets que podrían no contener texto descriptivo naturalmente.

Accesibilidad de las vistas

Si deseas 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 los 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 un evento de entrada, como un clic o colocar el cursor sobre un elemento, la vista respectiva recibe una notificación con una llamada a sendAccessibilityEvent(). Antes, 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 del elemento, etcétera. 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 varios tipos que se deben propagar con información de texto, la vista recibe una llamada a dispatchPopulateAccessibilityEvent(), que difiere a la devolución de llamada de 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 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 que llegue a la vista raíz, que envía el evento a AccessibilityManager con sendAccessibilityEvent().

Además de los nuevos métodos 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 desvía 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 maneja el delegado vuelve a la vista para su comportamiento predeterminado. Esto te permite anular solo los métodos necesarios para cualquier vista determinada sin extender la clase View.

Si deseas 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) con un conjunto de clases de utilidades que proporcionan 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 diversos eventos de accesibilidad se expandió significativamente a fin de permitir comentarios sobre accesibilidad más avanzados para los usuarios. En particular, los eventos se generan según la composición de 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 desarrollas un servicio de accesibilidad (como un lector de pantalla), puedes acceder a información de contenido adicional 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 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 para 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 de corrector ortográfico y la app de 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 usarlo 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 incluyen metadatos, como el ícono, la etiqueta y el nombre del paquete del motor.

Cómo crear motores de texto a voz

Anteriormente, 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 crear motores 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 de onSynthesizeText() en un servicio que extiende TextToSpeechService. El sistema entrega este método dos objetos:

  • SynthesisRequest: Contiene varios datos, incluidos el texto que se debe sintetizar, la configuración regional, la velocidad de la 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 transmisión de audio. 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 puedas usar para convertir tus motores de TTS antiguos al nuevo framework.

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 los 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 el uso según el tipo de conexión disponible.

Si tu aplicación realiza muchas transacciones de red, debes proporcionar parámetros de configuración que permitan a los usuarios controlar los hábitos de datos de tu app, como la frecuencia con la que sincroniza datos, si realiza cargas o descargas solo cuando el dispositivo está conectado a una red Wi-Fi, si se usan datos en roaming, etc. Con estos controles disponibles, es mucho menos probable que los usuarios inhabiliten el acceso de tu app a los datos precisamente cuando se acercan a sus límites. 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 el botón "Ver la configuración de la aplicación" que inicia tu actividad de preferencias para que el usuario pueda definir mejor la cantidad de datos que usa tu app.

Además, ten en cuenta que getBackgroundDataSetting() ahora es obsoleto y siempre muestra el valor "true". En su lugar, usa getActiveNetworkInfo(). Antes de intentar 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 una conexión. Luego, puedes verificar otras propiedades de conexión, por ejemplo, si el dispositivo está en roaming o está conectado a Wi-Fi.

Empresas

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 archivos.

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, puedes 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 el servicio de VPN, los usuarios deben habilitarlo manualmente en la configuración del sistema.

Políticas de dispositivo

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

Administración de certificados

La nueva clase KeyChain proporciona APIs que te permiten importar certificados y acceder a ellos en el almacén de claves del sistema. Los certificados optimizan la instalación de los certificados de cliente (para validar la identidad del usuario) y de los certificados de la autoridad certificadora (para verificar la identidad del servidor). Las aplicaciones como los navegadores web o los 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: Es un sensor de temperatura que proporciona la temperatura ambiente (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 rocío 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 una salida más fluida. Entre estos sensores se 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 optimizar 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 un teléfono celular se encuentra 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 coloca todos los elementos de acción en una barra separada en la parte inferior de la pantalla cuando esta es angosta.

Barra de acciones dividida

Si la barra de acciones incluye varios elementos de acción, no todos caberán en la barra de acciones en una pantalla estrecha, por lo que el sistema colocará más de ellos en el menú ampliado. Sin embargo, Android 4.0 permite habilitar la "barra de acciones dividida" para que puedan aparecer más elementos de acción en una barra separada en la parte inferior de la pantalla. 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 esta sea 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 aparezcan las pestañas en la parte superior), habilita la barra de acciones divididas 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 a la izquierda 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 color o un elemento de diseño 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 elementos de acción. Un proveedor de acciones puede definir una vista de acciones, 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 manejar 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 al uso compartido 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 en el que se use ShareActionProvider, consulta ActionBarShareActionProviderActivity en ApiDemos.

Vistas de acción 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 de 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 es contraíble, incluye la marca “collapseActionView" en el atributo android:showAsAction del elemento <item> del archivo en formato XML del menú.

Para recibir devoluciones de llamada cuando una vista de acción alterna 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 respectivo.

Cuando creas una vista de acciones 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 "arriba" (pasa "verdadero" para que se comporte como un botón).
  • setIcon() y setLogo() te permiten definir el ícono o el logotipo de la barra de acciones en 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 IU.

GridLayout

GridLayout es un nuevo grupo de vistas que coloca 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 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 manera secuencial en las filas y columnas de la cuadrícula. La orientación de GridLayout determina si los elementos secundarios secuenciales están distribuidos de forma predeterminada de forma horizontal o vertical. 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 muestras mediante GridLayout.

Vista Textura

TextureView es una vista nueva que te permite mostrar una transmisión de contenido, como un video o una escena 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 presionar) 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é activado y desactivado. El atributo android:text también te permite colocar una etiqueta junto al interruptor.

Para ver un ejemplo con interruptores, consulta el archivo de diseño switches.xml y sus respectivas actividades de interruptores .

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 extiende 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 del 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 la configuración de Wi-Fi y Bluetooth.

Temas del sistema

El tema predeterminado para todas las aplicaciones orientadas a Android 4.0 (mediante la configuración de targetSdkVersion o minSdkVersion en “14" o versiones posteriores) 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 esos temas 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 del menú, y establecer targetSdkVersion en "14" para aprovechar los comportamientos predeterminados más recientes del framework.

Controles para el nivel de visibilidad de la IU del sistema

Desde los inicios de Android, el sistema administra un componente de IU conocido como la barra de estado, que se encuentra en la parte superior de los teléfonos celulares para entregar información como la señal del proveedor, la hora y las notificaciones, entre otros. Android 3.0 agregó la barra del sistema para dispositivos tablet, que se encuentra en la parte inferior de la pantalla para proporcionar los controles de navegación del sistema (Inicio, Atrás, etc.) y también una interfaz para los elementos que tradicionalmente proporciona la barra de estado. En Android 4.0, el sistema proporciona un nuevo tipo de IU del sistema llamada barra de navegación. Podrías considerar la barra de navegación 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 y los controles de configuración de la barra del sistema. 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 la 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 para 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 mostrarse en cuanto el sistema recibe la entrada del usuario. Por lo tanto, este modo es útil principalmente para la reproducción de video y 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 tu 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, ya no se aplicarán sus marcas.

Para sincronizar otros eventos en tu actividad con cambios de visibilidad en la IU del sistema (por ejemplo, ocultar la barra de acciones o bien otros controles 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 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 con 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 permitir interacciones más enriquecidas mediante el uso de dispositivos de puntero (como un mouse o algún otro dispositivo que dirija un cursor en pantalla).

Para recibir eventos de desplazamiento en una vista, implementa View.OnHoverListener y regístralo con setOnHoverListener(). Cuando se produce un evento de colocar el cursor en la vista, el objeto de escucha recibe una llamada a onHover(), lo que 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 debe mostrar el valor "true" a partir de onHover() si controla el evento de colocar el cursor sobre él. Si el objeto de escucha muestra el valor falso, el evento de colocar el cursor sobre un elemento se enviará a la vista superior como de costumbre.

Si tu aplicación usa botones o algún otro widget que cambia 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 sobre el digitalizador, las aplicaciones reciben eventos de desplazamiento del mismo modo que lo harían cuando el puntero del mouse se mueve por la pantalla cuando no se presiona ningún botón.

Tu aplicación puede distinguir entre la entrada del dedo, el mouse, la pluma stylus y el 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 consultas 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 la pluma stylus se presionan mediante 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 adelantar del mouse se asignan automáticamente a las teclas KEYCODE_BACK y KEYCODE_FORWARD. Tu aplicación puede controlar estas teclas para admitir el botón del mouse según la navegación hacia atrás y hacia adelante.

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, y el ángulo de inclinación y 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 a los emisores establecer o obtener 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 y obtenga valores de la propiedad sin conocer los detalles de cuáles son los campos o métodos.

Por ejemplo, si deseas establecer el valor del campo bar en el objeto foo, debes hacerlo antes:

Kotlin

foo.bar = value

Java

foo.bar = value;

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

Kotlin

foo.setBar(value)

Java

foo.setBar(value);

Sin embargo, si deseas pasar la instancia de foo y que otro código configure el valor bar, no hay manera de hacerlo en versiones anteriores a 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.).

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

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 configuró targetSdkVersion o minSdkVersion en “14" o versiones posteriores. Por lo general, la aceleración de hardware da como resultado animaciones y desplazamientos más fluidos, y, en general, un mejor rendimiento y una respuesta a la interacción del usuario.

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 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 porque 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 “Referencias locales y globales” en Sugerencias de JNI. En Android 4.0, CheckJNI se mejoró para detectar estos errores. Mira el Blog para desarrolladores de Android para conocer la 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 si se establece targetSdkVersion o minSdkVersion en “14" o una versión posterior. Si has configurado 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 necesaria 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 facilita la prueba de las 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. Dado que la plataforma de Android 3.x solo está disponible para dispositivos de pantalla grande, si desarrollaste apps 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 pasaste por alto 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 sobre fragmentos.
  • 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 del menú. Consulta la guía para desarrolladores sobre la barra de acciones.
  • Loader: Es un componente de framework que facilita la carga asíncrona de datos en combinación con 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 View 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 sencillas 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 puedes escribir en C (estándar C99), lo que proporciona el tipo de rendimiento que esperas de un entorno nativo, a la vez que permanece 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 de OpenGL para tu aplicación si configuras {android:hardwareAccelerated="true"} en el elemento <application> de tu manifiesto o para elementos <activity> individuales. De esta manera, se obtienen animaciones y desplazamientos más fluidos, y un mejor rendimiento y una mejor respuesta a la interacción del usuario en general.

    Nota: Si configuras las opciones minSdkVersion o targetSdkVersion de tu aplicación en "14" o una versión posterior, la aceleración de hardware estará habilitada de forma predeterminada.

  • Y mucho, mucho más. Consulta las notas de la plataforma de 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 del dispositivo y el host 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, envío para hablar, conferencias y transmisión de audio pueden usar la API para 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 Android 3.1 para ver muchas más APIs nuevas.
Android 3.2
  • Las pantallas nuevas 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 hacerlo por sus tamaños de pantalla generalizados (como grande o extragrande). Por ejemplo, esto es importante para ayudarte a distinguir entre un dispositivo de 5" y uno de 7", que tradicionalmente se agruparían como pantallas "grandes". Consulta la entrada de blog New Tools for Manage 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, llamado "nivel de API", permite que el sistema determine correctamente si una aplicación es compatible con él antes de instalarla.

Para usar las APIs de 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?