Android 4.1 API

Nivel de API: 16

Android 4.1 (JELLY_BEAN) es una progresión de la plataforma que ofrece un mejor rendimiento y una experiencia del usuario mejorada. Agrega nuevas funciones para usuarios y desarrolladores de apps. En este documento, se proporciona una introducción a las nuevas APIs más notables y útiles para los desarrolladores de apps.

Como desarrollador de apps, Android 4.1 está disponible desde SDK Manager como una imagen del sistema que puedes ejecutar en Android Emulator y en una plataforma de SDK en la que puedes compilar tu app. Debes descargar la imagen del sistema y la plataforma lo antes posible para compilar y probar tu app en Android 4.1.

A fin de optimizar mejor tu app para los dispositivos que ejecutan Android 4.1, debes establecer tu targetSdkVersion en "16", instalarla en una imagen del sistema de Android 4.1, probarla y, luego, publicar una actualización con este cambio.

Puedes usar APIs en Android 4.1 y, al mismo tiempo, admitir versiones anteriores. Para ello, debes agregar condiciones a tu código que verifiquen el nivel de API del sistema antes de ejecutar las APIs no compatibles con tu minSdkVersion. Para obtener más información sobre cómo mantener la retrocompatibilidad, consulta Cómo crear IU retrocompatibles.

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

Componentes de la app

Servicios aislados

Si especificas android:isolatedProcess="true" en la etiqueta <service>, tu Service se ejecutará en su propio proceso de ID de usuario aislado que no tiene permisos propios.

Administración de la memoria

Las nuevas constantes ComponentCallbacks2, como TRIM_MEMORY_RUNNING_LOW y TRIM_MEMORY_RUNNING_CRITICAL, proporcionan más información a los procesos en primer plano sobre el estado de la memoria antes de que el sistema llame a onLowMemory().

El nuevo método getMyMemoryState(ActivityManager.RunningAppProcessInfo) te permite recuperar el estado general de la memoria.

Proveedores de contenido

Un nuevo método, acquireUnstableContentProviderClient(), te permite acceder a un ContentProviderClient que puede ser "inestable", de modo que tu app no falle si el proveedor de contenido lo hace. Resulta útil cuando interactúas con proveedores de contenido en otra app.

Fondos de pantalla animados

Nuevo protocolo de intents para iniciar directamente la actividad de vista previa del fondo animado para que puedas ayudar a los usuarios a seleccionar fácilmente tu fondo animado sin obligarlos a abandonar tu app y navegar por el selector de fondo de pantalla de la pantalla principal.

Para iniciar el selector de fondo animado, llama a startActivity() con un Intent usando ACTION_CHANGE_LIVE_WALLPAPER y un elemento adicional que especifique el fondo animado ComponentName como una cadena en EXTRA_LIVE_WALLPAPER_COMPONENT.

Navegación a la pila de apps

Android 4.1 facilita la implementación de los patrones de diseño adecuados para la navegación hacia arriba. Lo único que debes hacer es agregar el elemento android:parentActivityName a cada elemento <activity> de tu archivo de manifiesto. El sistema usa esta información para abrir la actividad correspondiente cuando el usuario presiona el botón Arriba de la barra de acciones (mientras finaliza la actividad actual). Por lo tanto, si declaras el android:parentActivityName para cada actividad, no necesitas el método onOptionsItemSelected() para controlar los eventos de clic en el ícono de la app de la barra de acciones, ya que el sistema ahora controla ese evento y reanuda o crea la actividad correspondiente.

Esta función es particularmente útil para escenarios en los que el usuario ingresa a una de las actividades de tu app mediante un intent de "análisis detallado", como una notificación o un intent de otra app (como se describe en la guía de diseño Cómo navegar entre apps). Cuando el usuario ingresa a tu actividad de esta manera, es posible que tu app no tenga naturalmente una pila de actividades de actividades que se pueda reanudar a medida que el usuario navega hacia arriba. Sin embargo, cuando proporcionas el atributo android:parentActivityName para tus actividades, el sistema reconoce si tu app ya contiene o no una pila de actividades principales y, de lo contrario, construye una pila de actividades sintética que contiene todas las actividades superiores.

