Android 4.1 API

Nivel de API: 16

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

Como desarrollador de apps, Android 4.1 está disponible para ti en SDK Manager como una imagen del sistema que puedes ejecutar en el emulador de Android y una plataforma de SDK con 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.

Para optimizar mejor tu app para dispositivos con Android 4.1, debes configurar tu targetSdkVersion en "16", instalarla en una imagen del sistema Android 4.1, probarla y, luego, publicar una actualización con este cambio.

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

Puedes encontrar más información sobre el funcionamiento de los niveles de API en ¿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 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 una app independiente.

Fondos de pantalla animados

Se agregó un 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 salir de tu app y navegar por el selector del fondo de pantalla de la pantalla principal.

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

Navegación de la pila de la app

Android 4.1 facilita mucho la implementación de los patrones de diseño adecuados para la navegación hacia arriba. Solo debes agregar android:parentActivityName a cada elemento <activity> de tu archivo de manifiesto. El sistema usa esta información para abrir la actividad adecuada cuando el usuario presiona el botón Arriba de la barra de acciones (y también finaliza la actividad actual). Por lo tanto, si declaras 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 acción. El sistema ahora controla ese evento y reanuda o crea la actividad adecuada.

Esto es particularmente útil en situaciones en las que el usuario ingresa a una de las actividades de tu app a través de un intent de "inmersión profunda", como desde una notificación o un intent de una app diferente (como se describe en la guía de diseño para Navegar entre apps). Cuando el usuario ingresa a tu actividad de esta manera, es posible que tu app no tenga, de forma predeterminada, 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 de actividades superiores y, en caso contrario, construye una pila sintética que contiene todas las actividades superiores.

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

Cuando el sistema crea una pila de actividades sintética para tu app, compila un Intent básico para crear una instancia nueva de cada actividad superior. Por lo tanto, no hay un estado guardado para las actividades principales como se esperaría si el usuario navegara naturalmente por cada actividad. Si alguna de las actividades superiores muestra normalmente una IU que depende del contexto del usuario, faltará esa información de contexto y debes entregarla cuando el usuario vuelva a navegar por la pila. Por ejemplo, si el usuario está viendo un álbum en una app de música, la navegación hacia arriba podría llevarlo a una actividad que enumere 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 superior a qué género pertenece el álbum actual para que el elemento superior pueda mostrar la lista adecuada como si el usuario realmente provenga de esa actividad. Para entregar esa información a una actividad superior sintética, debes anular el método onPrepareNavigateUpTaskStack(). Eso 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 adecuado para agregar datos adicionales que la actividad superior pueda usar para determinar el contexto adecuado 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 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. Estas son algunas de las APIs que te brindan control adicional:

onNavigateUp()
Anula esta acción para realizar una acción personalizada cuando el usuario presione el botón Arriba.
navigateUpTo(Intent)
Llama a esta función para finalizar la actividad actual y ir a la actividad indicada por el Intent proporcionado. Si la actividad existe en la pila de actividades, pero no es la actividad superior más cercana, todas las demás actividades entre la actividad actual y la especificada con el intent también finalizan.
getParentActivityIntent()
Llama a esto para obtener el Intent que iniciará el elemento superior lógico de la actividad actual.
shouldUpRecreateTask(Intent)
Llama a esta función para consultar si se debe crear una pila de actividades sintética para navegar hacia arriba. Muestra el valor "true" si se debe crear una pila sintética y "false" 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. Si solo quieres agregar algunos 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. Puedes crear una instancia de MediaCodec si llamas a createEncoderByType() para codificar contenido multimedia o a createDecoderByType() para decodificar contenido multimedia. Cada uno de estos métodos toma un tipo MIME para el tipo de contenido multimedia que deseas codificar o decodificar, como "video/3gpp" o "audio/vorbis".

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

Ya sea que codifiques o decodifiques 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 getOutputBuffers() para obtener un array de objetos ByteBuffer de salida.

Cuando tengas todo listo para codificar o decodificar, llama a dequeueInputBuffer() para obtener la posición del índice de 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 tu 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() para 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.

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

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

Graba audio a la señal

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

Pistas de texto cronometrado

MediaPlayer ahora controla pistas de texto dentro y fuera de banda. Las pistas de texto en banda aparecen como pistas de texto dentro de una fuente multimedia MP4 o 3GPP. Los segmentos de texto fuera de banda se pueden agregar como una fuente de texto externa a través del método addTimedTextSource(). Después de agregar todas las fuentes de segmentos de texto externos, se debe llamar a getTrackInfo() para obtener la lista actualizada de todos los segmentos disponibles en una fuente de datos.

Para configurar la pista que se usará con MediaPlayer, debes llamar a selectTrack() con la posición de índice de la pista que deseas usar.

