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 los usuarios y los 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 en SDK Manager como una imagen del sistema que puedes ejecutar en el emulador de Android y como 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 configurar tu targetSdkVersion como "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 admitir versiones anteriores si agregas condiciones a tu código que verifiquen el nivel de API del sistema antes de ejecutar APIs no compatibles con tu minSdkVersion. Para obtener más información sobre cómo mantener la retrocompatibilidad, consulta Cómo crear IU retrocompatibles.

Para obtener más información sobre el funcionamiento de los niveles de API, consulta ¿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 a los procesos en primer plano más información 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 una ContentProviderClient que puede ser "inestable", de modo que tu app no fallará si lo hace el proveedor de contenido. Resulta útil cuando interactúas con proveedores de contenido en una app independiente.

Fondos de pantalla animados

Nuevo protocolo de intents para iniciar directamente la actividad de vista previa del fondo animado de modo que puedas ayudar a los usuarios a seleccionarlo fácilmente sin forzarlos a salir de 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 mediante 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 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 (al mismo tiempo que 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; el sistema ahora controla ese evento y reanuda o crea la actividad adecuada.

Esta función es particularmente útil para situaciones en las que el usuario ingresa una de las actividades de tu app mediante un intent de "análisis detallado", como una notificación o un intent de una app diferente (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 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 no ser así, 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 esta crea una tarea nueva para ella, el sistema inserta la pila de actividades principales en la tarea. Por lo tanto, cuando se presiona 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, compila un Intent básico a fin de 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 haya navegado naturalmente por cada actividad. Si en alguna de las actividades superiores normalmente se 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 ve un álbum en una app de música, navegar hacia arriba podría llevarlo a una actividad que enumera todos los álbumes de un género musical elegido. En este caso, si se debe crear la pila, es necesario que le informes a la actividad principal a qué género pertenece el álbum actual para que este pueda mostrar la lista adecuada como si el usuario proviniera realmente 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 la TaskStackBuilder, agrega los objetos Intent que se usan para crear las actividades superiores en su orden lógico a partir de la parte superior del árbol de actividades. Por lo tanto, la última Intent agregada al array interno es el elemento superior directo de la actividad actual. Si deseas modificar el Intent para el 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()
Anótalo para realizar una acción personalizada cuando el usuario presione el botón Arriba.
navigateUpTo(Intent)
Llama a este método para finalizar la actividad actual y dirigirte 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 actividad especificada con el intent.
getParentActivityIntent()
Llama a este método 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 a fin de navegar hacia arriba. Muestra true 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 esto 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 de contenido multimedia de bajo nivel para codificar y decodificar tu contenido multimedia. Para crear una instancia de un MediaCodec, llama a createEncoderByType() a fin de codificar contenido multimedia o 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 multimedia 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 que creas 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 estés listo para codificar o decodificar, llama a dequeueInputBuffer() a fin de obtener la posición de índice del ByteBuffer (desde el array de búferes de entrada) que debes usar para alimentar el contenido multimedia de origen. Después de completar el ByteBuffer con el contenido multimedia de origen, llama a queueInputBuffer() para liberar la propiedad del búfer.

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

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

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

Grabar audio cuando se 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 la definida por MediaPlayer) que, cuando se completa, activa la grabadora de audio para que comience a grabar. Por ejemplo, puedes usar esta funcionalidad para reproducir un tono de audio que indique el comienzo de una sesión de grabación, y la grabación se iniciará automáticamente para que no tengas que sincronizar manualmente el tono y el comienzo de la grabación.

Pistas de texto cronometradas

MediaPlayer ahora controla pistas de texto dentro y fuera de banda. Las pistas de texto en banda vienen como pistas de texto dentro de una fuente de contenido multimedia MP4 o 3GPP. Se pueden agregar pistas de texto fuera de banda como fuente de texto externa a través del método addTimedTextSource(). Después de agregar todas las fuentes de pistas de texto externas, 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 MediaPlayer, debes llamar a selectTrack() mediante la posición de índice de la pista que deseas 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 adicionales de procesamiento previo de audio 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 de 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 al 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 jugador en el momento en que se detenga el primero.

Router 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 indicará si el enfoque automático comenzó a moverse o si dejó de hacerlo.

Sonidos de la cámara

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

Para reproducir un sonido, 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 cargas útiles de gran tamaño 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 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, a fin de que puedas definir los URI que se compartirán en el momento del uso compartido. Esto es útil si los URI que se compartirán pueden variar según el contexto del usuario dentro de la actividad, mientras que llamar a setBeamPushUris() es útil cuando los URI para compartir no cambian y puedes definirlos con seguridad 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 de pares y conectarte a ellos a través de 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 dispositivos.

Para registrar tu servicio, primero debes crear un objeto NsdServiceInfo y definir sus diversas propiedades 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 pasando 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 Wi-Fi

Las APIs de P2P 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 que usan 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 un servicio por 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 WifiP2pManager.UpnpServiceResponseListener.

Antes de que puedas comenzar a descubrir servicios en los 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. La devolución de llamada recibida en cualquiera de los casos contiene un objeto WifiP2pDevice que representa al dispositivo de intercambio de tráfico.

Uso de red

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

Accesibilidad

APIs de servicio de accesibilidad

El alcance de las APIs del servicio de accesibilidad se incrementó de forma significativa en Android 4.1. Ahora, te permite compilar servicios que supervisan y responden a más eventos de entrada, como gestos complejos mediante onGesture() y otros eventos de entrada a través de 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 desplazarse por 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 de apps personalizable

Cuando compilas una app para Android, ahora puedes personalizar los esquemas de navegación. Para ello, busca elementos enfocables y widgets de entrada con findFocus() y focusSearch(), y establece 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 independiente 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 a ellos.

Compatibilidad con estilos de strings y HTML

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 con la lectura 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.
  • Diversas 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 otra manera no serían posibles con el estándar IEEE 754-2008 completo.

Nota: El motor de gráficos experimental de Renderscript ahora es obsoleto.

Animación

Animaciones de inicio de 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 luego puedes 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 cuando se abre la actividad:

makeScaleUpAnimation()
Crea una animación que escala verticalmente la ventana de la actividad desde una posición de inicio especificada en la pantalla y un tamaño de inicio especificado. Por ejemplo, la pantalla principal en Android 4.1 lo usa 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: uno que define la animación para la apertura de la actividad y otra para la actividad que se detiene.

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, incluido el tiempo transcurrido total 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 tres estilos nuevos para tu notificación, cada uno de los cuales ofrece una región de contenido más grande. Para especificar el estilo de tu región de contenido grande, pasa 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 strings, como fragmentos de varios correos electrónicos.
Acciones de la notificación

Ahora puedes mostrar hasta dos botones de acción 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 usa 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 indicarle 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 constantes PRIORITY_* en la clase Notification. El valor predeterminado es PRIORITY_DEFAULT, y hay dos niveles superiores y dos inferiores.

Las notificaciones de prioridad alta son aquellas 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 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 llamando a setSystemUiVisibility() y pasando 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 (cuando habilitas android:windowActionBarOverlay), esta marca también oculta la barra de acciones y lo hace con una animación coordinada cuando se ocultan y se muestran las dos.
SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
Configura el diseño de tu actividad para que use la misma área de la pantalla que está disponible cuando habilitas SYSTEM_UI_FLAG_FULLSCREEN, incluso si los elementos de la IU del sistema aún están visibles. Si bien la IU del sistema superpone 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 oculta o aparece.
SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
Configura 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 aún están visibles. Si bien la barra de navegación superpone 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 que agregues 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 hubiera cambiado, incluso después de ocultar toda la IU del sistema.

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

Vistas remotas

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

Familias de fuentes

Android 4.1 agrega varias variantes más del estilo de fuente Roboto para 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-cursiva
  • Claro
  • Cursiva claro
  • Condensado regular
  • Cursiva condensada
  • Negrita condensada
  • Condensada en negrita y cursiva

Puedes aplicar cualquiera de estos 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 "bold" y "italic" de textStyle. Puedes aplicar ambas 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

Varios dispositivos de entrada

La nueva clase InputManager te permite consultar el conjunto de dispositivos de entrada que están conectados actualmente y registrarte para recibir una notificación cuando se agrega, cambia o quita un dispositivo nuevo. Esto es particularmente útil si estás creando 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 recibir un aviso cuando se conecten, cambien o 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 capacidades 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 tienen acceso de lectura. Esto se cambiará en una versión futura para requerir que las aplicaciones soliciten acceso de lectura de forma explícita 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 y comprueben cómo se comportará 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 necesario para 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 funciones para dispositivos destinados 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, con el usuario sentado lejos; la forma de entrada predominante es un pad direccional; y, por lo general, no se ve a través del tacto ni con un mouse o puntero.