Nota: Cuando el usuario ingresa una actividad profunda en tu app y crea una tarea nueva para ella, el sistema inserta la pila de actividades principales en la tarea. Por lo tanto, si presionas el botón Atrás, también se navega hacia atrás por la pila de actividades superiores.

Cuando el sistema crea una pila de actividades sintética para tu app, crea un Intent básico para crear una instancia nueva de cada actividad superior. Por lo tanto, no hay un estado guardado para las actividades superiores como se espera que el usuario navegó de forma natural por cada actividad. Si alguna de las actividades superiores normalmente muestra una IU que depende del contexto del usuario, faltará esa información de contexto y deberás entregarla cuando el usuario navegue hacia atrás en la pila. Por ejemplo, si el usuario está viendo un álbum en una app de música, al navegar hacia arriba, podría llegar a una actividad que enumera todos los álbumes de un género musical elegido. En este caso, si es necesario crear la pila, es necesario que informes a la actividad superior a qué género pertenece el álbum actual para que el superior pueda mostrar la lista adecuada como si el usuario efectivamente provenga de esa actividad. Para entregar esa información a una actividad superior sintética, debes anular el método onPrepareNavigateUpTaskStack(). Esto te proporciona un objeto TaskStackBuilder que el sistema creó para sintetizar las actividades superiores. TaskStackBuilder contiene objetos Intent que el sistema usa para crear cada actividad superior. En tu implementación de onPrepareNavigateUpTaskStack(), puedes modificar el Intent apropiado para agregar datos adicionales que la actividad superior puede usar para determinar el contexto apropiado y mostrar la IU adecuada.

Cuando el sistema crea el TaskStackBuilder, agrega los objetos Intent que se usan para crear las actividades superiores en su orden lógico comenzando desde la parte superior del árbol de actividades. Por lo tanto, el último Intent agregado al array interno es el elemento superior directo de la actividad actual. Si deseas modificar el Intent del elemento superior de la actividad, primero determina la longitud del array con getIntentCount() y pasa ese valor a editIntentAt().

Si la estructura de tu app es más compleja, hay varias otras APIs disponibles que te permiten controlar el comportamiento de la navegación hacia arriba y personalizar por completo la pila de actividades sintética. Algunas de las APIs que te brindan control adicional incluyen las siguientes:

onNavigateUp()
Anula esta acción para realizar una acción personalizada cuando el usuario presione el botón Arriba.
navigateUpTo(Intent)
Llámalo para finalizar la actividad actual y ve a la actividad indicada por el Intent proporcionado. Si la actividad existe en la pila de actividades, pero no es el superior más cercano, también se finalizarán todas las demás actividades entre la actividad actual y la que se especifique con el intent.
getParentActivityIntent()
Llámalo para obtener el Intent que iniciará el elemento superior lógico para la actividad actual.
shouldUpRecreateTask(Intent)
Llama a este método para consultar si se debe crear una pila de actividades sintética para navegar hacia arriba. El resultado es verdadero si se debe crear una pila sintética y falso si ya existe la pila adecuada.
finishAffinity()
Llama a este método para finalizar la actividad actual y todas las actividades superiores con la misma afinidad de tarea que están encadenadas a la actividad actual. Si anulas los comportamientos predeterminados, como onNavigateUp(), debes llamar a este método cuando crees una pila de actividades sintética en la navegación hacia arriba.
onCreateNavigateUpTaskStack
Anula esta opción si necesitas controlar por completo cómo se crea la pila de tareas sintética. En cambio, si solo quieres agregar datos adicionales a los intents de tu pila de actividades, debes anular onPrepareNavigateUpTaskStack().

Sin embargo, la mayoría de las apps no necesitan usar estas APIs ni implementar onPrepareNavigateUpTaskStack(), pero pueden lograr el comportamiento correcto con solo agregar android:parentActivityName a cada elemento <activity>.

Multimedia

Códecs de archivos multimedia