Para 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 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 de la señal de audio capturada.
  • El control automático de ganancia (AGC) con AutomaticGainControl normaliza automáticamente el resultado 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 de AudioEffect.

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

Reproducción sin interrupciones

Ahora puedes realizar la reproducción sin interrupciones 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 contenido multimedia.

Cámara

Movimiento de enfoque automático

La nueva interfaz Camera.AutoFocusMoveCallback te permite detectar cambios en el movimiento del enfoque automático. Puedes registrar tu interfaz con setAutoFocusMoveCallback(). Luego, cuando la cámara esté en el 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 hace la cámara o cualquier otra acción multimedia. Debes usar estas APIs para reproducir el sonido adecuado cuando crees una cámara de fotos o de video 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 adecuado, llama a play().

Conectividad

Android Beam

Android BeamTM ahora admite transferencias de cargas útiles grandes por 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 entrega 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 necesita realizar ningún trabajo 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 para que puedas definir los URIs que se compartirán en el momento del uso compartido. Esto es útil si los URIs 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 de forma segura con anticipación.

Detección del servicio de red

Android 4.1 agrega compatibilidad con el descubrimiento de servicios basados en DNS multidifusión, que te permite encontrar y conectarte a servicios ofrecidos por dispositivos similares 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 ellos.

Para registrar tu servicio, primero debes crear un objeto NsdServiceInfo y definir sus distintas 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 los servicios encontrados, debes resolver el servicio llamando a resolveService() y pasándole 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.

Descubrimiento de servicios Wi-Fi P2P

Las APIs de Wi-Fi P2P se mejoraron en Android 4.1 para admitir el descubrimiento de servicios asociados previamente en WifiP2pManager. Esto te permite descubrir y filtrar dispositivos cercanos por servicios usando 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 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 con 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 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 correcta, puedes comenzar a descubrir servicios en dispositivos locales llamando a discoverServices().

Cuando se descubran los 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 cualquier caso contiene un objeto WifiP2pDevice que representa el dispositivo del par.

Uso de red

El nuevo método isActiveNetworkMetered() te permite verificar si el dispositivo está conectado actualmente a una red con medición. Si verificas este estado antes de realizar transacciones de red intensivas, podrás administrar el uso de datos que podría costarles dinero a los usuarios y tomar decisiones fundamentadas sobre si realizar las transacciones ahora o más tarde (como cuando el dispositivo se conecta a Wi-Fi).

Accesibilidad

APIs del servicio de accesibilidad

El alcance de las APIs de los servicios de accesibilidad aumentó significativamente en Android 4.1. Ahora, te permite compilar servicios que supervisen y respondan a más eventos de entrada, como gestos complejos con onGesture() y otros eventos de entrada a través de incorporaciones a las clases AccessibilityEvent, AccessibilityNodeInfo y AccessibilityRecord.

Los servicios de accesibilidad también pueden realizar acciones en nombre del usuario, como hacer clic, desplazar el contenido y avanzar por el texto con performAction y setMovementGranularities. El método performGlobalAction() también permite que los servicios realicen acciones, como Atrás, Página principal, 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 foco con setAccessibilityFocused().

Widgets más accesibles

La nueva clase android.view.accessibility.AccessibilityNodeProvider te permite mostrarles 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 del 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 especialmente útil cuando se usa un intent para transferir varios URIs de content: a otra aplicación, como cuando se comparten varios documentos. Los URIs 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 URIs proporcionados en el intent ahora se propagan automáticamente a ClipData para que el receptor pueda tener acceso.

Compatibilidad con HTML y estilos de cadenas

La clase ClipData ahora admite texto con diseño (como HTML o cadenas con diseño de Android). Puedes agregar texto con estilo HTML a ClipData con newHtmlText().

RenderScript

La funcionalidad de procesamiento de Renderscript se mejoró con las siguientes funciones:

  • Compatibilidad con varios kernels dentro de una sola secuencia de comandos
  • Compatibilidad para leer desde la asignación con muestreadores filtrados desde el procesamiento en una nueva API de secuencia de comandos rsSample.
  • Compatibilidad con diferentes niveles de precisión de FP en #pragma.
  • Compatibilidad para consultar información adicional de objetos de RS desde una secuencia de comandos de procesamiento
  • Se realizaron varias mejoras de rendimiento.

También hay nuevos pragmas disponibles para definir la precisión de punto flotante requerida por tus Renderscripts de procesamiento. De esta manera, puedes habilitar operaciones similares a 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 Renderscript ahora está obsoleto.

Animación

Animaciones para iniciar la actividad

Ahora puedes iniciar un 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 a medida que se abre tu actividad:

makeScaleUpAnimation()
Crea una animación que escala verticalmente la ventana de actividad desde una posición inicial especificada en la pantalla y un tamaño de inicio especificado. Por ejemplo, la pantalla principal de Android 4.1 lo usa cuando se abre una app.
makeThumbnailScaleUpAnimation()
Crea una animación que aumenta la ventana de actividad a partir de una posición especificada y una imagen de miniatura proporcionada. Por ejemplo, la ventana de Apps recientes en Android 4.1 usa esto cuando se vuelve 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 detención de la actividad.

Animador de tiempo

El nuevo TimeAnimator proporciona un mecanismo de devolución de llamada simple con el TimeAnimator.TimeListener que te notifica en cada fotograma de la animación. No hay duración, interpolación ni configuración de valores de objetos con este animador. La devolución de llamada del objeto de escucha recibe información para 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 los tres estilos nuevos para tu notificación, cada uno de los cuales ofrece una región de contenido más grande. Para especificar el diseño de la región de contenido grande, pasa uno de los siguientes objetos a setStyle():

Notification.BigPictureStyle
Para notificaciones que incluyen una imagen adjunta grande.
Notification.BigTextStyle
Para 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 se admite 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 toma tres argumentos: un recurso de elementos de diseño para un ícono, el 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 mediante la configuración de la prioridad con setPriority(). Puedes pasar 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 más altos y dos más bajos.

Las notificaciones de prioridad alta son aquellas a las que los usuarios suelen querer responder con rapidez, como un mensaje instantáneo nuevo, un mensaje de texto o un recordatorio de un evento inminente. Las notificaciones de prioridad baja son, por ejemplo, eventos de calendario vencidos o promociones de apps.

Controles de 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 llamando a setSystemUiVisibility() y pasando las siguientes marcas:

SYSTEM_UI_FLAG_FULLSCREEN
Oculta la IU del sistema que no es crítica (como la barra de estado). Si tu actividad usa la barra de acciones en modo superpuesto (habilitando android:windowActionBarOverlay), esta marca también oculta la barra de acciones y lo hace con una animación coordinada cuando se ocultan y muestran ambas.
SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
Establece el diseño de tu actividad para que use el mismo área de pantalla que está disponible cuando habilitaste SYSTEM_UI_FLAG_FULLSCREEN, incluso si los elementos de la IU del sistema aún son visibles. Aunque la IU del sistema se superpondrá a partes de tu diseño, esto es útil si tu app suele ocultar y mostrar 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 se oculta o aparece la IU del sistema.
SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
Establece el diseño de tu actividad para que use el mismo área de pantalla que está disponible cuando habilitaste SYSTEM_UI_FLAG_HIDE_NAVIGATION (se agregó en Android 4.0), incluso si los elementos de la IU del sistema aún son visibles. Aunque la barra de navegación superpondrá partes de tu diseño, esto es útil si tu app suele ocultar y mostrar la barra de navegación con SYSTEM_UI_FLAG_HIDE_NAVIGATION, ya que evita que el 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 permanezcan 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 ocultar toda la IU del sistema.

Para obtener más información sobre las otras marcas relacionadas de la IU del sistema, lee sobre las que se agregaron 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 condensadas y claras.

El conjunto completo de variantes de fuente Roboto disponibles es el siguiente:

  • Frecuente
  • Cursiva
  • Negrita
  • Negrita y cursiva
  • Claro
  • Cursiva clara
  • Condensed regular
  • Cursiva condensada
  • Negrita condensada
  • Negrita cursiva condensada

Puedes aplicar cualquiera de estos con el nuevo atributo fontFamily en combinación con el atributo textStyle.

Estos son los valores admitidos para fontFamily:

  • "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

Varios dispositivos de entrada

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

Puedes llamar a getInputDeviceIds() para consultar todos los dispositivos de entrada conectados. Esto muestra 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() para adquirir un InputDevice para un ID de dispositivo de entrada especificado.

Si quieres recibir información cuando se conecten, cambien o desconecten dispositivos de entrada nuevos, 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 con las APIs de Vibrator existentes. Para ello, simplemente llama a getVibrator() en InputDevice.

Permisos

Los siguientes son permisos nuevos:

READ_EXTERNAL_STORAGE
Proporciona acceso de lectura protegido al almacenamiento externo. En Android 4.1, de forma predeterminada, todas las aplicaciones aún tienen acceso de lectura. Esto cambiará en una versión futura para exigir 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 para que prueben sus aplicaciones en función del comportamiento de Android en el futuro.
android.Manifest.permission.READ_USER_DICTIONARY
Permite que una aplicación lea el diccionario del usuario. Solo debe hacerlo 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 dedicados 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 y, por lo general, no a través del tacto ni de un mouse/dispositivo puntero.