La clase MediaCodec proporciona acceso a códecs multimedia de bajo nivel para codificar y decodificar tu contenido multimedia. Si deseas crear una instancia de MediaCodec, llama a createEncoderByType() para codificar contenido multimedia o llama a createDecoderByType() para decodificarlo. Cada uno de estos métodos toma un tipo de MIME para el tipo de contenido multimedia que quieres codificar o decodificar, como "video/3gpp" o "audio/vorbis".

Con una instancia de MediaCodec creada, puedes llamar a configure() para especificar propiedades como el formato de medios o si el contenido está encriptado o no.

Ya sea que estés codificando o decodificando tu contenido multimedia, el resto del proceso es el mismo después de crear el MediaCodec. Primero, llama a getInputBuffers() para obtener un array de objetos ByteBuffer de entrada y a getOutputBuffers() para obtener un array de objetos ByteBuffer de salida.

Cuando tengas todo listo para codificar o decodificar, llama a dequeueInputBuffer() a fin de obtener la posición de índice de ByteBuffer (del array de búferes de entrada) que debes usar para ingresar en el contenido multimedia de origen. Después de completar el ByteBuffer con el contenido multimedia de origen, libera la propiedad del búfer llamando a queueInputBuffer().

Del mismo modo, para el búfer de salida, llama a dequeueOutputBuffer() a fin de obtener la posición de índice del ByteBuffer en el que recibirás los resultados. Después de leer el resultado de ByteBuffer, libera la propiedad mediante una llamada a releaseOutputBuffer().

Puedes controlar los datos multimedia encriptados en los códecs si llamas a queueSecureInputBuffer() junto con las APIs de MediaCrypto, en lugar de queueInputBuffer() normal.

Para obtener más información sobre cómo usar códecs, consulta la documentación de MediaCodec.

Graba audio cuando se te indique

El nuevo método startRecording() te permite comenzar a grabar audio en función de una indicación definida por un MediaSyncEvent. MediaSyncEvent especifica una sesión de audio (como una definida por MediaPlayer) que, cuando se completa, activa la grabadora de audio para comenzar a grabar. Por ejemplo, puedes usar esta funcionalidad para reproducir un tono de audio que indique el inicio de una sesión de grabación y esta se iniciará automáticamente para que no tengas que sincronizar manualmente el tono y el comienzo de la grabación.

Pistas de texto temporizadas

MediaPlayer ahora controla las pistas de texto dentro y fuera de banda. Las pistas de texto en banda se incluyen como pistas de texto dentro de una fuente de medios MP4 o 3GPP. Se pueden agregar pistas de texto fuera de banda como una fuente de texto externa mediante el método addTimedTextSource(). Después de agregar todas las fuentes externas de pistas de texto, se debe llamar a getTrackInfo() para obtener la lista actualizada de todas las pistas disponibles en una fuente de datos.

Para configurar el segmento que se usará con el MediaPlayer, debes llamar a selectTrack() mediante la posición del índice del segmento que desees usar.

Si quieres recibir una notificación cuando la pista de texto esté lista para reproducirse, implementa la interfaz MediaPlayer.OnTimedTextListener y pásala a setOnTimedTextListener().

Efectos de audio

La clase AudioEffect ahora admite tipos de procesamiento previo de audio adicionales cuando se captura audio:

  • El cancelador de eco acústico (AEC) con AcousticEchoCanceler quita la contribución de la señal recibida de la parte remota desde la señal de audio capturada.
  • El control automático de ganancia (AGC) con AutomaticGainControl normaliza automáticamente la salida de la señal capturada.
  • El Supresor de ruido (NS) con NoiseSuppressor quita el ruido de fondo de la señal capturada.

Puedes aplicar estos efectos del preprocesador en el audio capturado con un AudioRecord mediante una de las subclases AudioEffect.

Nota: No se garantiza que todos los dispositivos admitan estos efectos, por lo que siempre debes verificar la disponibilidad primero llamando a isAvailable() en la clase de efecto de audio correspondiente.

Reproducción sin interrupciones

Ahora puedes realizar una reproducción sin espacios entre dos objetos MediaPlayer separados. En cualquier momento antes de que finalice tu primer MediaPlayer, llama a setNextMediaPlayer(), y Android intentará iniciar el segundo reproductor en el momento en que se detenga el primero.

Router de contenido multimedia. Las nuevas APIs de MediaRouter, MediaRouteActionProvider y MediaRouteButton proporcionan IU y mecanismos estándar para elegir dónde reproducir el contenido multimedia.

Cámara

Movimiento de enfoque automático

La nueva interfaz Camera.AutoFocusMoveCallback te permite escuchar los cambios en el movimiento del enfoque automático. Puedes registrar tu interfaz con setAutoFocusMoveCallback(). Luego, cuando la cámara esté en un modo de enfoque automático continuo (FOCUS_MODE_CONTINUOUS_VIDEO o FOCUS_MODE_CONTINUOUS_PICTURE), recibirás una llamada a onAutoFocusMoving(), que te indica si el enfoque automático comenzó a moverse o dejó de moverse.

Sonidos de la cámara

La clase MediaActionSound proporciona un conjunto simple de APIs para producir sonidos estándar creados por la cámara y otras acciones multimedia. Debes usar estas APIs para reproducir el sonido apropiado cuando crees una cámara de video o fija personalizada.

Para reproducir un sonido, simplemente crea una instancia de un objeto MediaActionSound, llama a load() para precargar el sonido deseado y, luego, en el momento apropiado, llama a play().

Conectividad

Android Beam

Android BeamTM ahora admite transferencias de grandes cargas útiles a través de Bluetooth. Cuando defines los datos que se transferirán con el nuevo método setBeamPushUris() o la nueva interfaz de devolución de llamada NfcAdapter.CreateBeamUrisCallback, Android transfiere la transferencia de datos a Bluetooth o a otro transporte alternativo para lograr velocidades de transferencia más rápidas. Esto es especialmente útil para cargas útiles grandes, como archivos de imagen y audio, y no requiere una vinculación visible entre los dispositivos. Tu app no requiere ninguna acción adicional para aprovechar las transferencias por Bluetooth.

El método setBeamPushUris() toma un array de objetos Uri que especifican los datos que deseas transferir desde tu app. Como alternativa, puedes implementar la interfaz NfcAdapter.CreateBeamUrisCallback, que puedes especificar para tu actividad llamando a setBeamPushUrisCallback().

Cuando se usa la interfaz de devolución de llamada, el sistema llama al método createBeamUris() de la interfaz cuando el usuario ejecuta un uso compartido con Android Beam, de modo que puedas definir los URIs que se compartirán en el momento de compartir. Esto es útil si los URIs para compartir pueden variar según el contexto del usuario dentro de la actividad, mientras que llamar a setBeamPushUris() es útil cuando los URIs para compartir no cambian y puedes definirlos con anticipación.

Detección del servicio de red

Android 4.1 agrega compatibilidad con el descubrimiento de servicios multidifusión basados en DNS, que te permite buscar servicios ofrecidos por dispositivos similares y conectarte a ellos mediante Wi-Fi, como dispositivos móviles, impresoras, cámaras, reproductores multimedia y otros que están registrados en la red local.

El nuevo paquete android.net.nsd contiene las nuevas APIs que te permiten transmitir tus servicios en la red local, descubrir dispositivos locales en la red y conectarte a los dispositivos.

Para registrar tu servicio, primero debes crear un objeto NsdServiceInfo y definir las diversas propiedades del servicio con métodos como setServiceName(), setServiceType() y setPort().

Luego, debes implementar NsdManager.RegistrationListener y pasarlo a registerService() con tu NsdServiceInfo.

Para descubrir servicios en la red, implementa NsdManager.DiscoveryListener y pásalo a discoverServices().

Cuando tu NsdManager.DiscoveryListener recibe devoluciones de llamada sobre servicios encontrados, debes resolver el servicio llamando a resolveService() y pasarle una implementación de NsdManager.ResolveListener que reciba un objeto NsdServiceInfo que contenga información sobre el servicio descubierto, lo que te permitirá iniciar la conexión.

Detección de servicio P2P de Wi-Fi

Las APIs de P2P de Wi-Fi se mejoraron en Android 4.1 para admitir el descubrimiento de servicios de asociación previa en WifiP2pManager. Esto te permite descubrir y filtrar dispositivos cercanos por servicios mediante Wi-Fi P2P antes de conectarte a uno, mientras que la detección de servicios de red te permite descubrir un servicio en una red conectada existente (como una red Wi-Fi local).

Para transmitir tu app como servicio a través de Wi-Fi de modo que otros dispositivos puedan descubrirla y conectarse a ella, llama a addLocalService() con un objeto WifiP2pServiceInfo que describa los servicios de tu app.

Para iniciar el descubrimiento de dispositivos cercanos a través de Wi-Fi, primero debes decidir si te comunicarás mediante Bonjour o Upnp. Para usar Bonjour, primero configura algunos objetos de escucha de devolución de llamada con setDnsSdResponseListeners(), que toma un WifiP2pManager.DnsSdServiceResponseListener y un WifiP2pManager.DnsSdTxtRecordListener. Para usar Upnp, llama a setUpnpServiceResponseListener(), que toma un objeto WifiP2pManager.UpnpServiceResponseListener.

Antes de comenzar a descubrir servicios en dispositivos locales, también debes llamar a addServiceRequest(). Cuando el WifiP2pManager.ActionListener que pasas a este método recibe una devolución de llamada exitosa, puedes comenzar a descubrir servicios en dispositivos locales llamando a discoverServices().

Cuando se detecten servicios locales, recibirás una devolución de llamada a WifiP2pManager.DnsSdServiceResponseListener o WifiP2pManager.UpnpServiceResponseListener, según si te registraste para usar Bonjour o Upnp. En ambos casos, la devolución de llamada que se recibe contiene un objeto WifiP2pDevice que representa el dispositivo de intercambio de tráfico.

Uso de red

El nuevo método isActiveNetworkMetered() te permite comprobar si el dispositivo está conectado a una red de uso medido. Si verificas este estado antes de realizar transacciones intensivas de red, puedes ayudar a administrar el uso de datos que podría costarle dinero a tus usuarios y tomar decisiones fundamentadas sobre si realizar las transacciones ahora o más tarde (por ejemplo, cuando el dispositivo se conecta a una red Wi-Fi).

Accesibilidad

APIs de servicio de accesibilidad

El alcance de las APIs del servicio de accesibilidad se incrementó de manera significativa en Android 4.1. Ahora te permite compilar servicios que supervisan y responden más eventos de entrada, como gestos complejos con onGesture() y otros eventos de entrada mediante adiciones a las clases AccessibilityEvent, AccessibilityNodeInfo y AccessibilityRecord.

Los servicios de accesibilidad también pueden realizar acciones en nombre del usuario, como hacer clic, desplazarse y recorrer el texto con performAction y setMovementGranularities. El método performGlobalAction() también permite que los servicios realicen acciones, como Atrás, Inicio, y abrir apps y notificaciones recientes.

Navegación personalizable en la app

Cuando compilas una app para Android, ahora puedes personalizar los esquemas de navegación buscando elementos enfocables y widgets de entrada con findFocus() y focusSearch(), y establecer el enfoque con setAccessibilityFocused().

Widgets más accesibles

La nueva clase android.view.accessibility.AccessibilityNodeProvider te permite mostrar vistas personalizadas complejas a los servicios de accesibilidad para que puedan presentar la información de una manera más accesible. android.view.accessibility.AccessibilityNodeProvider permite que un widget de usuario con contenido avanzado, como una cuadrícula de calendario, presente una estructura semántica lógica para los servicios de accesibilidad que está completamente separada de la estructura de diseño del widget. Esta estructura semántica permite que los servicios de accesibilidad presenten un modelo de interacción más útil para los usuarios con discapacidad visual.

Copiar y pegar

Cómo copiar y pegar con intents

Ahora puedes asociar un objeto ClipData con un Intent usando el método setClipData(). Esto es muy útil cuando se usa un intent para transferir varios URI content: a otra aplicación, como cuando se comparten varios documentos. Los URI de content: proporcionados de esta manera también respetarán las marcas del intent para ofrecer acceso de lectura o escritura, lo que te permite otorgar acceso a varios URI en un intent. Cuando se inicia un intent ACTION_SEND o ACTION_SEND_MULTIPLE, los URI proporcionados en el intent ahora se propagan automáticamente al ClipData para que el receptor pueda tener acceso otorgado.

Compatibilidad con estilos HTML y de cadena

La clase ClipData ahora admite texto con estilo (ya sea como strings con estilo HTML o Android). Puedes agregar texto con estilo HTML a ClipData con newHtmlText().

RenderScript

Se mejoró la funcionalidad de procesamiento de Renderscript con las siguientes funciones:

  • Compatibilidad con varios kernels dentro de una secuencia de comandos.
  • Compatibilidad para leer desde la asignación con muestras filtradas del procesamiento en una nueva API de secuencia de comandos rsSample.
  • Se admiten diferentes niveles de precisión de FP en #pragma.
  • Compatibilidad con la consulta de información adicional de objetos RS desde una secuencia de comandos de procesamiento.
  • Se implementaron varias mejoras en el rendimiento.

También hay nuevos pragmas disponibles para definir la precisión de punto flotante que requieren tus RenderScripts de procesamiento. Esto te permite habilitar operaciones similares a las de NEON, como operaciones rápidas de matemáticas de vector en la ruta de acceso de la CPU, que de otro modo no serían posibles con el estándar IEEE 754-2008 completo.

Nota: El motor de gráficos experimental de Renderscript ya no está disponible.

Animación

Animaciones de inicio de la actividad

Ahora puedes iniciar un objeto Activity con animaciones de zoom o tus propias animaciones personalizadas. Para especificar la animación que deseas, usa las APIs de ActivityOptions para compilar un Bundle que puedas pasar a cualquiera de los métodos que inician una actividad, como startActivity().

La clase ActivityOptions incluye un método diferente para cada tipo de animación que quieras mostrar a medida que se abre tu actividad:

makeScaleUpAnimation()
Crea una animación que aumenta la escala de la ventana de actividad desde una posición de inicio especificada en la pantalla y un tamaño de inicio determinado. Por ejemplo, la pantalla principal en Android 4.1 usa esto cuando se abre una app.
makeThumbnailScaleUpAnimation()
Crea una animación que escala verticalmente la ventana de la actividad a partir de una posición específica y una imagen en miniatura proporcionada. Por ejemplo, la ventana Apps recientes de Android 4.1 la usa cuando regresa a una app.
makeCustomAnimation()
Crea una animación definida por tus propios recursos: una que define la animación para la apertura de la actividad y otra para la actividad que se está deteniendo.

Animador de tiempo

El nuevo TimeAnimator proporciona un mecanismo de devolución de llamada simple con el TimeAnimator.TimeListener que te notifica sobre cada fotograma de la animación. Con este Animator, no hay duración, interpolación ni configuración de valor de objeto. La devolución de llamada del objeto de escucha recibe información de cada fotograma, incluidos el tiempo total transcurrido y el tiempo transcurrido desde el fotograma de animación anterior.

Interfaz de usuario

Notificaciones

En Android 4.1, puedes crear notificaciones con regiones de contenido más grandes, vistas previas de imágenes grandes, varios botones de acción y prioridad configurable.

Estilos de notificaciones

El nuevo método setStyle() te permite especificar uno de los tres estilos nuevos para tu notificación, que ofrecen una región de contenido más grande. Para especificar el diseño de tu región de contenido grande, pasa a setStyle() uno de los siguientes objetos:

Notification.BigPictureStyle
Para notificaciones que incluyen una imagen grande adjunta.
Notification.BigTextStyle
Para las notificaciones que incluyen mucho texto, como un solo correo electrónico.
Notification.InboxStyle
Para notificaciones que incluyen una lista de cadenas, como fragmentos de varios correos electrónicos.
Acciones de la notificación

Ahora hay compatibilidad para hasta dos botones de acción que aparecen en la parte inferior del mensaje de notificación, ya sea que la notificación use el estilo normal o más grande.

Para agregar un botón de acción, llama a addAction(). Este método tiene tres argumentos: un recurso de elemento de diseño para un ícono, texto para el botón y un PendingIntent que define la acción que se realizará.

Prioridades

Ahora puedes indicar al sistema la importancia de tu notificación para afectar su orden en la lista estableciendo la prioridad con setPriority(). Puedes pasar este uno de los cinco niveles de prioridad diferentes definidos por las constantes PRIORITY_* en la clase Notification. El valor predeterminado es PRIORITY_DEFAULT, y hay dos niveles superiores y dos niveles inferiores.

Las notificaciones de prioridad alta son respuestas a las que los usuarios generalmente desean responder rápidamente, como un nuevo mensaje instantáneo, un mensaje de texto o un recordatorio de evento inminente. Las notificaciones de prioridad baja incluyen eventos de calendario vencidos o promociones de apps.

Controles para la IU del sistema

Android 4.0 (Ice Cream Sandwich) agregó nuevas marcas para controlar la visibilidad de los elementos de la IU del sistema, como atenuar la apariencia de la barra del sistema o hacer que desaparezca por completo en los teléfonos celulares. Android 4.1 agrega algunas marcas más que te permiten controlar aún más la apariencia de los elementos de la IU del sistema y el diseño de tu actividad en relación con ellos. Para ello, llama a setSystemUiVisibility() y pasa las siguientes marcas:

SYSTEM_UI_FLAG_FULLSCREEN
Oculta la IU no crítica del sistema (como la barra de estado). Si tu actividad usa la barra de acciones en el modo de superposición (al habilitar android:windowActionBarOverlay), esta marca también oculta la barra de acciones y lo hace con una animación coordinada cuando se oculta y muestra las dos.
SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
Configura el diseño de tu actividad para que use la misma área de pantalla que está disponible cuando habilitaste SYSTEM_UI_FLAG_FULLSCREEN, incluso si los elementos de la IU del sistema siguen visibles. Si bien la IU del sistema superpondrá partes de tu diseño, esto resulta útil si tu app a menudo oculta y muestra la IU del sistema con SYSTEM_UI_FLAG_FULLSCREEN, ya que evita que tu diseño se ajuste a los nuevos límites de diseño cada vez que la IU del sistema se oculta o aparece.
SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
Establece el diseño de tu actividad para que use la misma área de pantalla que está disponible cuando habilitaste SYSTEM_UI_FLAG_HIDE_NAVIGATION (agregado en Android 4.0) incluso si los elementos de la IU del sistema siguen siendo visibles. Si bien la barra de navegación superpondrá partes de tu diseño, esto resulta útil si tu app a menudo oculta y muestra la barra de navegación con SYSTEM_UI_FLAG_HIDE_NAVIGATION, ya que evita que tu diseño se ajuste a los nuevos límites de diseño cada vez que la barra de navegación se oculta o aparece.
SYSTEM_UI_FLAG_LAYOUT_STABLE
Te recomendamos agregar esta marca si usas SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN o SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION para asegurarte de que, cuando llames a fitSystemWindows() en una vista, los límites definidos sean coherentes con respecto al espacio de pantalla disponible. Es decir, con esta marca establecida, fitSystemWindows() se comportará como si la visibilidad de los elementos de la IU del sistema no cambiara, incluso después de que ocultes toda la IU del sistema.

Para obtener más información sobre las otras marcas relacionadas de IU del sistema, lee sobre las agregadas en Android 4.0.

Vistas remotas

GridLayout y ViewStub ahora son vistas que se pueden usar de manera remota, por lo que puedes usarlas en diseños para los widgets de tu app y en los diseños personalizados de notificaciones.

Familias de fuentes

Android 4.1 agrega varias variantes más del estilo de fuente Roboto, lo que suma un total de 10 variantes, que las apps pueden usar. Ahora tus apps tienen acceso al conjunto completo de variantes ligeras y condensadas.

El conjunto completo de variantes de fuentes Roboto disponible es el siguiente:

  • Frecuente
  • Cursiva
  • Negrita
  • Negrita y cursiva
  • Claro
  • Cursiva clara
  • Condensado regular
  • Cursiva condensada
  • Negrita condensada
  • Negrita-cursiva resumida

Puedes aplicar cualquiera de ellos con el nuevo atributo fontFamily junto con el atributo textStyle.

Los valores admitidos para fontFamily son los siguientes:

  • "sans-serif" para Roboto normal
  • "sans-serif-light" para Roboto Light
  • "sans-serif-condensed" para Roboto Condensed

Luego, puedes aplicar negrita o cursiva con los valores textStyle, "bold" y "italic". Puedes aplicar ambos de la siguiente manera: android:textStyle="bold|italic".

También puedes usar Typeface.create(). Por ejemplo, Typeface.create("sans-serif-light", Typeface.NORMAL).

Framework de entrada

Múltiples dispositivos de entrada

La nueva clase InputManager te permite consultar el conjunto de dispositivos de entrada conectados actualmente y registrarte para recibir notificaciones cuando se agregue, cambie o quite un dispositivo nuevo. Esto es particularmente útil si estás compilando un juego que admite varios jugadores y quieres detectar cuántos controles están conectados y cuándo hay cambios en la cantidad de controles.

Puedes llamar a getInputDeviceIds() para consultar todos los dispositivos de entrada conectados. Se mostrará un array de números enteros, cada uno de los cuales es un ID para un dispositivo de entrada diferente. Luego, puedes llamar a getInputDevice() a fin de adquirir un InputDevice para un ID de dispositivo de entrada especificado.

Si deseas que se te informe cuando se conecten, cambien o se desconecten nuevos dispositivos de entrada, implementa la interfaz InputManager.InputDeviceListener y regístrala con registerInputDeviceListener().

Vibrar para controladores de entrada

Si los dispositivos de entrada conectados tienen sus propias funciones de vibración, ahora puedes controlar la vibración de esos dispositivos usando las APIs de Vibrator existentes con solo llamar a getVibrator() en InputDevice.

Permisos

Los siguientes son permisos nuevos:

READ_EXTERNAL_STORAGE
Proporciona acceso de lectura protegido al almacenamiento externo. De forma predeterminada, en Android 4.1, todas las aplicaciones todavía tienen acceso de lectura. Esto se cambiará en una versión futura para requerir que las aplicaciones soliciten acceso de lectura explícitamente con este permiso. Si tu aplicación ya solicita acceso de escritura, también obtendrá acceso de lectura automáticamente. Hay una nueva opción para desarrolladores que permite activar la restricción de acceso de lectura a fin de que los desarrolladores prueben sus aplicaciones con el comportamiento que tendrá Android en el futuro.
android.Manifest.permission.READ_USER_DICTIONARY
Permite que una aplicación lea el diccionario del usuario. Esto solo debería ser solicitado por un IME o un editor de diccionario como la app de Configuración.
READ_CALL_LOG
Permite que una aplicación lea el registro de llamadas del sistema que contiene información sobre llamadas entrantes y salientes.
WRITE_CALL_LOG
Permite que una aplicación modifique el registro de llamadas del sistema almacenado en el teléfono.
android.Manifest.permission.WRITE_USER_DICTIONARY
Permite que una aplicación escriba en el diccionario de palabras del usuario.

Funciones del dispositivo

Android 4.1 incluye una nueva declaración de función para dispositivos que se dedican a mostrar la interfaz de usuario en una pantalla de televisión: FEATURE_TELEVISION. Para declarar que tu app requiere una interfaz de televisión, declara esta función en tu archivo de manifiesto con el elemento <uses-feature>:

<manifest ... >
    <uses-feature android:name="android.hardware.type.television"
                  android:required="true" />
    ...
</manifest>

Esta función define "televisión" como una típica experiencia de televisión en una sala de estar: se muestra en una pantalla grande, en la que el usuario está sentado lejos y la forma de entrada predominante es un pad direccional; en general, no a través del tacto o de un mouse/dispositivo apuntador.