API y funciones de Android Q

En Android Q, se incluyen excelentes funciones y capacidades nuevas para usuarios y desarrolladores. En este documento, se destacan las novedades para desarrolladores.

Para obtener más información sobre las API nuevas, lee el informe de diferencias de las API o consulta la referencia de la API de Android. Las API nuevas están destacadas para que puedas verlas fácilmente. Además, asegúrate de revisar los cambios de comportamiento de Android Q (para las apps que se orientan a Q y para todas las apps), al igual que los cambios de privacidad, a fin de obtener más información sobre las áreas en las que los cambios en la plataforma podrían afectar tus apps.

Mejoras de seguridad

En Android Q, se incluyen varias funciones de seguridad que se resumen en las siguientes secciones.

Diálogos de autenticación biométrica mejorados

En Android Q, se incluyen las siguientes mejoras a los diálogos de autenticación biométrica unificados que se agregaron en Android 9:

Especifica los requisitos de confirmación del usuario

Ahora puedes indicarle al sistema que no requiera la confirmación del usuario una vez que se lo haya autenticado mediante una modalidad biométrica implícita. Por ejemplo, puedes indicarle al sistema que no requiera pasos de confirmación adicionales una vez que se haya autenticado a un usuario mediante la autenticación facial.

De manera predeterminada, el sistema requiere la confirmación del usuario. Por lo general, los usuarios quieren confirmar acciones sensibles o de alto riesgo (por ejemplo, hacer una compra). No obstante, si tienes acciones de bajo riesgo en tu app, establece el método setConfirmationRequired() en false a fin de proporcionar una sugerencia para que no se requiera la confirmación del usuario. Debido a que esta marca se agrega como una sugerencia para el sistema, es posible que este ignore el valor si el usuario cambió su configuración del sistema por la autenticación biométrica.

Un ejemplo de autenticación facial sin confirmación del usuario.

Figura 1:Autenticación facial sin confirmación del usuario

Un ejemplo de autenticación facial que requiere confirmación del usuario.

Figura 2:Autenticación facial que requiere confirmación del usuario

Compatibilidad de resguardo mejorada para las credenciales del dispositivo

Ahora puedes indicarle al sistema que permita que un usuario se autentique con el PIN, el patrón o la contraseña de su dispositivo si, por algún motivo, no puede autenticarse con sus datos biométricos. Para habilitar la compatibilidad de resguardo, usa el método setDeviceCredentialAllowed().

Si actualmente tu app usa createConfirmDeviceCredentialIntent() como resguardo de las credenciales del dispositivo, comienza a usar el método nuevo en su lugar.

Verifica la capacidad biométrica del dispositivo

Ahora puedes verificar si un dispositivo admite la autenticación biométrica antes de invocar BiometricPrompt mediante el método canAuthenticate() en la clase BiometricManager.

Ejecuta código DEX incorporado directamente desde un APK

Ahora puedes indicarle a la plataforma que ejecute código DEX incorporado directamente desde el archivo APK de tu app. Esta opción puede ayudar a evitar un ataque si el atacante logró manipular el código compilado a nivel local en el dispositivo.

Para habilitar esta función, establece el valor del atributo android:useEmbeddedDex en true en el elemento <application> del archivo de manifiesto de tu app. También debes compilar un APK que contenga código DEX sin comprimir al que ART pueda acceder directamente. Agrega las siguientes opciones a tu archivo de configuración de Gradle o Bazel para compilar un APK con código DEX sin comprimir.

Gradle

aaptOptions {
       noCompress 'dex'
    }
    

Bazel

    android_binary(
       ...,
       nocompress_extensions = [“.dex”],
    )
    

Compatibilidad con TLS 1.3

La implementación de TLS de la plataforma ahora admite TLS 1.3. TLS 1.3 es una revisión importante al estándar de TLS que incluye ventajas de rendimiento y una seguridad mejorada. Nuestras comparativas indican que se pueden establecer conexiones seguras hasta un 40% más rápido con TLS 1.3 que con TLS 1.2.

TLS 1.3 está habilitado de manera predeterminada para todas las conexiones de TLS. Para obtener un SSLContext que tenga TLS 1.3 inhabilitado, llama a SSLContext.getInstance("TLSv1.2"). También puedes habilitar o inhabilitar versiones de protocolo por conexión si llamas a setEnabledProtocols() en un objeto correspondiente.

A continuación, se ofrecen algunos detalles importantes sobre nuestra implementación de TLS 1.3:

  • Los conjuntos de cifrado de TLS 1.3 no se pueden personalizar. Los conjuntos de cifrado de TLS 1.3 admitidos siempre están habilitados cuando TLS 1.3 está habilitado, y se ignora cualquier intento de inhabilitarlos mediante una llamada a setEnabledCipherSuites().
  • Cuando se negocia TLS 1.3, el llamado a los HandshakeCompletedListeners ocurre antes de que se agreguen sesiones a la caché de sesiones (que es lo opuesto a lo que sucede en TLS 1.2 y otras versiones anteriores).
  • Las instancias de SSLEngine mostrarán una SSLProtocolException en algunas circunstancias en las que anteriormente habrían mostrado una SSLHandshakeException.
  • No se admite el modo de 0-RTT.

API de Conscrypt pública

El proveedor de seguridad de Conscrypt ahora incluye una API pública para la funcionalidad de TLS. Anteriormente, los usuarios podían acceder a esta funcionalidad mediante reflejo. Sin embargo, debido a restricciones en las llamadas a API no públicas agregadas en P, esta función quedó en la lista gris en Q y continuarán las restricciones en versiones futuras.

En esta actualización, se agrega una colección de clases en android.net.ssl que contienen métodos estáticos para acceder a funcionalidades no disponibles desde las API javax.net.ssl genéricas. Los nombres de estas clases se pueden inferir como el plural de la clase javax.net.ssl asociada. Por ejemplo, el código que opera en instancias javax.net.ssl.SSLSocket puede usar métodos de la clase android.net.ssl.SSLSockets nueva.

Funciones de conectividad

En Android Q, se incluyen varias mejoras relacionadas con las redes y la conectividad.

API de conexión de red Wi-Fi

En Android Q, se admiten las conexiones entre pares. Esta función permite a tu app solicitarle al usuario que cambie el punto de acceso al que está conectado el dispositivo por medio de WifiNetworkSpecifier para describir las propiedades de una red solicitada. La conexión entre pares no se usa para proporcionar redes, sino para conectar dispositivos secundarios con otros fines, por ejemplo, para configurar el arranque de un Chromecast o del hardware de Google Home.

Cuando uses esta API, deberás realizar el siguiente flujo:

  1. Crea un especificador de red Wi-Fi por medio de WifiNetworkSpecifier.Builder.

  2. Establece un filtro de red para que coincida con las redes a las que debes conectarte junto con las credenciales requeridas.

  3. Elige una combinación de SSID, SSID pattern, BSSID y BSSID pattern para establecer el filtro de red en cada solicitud, en función de los siguientes requisitos:

    • Cada solicitud debe proporcionar al menos uno de los siguientes: SSID, SSID pattern, BSSID o BSSID pattern.
    • Cada solicitud solo puede establecer uno de los siguientes: SSID o SSID pattern.
    • Cada solicitud solo puede establecer uno de los siguientes: BSSID o BSSID pattern.
  4. Agrega los especificadores a la solicitud de red junto con una instancia NetworkCallback para realizar el seguimiento del estado de la solicitud.

    Si el usuario acepta la solicitud y la conexión a la red es exitosa, se invoca a NetworkCallback.onAvailable() en el objeto de devolución de llamada. Si el usuario rechaza esta solicitud o la conexión a la red no es exitosa, se invoca a NetworkCallback.onUnavailable() en el objeto de devolución de llamada.

Las conexiones entre pares no requieren permisos de ubicación ni de Wi-Fi. Cuando se inicia la solicitud para conectarse a un dispositivo de pares, se abre un cuadro de diálogo en el mismo dispositivo, en el que su usuario puede aceptar la solicitud de conexión.

Omite la aprobación del usuario

Una vez que el usuario aprueba una red para que se conecte como respuesta a una solicitud de una app específica, el dispositivo almacena la aprobación para ese punto de acceso específico. Si la app realiza una solicitud específica para volver a conectarse a ese punto de acceso, el dispositivo omitirá la fase de aprobación del usuario y se conectará automáticamente a la red. Si el usuario decide olvidar la red mientras está conectado a una red solicitada por la API, entonces se quita la aprobación almacenada para esa combinación de app y red, y el usuario deberá aprobar cualquier solicitud futura de la app. Si la app realiza una solicitud que no es específica (por ejemplo, como un SSID o patrón BSSID), el usuario deberá aprobarla.

Muestra de código

En la siguiente muestra de código, podrás ver cómo conectarte a una red abierta con un prefijo SSID de una "prueba" y un OUI de BSSID de "10:03:23":

Kotlin

    val specifier = WifiNetworkSpecifier.Builder()
        .setSsidPattern(PatternMatcher("test", PatternMatcher.PATTERN_PREFIX))
        .setBssidPattern(MacAddress.fromString("10:03:23:00:00:00"), MacAddress.fromString("ff:ff:ff:00:00:00"))
        .build()

    val request = NetworkRequest.Builder()
        .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
        .removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
        .setNetworkSpecifier(specifier)
        .build()

    val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager

    val networkCallback = object : ConnectivityManager.NetworkCallback() {
        ...
        override fun onAvailable(network: Network?) {
            // do success processing here..
        }

        override fun onUnavailable() {
            // do failure processing here..
        }
        ...
    }
    connectivityManager.requestNetwork(request, networkCallback)
    ...
    // Release the request when done.
    connectivityManager.unregisterNetworkCallback(networkCallback)
    

Java

    final NetworkSpecifier specifier =
      new WifiNetworkSpecifier.Builder()
      .setSsidPattern(new PatternMatcher("test", PatterMatcher.PATTERN_PREFIX))
      .setBssidPattern(MacAddress.fromString("10:03:23:00:00:00"), MacAddress.fromString("ff:ff:ff:00:00:00"))
      .build();

    final NetworkRequest request =
      new NetworkRequest.Builder()
      .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
      .removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
      .setNetworkSpecifier(specifier)
      .build();

    final ConnectivityManager connectivityManager = (ConnectivityManager)
      context.getSystemService(Context.CONNECTIVITY_SERVICE);

    final NetworkCallback networkCallback = new NetworkCallback() {
      ...
      @Override
      void onAvailable(...) {
          // do success processing here..
      }

      @Override
      void onUnavailable(...) {
          // do failure processing here..
      }
      ...
    };
    connectivityManager.requestNetwork(request, networkCallback);
    ...
    // Release the request when done.
    connectivityManager.unregisterNetworkCallback(networkCallback);
    

API de sugerencia de red de Wi-Fi

En Android Q, se agregó compatibilidad para que tu app pueda agregar credenciales de red en un dispositivo a fin de conectarse automáticamente a un punto de acceso de Wi-Fi. Puedes usar WifiNetworkSuggestion para brindar sugerencias de redes a las cuales conectarse. En última instancia, la plataforma elige qué punto de acceso aceptar en función de la información que obtenga de tu app y de otras.

En la siguiente muestra de código, se indica cómo proporcionar credenciales para una red abierta, una WPA2 y una WPA3:

Kotlin

    val suggestion1 = WifiNetworkSuggestion.Builder()
            .setSsid("test111111")
            .setIsAppInteractionRequired() // Optional (Needs location permission)
            .build()

    val suggestion2 = WifiNetworkSuggestion.Builder()
            .setSsid("test222222")
            .setWpa2Passphrase("test123456")
            .setIsAppInteractionRequired() // Optional (Needs location permission)
            .build()

    val suggestion3 = WifiNetworkSuggestion.Builder()
            .setSsid("test333333")
            .setWpa3Passphrase("test6789")
            .setIsAppInteractionRequired() // Optional (Needs location permission)
            .build()

    val suggestionsList = listOf(suggestion1, suggestion2, suggestion3)

    val wifiManager = context.getSystemService(Context.WIFI_SERVICE) as WifiManager

    val status = wifiManager.addNetworkSuggestions(suggestionsList);
    if (status != WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS) {
        // do error handling here
    }

    // Optional (Wait for post connection broadcast to one of your suggestions)
    val intentFilter = IntentFilter(WifiManager.ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION);

    val broadcastReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            if (!intent.action.equals(WifiManager.ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION)) {
                return;
            }
            // do post connect processing here
        }
    };
    context.registerReceiver(broadcastReceiver, intentFilter);
    

Java

    final WifiNetworkSuggestion suggestion1 =
      new WifiNetworkSuggestion.Builder()
      .setSsid("test111111")
      .setIsAppInteractionRequired() // Optional (Needs location permission)
      .build()

    final WifiNetworkSuggestion suggestion2 =
      new WifiNetworkSuggestion.Builder()
      .setSsid("test222222")
      .setWpa2Passphrase("test123456")
      .setIsAppInteractionRequired() // Optional (Needs location permission)
      .build()

    final WifiNetworkSuggestion suggestion3 =
      new WifiNetworkSuggestion.Builder()
      .setSsid("test333333")
      .setWpa3Passphrase("test6789")
      .setIsAppInteractionRequired() // Optional (Needs location permission)
      .build()

    final List<wifinetworksuggestion> suggestionsList =
      new ArrayList<wifinetworksuggestion> {{
        add(suggestion1);
        add(suggestion2);
        add(suggestion3);
      }};

    final WifiManager wifiManager =
      (WifiManager) context.getSystemService(Context.WIFI_SERVICE);

    final int status = wifiManager.addNetworkSuggestions(suggestionsList);
    if (status != WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS) {
    // do error handling here…
    }

    // Optional (Wait for post connection broadcast to one of your suggestions)
    final IntentFilter intentFilter =
      new IntentFilter(WifiManager.ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION);

    final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
      @Override
      public void onReceive(Context context, Intent intent) {
        if (!intent.getAction().equals(
          WifiManager.ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION)) {
          return;
        }
        // do post connect processing here..
      }
    };
    context.registerReceiver(broadcastReceiver, intentFilter);
    

El usuario debe aprobar las sugerencias de la app para que la plataforma establezca una conexión con ellas. El usuario proporciona esta aprobación como respuesta a una notificación la primera vez que la plataforma encuentra una red que coincide con una de las sugerencias de la app en los resultados de análisis. Cuando la plataforma se conecta a una de las sugerencias de red, la configuración mostrará un mensaje de texto en el que se atribuye la conexión de red a la app que hizo la sugerencia correspondiente.

Administra las desconexiones de usuarios

Si el usuario utiliza el selector de Wi-Fi para desconectarse explícitamente de una de las sugerencias de red cuando está conectado a ella, esa red se incluye en la lista negra durante 24 horas. Durante el período dentro de la lista negra, esa red no se considerará para la conexión automática, incluso si la aplicación quita y vuelve a agregar la sugerencia de red correspondiente.

Cambia el estado de aprobación para una app

Un usuario que rechaza la notificación de la sugerencia de red quita el permiso CHANGE_WIFI_STATE de la app. El usuario puede otorgar esta aprobación más adelante desde el menú de control de Wi-Fi (Configuración > Apps y notificaciones > Acceso especial a apps > Control de Wi-Fi > Nombre de aplicación).

Mejoras a los modos de baja latencia y alto rendimiento de Wi-Fi

Android Q te permite sugerirle al módem subyacente que minimice la latencia.

Android Q amplía la API de bloqueo de Wi-Fi para brindar compatibilidad de manera efectiva con el modo de alto rendimiento y el modo de baja latencia. El ahorro de energía de Wi-Fi está inhabilitado para el modo de alto rendimiento y baja latencia, y podrías habilitar una mayor optimización de la latencia en el modo de baja latencia, según la compatibilidad del módem.

El modo de baja latencia solo está habilitado cuando la app que adquiere el bloqueo se está ejecutando en segundo plano y la pantalla está encendida. El modo de baja latencia es especialmente útil para las apps de juegos para dispositivos móviles en tiempo real.

Búsquedas especializadas en el agente de resolución de DNS

En Android Q, se agregó compatibilidad nativa para DNS mediante TLS y para búsquedas de DNS especializadas. Anteriormente, el agente de resolución de DNS de la plataforma admitía resoluciones de tipo A, lo que resolvía una dirección de IP respecto de un nombre de dominio sin especificaciones sobre los servicios que se ofrecían en ese IP. Con esta actualización, ahora se admiten las búsquedas SRV y NAPTR.

Android Q permite a los desarrolladores usar búsquedas de Cleartext estándar y un modo de DNS mediante TLS.

Easy Connect para Wi-Fi

Android Q te permite usar Easy Connect para aprovisionar credenciales de Wi-Fi a un dispositivo de pares como reemplazo de WPS, que dejó de estar disponible. Las apps pueden integrar Easy Connect en su flujo de aprovisionamiento y configuración mediante el intent ACTION_PROCESS_WIFI_EASY_CONNECT_URI. Este intent requiere un URI. La app de llamadas puede obtener el URI mediante varios métodos, como escanear un código QR de una calcomanía o pantalla, o bien escanear anuncios de NFC o Bluetooth de bajo consumo.

Una vez que el URI está disponible, puedes aprovisionar las credenciales de Wi-Fi del dispositivo de pares con el intent ACTION_PROCESS_WIFI_EASY_CONNECT_URI, lo que permite que el usuario seleccione una red Wi-Fi para compartir y transferir de manera segura las credenciales.

Easy Connect no requiere permisos de ubicación ni de Wi-Fi.

API de conexión para Wi-Fi directo

Las clases de API WifiP2pConfig y WifiP2pManager tienen actualizaciones en Android Q para admitir las capacidades de establecer conexión rápidamente con Wi-Fi directo mediante información predeterminada. Esta información se comparte mediante un canal lateral, como Bluetooth o NFC.

En el siguiente código se muestra cómo crear un grupo con información predeterminada:

Kotlin

    val manager = getSystemService(Context.WIFI_P2P_SERVICE) as WifiP2pManager
    val channel = manager.initialize(this, mainLooper, null)

    // prefer 5G band for this group
    val config = WifiP2pConfig.Builder()
        .setNetworkName("networkName")
        .setPassphrase("passphrase")
        .enablePersistentMode(false)
        .setGroupOperatingBand(WifiP2pConfig.GROUP_OWNER_BAND_5GHZ)
        .build()

    // create a non-persistent group on 5GHz
    manager.createGroup(channel, config, null)
    

Java

    WifiP2pManager manager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
    Channel channel = manager.initialize(this, getMainLooper(), null);

    // prefer 5G band for this group
    WifiP2pConfig config = new WifiP2pConfig.Builder()
    .setNetworkName("networkName")
    .setPassphrase("passphrase")
    .enablePersistentMode(false)
    .setGroupOperatingBand(WifiP2pConfig.GROUP_OWNER_BAND_5GHZ)
    .build();

    // create a non-persistent group on 5GHz
    manager.createGroup(channel, config, null);
    

Para unirte a un grupo mediante credenciales, reemplaza manager.createGroup() con el código siguiente:

Kotlin

    manager.connect(channel, config, null)
    

Java

    manager.connect(channel, config, null);
    

Canales orientados a la conexión (CoC) de Bluetooth de bajo consumo

Android Q permite que tu app use conexiones CoC de BLE para transferir flujos de datos más grandes entre dos dispositivos BLE. Esta interfaz abstrae las mecánicas de Bluetooth y de conectividad para simplificar la implementación.

Funciones de telefonía

En Android Q, se incluyen varias mejoras relacionadas con la telefonía.

Mejoras de calidad de la llamada

En Android Q, se agregó la capacidad de recopilar información sobre la calidad de las llamadas en curso del Subsistema multimedia de IP (IMS), lo que incluye la calidad de la red de envío y recepción en los dispositivos que admiten la función.

Identificación de llamada y número de llamada

Android Q proporciona una manera para que tu app pueda identificar llamadas de emisores que no están en la libreta de direcciones del usuario y posibles llamadas de spam. Además, puede rechazar llamadas de spam de manera silenciosa en nombre del usuario. La información sobre estas llamadas bloqueadas se registra bajo el mismo nombre en el registro de llamadas a fin de brindar mayor transparencia al usuario cuando hay llamadas perdidas. El uso de esta API nueva elimina el requisito de obtener permisos de READ_CALL_LOG del usuario a fin de brindar la funcionalidad de identificador de llamada y número de llamada.

API de servicio de redireccionamiento de llamadas

Android Q cambia la manera en la que se administran los intents de las llamadas. La transmisión de NEW_OUTGOING_CALL dejó de estar disponible y se reemplazó con la API CallRedirectionService. La API CallRedirectionService brinda interfaces para que puedas modificar las llamadas salientes que hizo la plataforma Android. Por ejemplo, las apps de terceros podrían cancelar llamadas y redirigirlas mediante VoIP.

Mejoras en la creación de archivos en el almacenamiento externo

Además de introducir el cambio de comportamiento en la privacidad del almacenamiento específico, Android Q brinda más flexibilidad en la escritura de archivos y presenta capacidades para ayudarte a cambiar dónde se guardan esos archivos en un dispositivo de almacenamiento externo.

Estado pendiente para nuevos archivos multimedia

Android Q presenta el marcador IS_PENDING, que otorga a tu app acceso exclusivo a un archivo multimedia mientras se escribe en el disco.

El siguiente fragmento de código ejemplifica cómo usar el marcador IS_PENDING cuando creas una nueva imagen en tu app:

Kotlin

    val values = ContentValues().apply {
        put(MediaStore.Images.Media.DISPLAY_NAME, "IMG1024.JPG")
        put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
        put(MediaStore.Images.Media.IS_PENDING, 1)
    }

    val resolver = context.getContentResolver()
    val collection = MediaStore.Images.Media
            .getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
    val item = resolver.insert(collection, values)

    resolver.openFileDescriptor(item, "w", null).use { pfd ->
        // Write data into the pending image.
    }

    // Now that we're finished, release the "pending" status, and allow other apps
    // to view the image.
    values.clear()
    values.put(MediaStore.Images.Media.IS_PENDING, 0)
    resolver.update(item, values, null, null)
    

Java

    ContentValues values = new ContentValues();
    values.put(MediaStore.Images.Media.DISPLAY_NAME, "IMG1024.JPG");
    values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
    values.put(MediaStore.Images.Media.IS_PENDING, 1);

    ContentResolver resolver = context.getContentResolver();
    Uri collection = MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY);
    Uri item = resolver.insert(collection, values);

    try (ParcelFileDescriptor pfd = resolver.openFileDescriptor(item, "w", null)) {
        // Write data into the pending image.
    } catch (IOException e) {
        e.printStackTrace();
    }

    // Now that we're finished, release the "pending" status, and allow other apps
    // to view the image.
    values.clear();
    values.put(MediaStore.Images.Media.IS_PENDING, 0);
    resolver.update(item, values, null, null);
    

Influencia en la ubicación del almacenamiento

Android Q presenta varias capacidades para ayudarte a organizar los archivos que su aplicación proporciona al almacenamiento externo.

Sugerencias de directorios

Cuando tu app proporciona contenido multimedia en un dispositivo con Android Q, ese contenido se organiza según su tipo de manera predeterminada. Por ejemplo, los nuevos archivos de imagen se colocan en un directorio de "imágenes" de forma predeterminada.

Si tu app identifica una ubicación concreta donde se deberían almacenar los archivos, como Pictures/MyVacationPictures, puedes definir MediaColumns.RELATIVE_PATH para brindar al sistema una sugerencia sobre dónde almacenar los archivos escritos recientemente. De forma similar, puedes mover archivos en el disco durante una llamada a update() si cambias MediaColumns.RELATIVE_PATH o MediaColumns.DISPLAY_NAME.

Selección de dispositivos

En Android 9 (nivel de API 28) y versiones anteriores, todos los archivos guardados en dispositivos de almacenamiento externo aparecen bajo un volumen individual llamado external. Android Q, por otro lado, le da a cada dispositivo de almacenamiento externo un nombre de volumen único. Este nuevo sistema de nombres te ayuda a organizar e indexar contenido de manera eficaz, y además te permite controlar dónde se guarda el contenido nuevo.

El dispositivo de almacenamiento compartido principal siempre se llama VOLUME_EXTERNAL_PRIMARY. Puedes llamar a MediaStore.getExternalVolumeNames() para descubrir otros volúmenes.

Para buscar, insertar, actualizar o borrar un volumen específico, transfiere el nombre del volumen a cualquiera de los métodos getContentUri() disponibles en la API de MediaStore, como en el siguiente fragmento de código:

    // Publish an audio file onto a specific external storage device.
    val values = ContentValues().apply {
        put(MediaStore.Audio.Media.RELATIVE_PATH, "Music/My Album/My Song")
        put(MediaStore.Audio.Media.DISPLAY_NAME, "My Song.mp3")
    }

    // Assumes that the storage device of interest is the 2nd one
    // that your app recognizes.
    val volumeNames = MediaStore.getExternalVolumeNames(context)
    val selectedVolumeName = volumeNames[1]
    val collection = MediaStore.Audio.Media.getContentUri(selectedVolumeName)
    val item = resolver.insert(collection, values)
    

Contenido multimedia y gráficos

En Android Q, se incluyen las siguientes API y funciones de contenido multimedia y gráficos nuevas:

Captura de reproducción de audio

Android Q brinda a una app la capacidad de capturar la reproducción de audio de otras apps. Para obtener la información completa, consulta Captura de la reproducción.

API de MIDI nativo

La API de MIDI nativo de Android (AMidi) brinda a los desarrolladores de apps la capacidad de enviar y recibir datos de MIDI con código C/C++, lo que permite mejorar la integración con la lógica de audio/control de C/C++ y minimizar la necesidad de JNI.

Para obtener más información, consulta API de MIDI nativo de Android.

Mejoras de MediaCodecInfo

Hay métodos nuevos en MediaCodecInfo que revelan más información sobre un códec:

isSoftwareOnly()
Muestra el valor "true" si el códec se ejecuta solo en software. Los códecs de software no permiten garantizar el rendimiento de procesamiento.
isHardwareAccelerated()
Muestra el valor "true" si un código se ejecuta para aceleración de hardware.
isVendor()
Muestra el valor "true" si el proveedor del dispositivo proporciona el códec o "false" si lo proporciona la plataforma de Android.
isAlias()
MediaCodecList puede contener entradas adicionales para el mismo códec subyacente mediante un nombre de códec alternativo (alias). Este método muestra el valor "true" si el códec en esta entrada es un alias para otro códec.

Además, MediaCodec.getCanonicalName() muestra el nombre del códec subyacente para los códecs creados mediante un alias.

Puntos de rendimiento

Un punto de rendimiento representa la capacidad de un códec de procesar video a una altura, un ancho y una velocidad de fotogramas específica. Por ejemplo, el punto de rendimiento UHD_60 representa un video en ultraalta definición (3840 × 2160 píxeles) procesado a 60 fotogramas por segundo.

El método MediaCodecInfo.VideoCapabilities.getSupportedPerformancePoints() muestra una lista de entradas de PerformancePoint que el códec puede procesar o capturar.

Puedes verificar si un PerformancePoint específico cubre a otro mediante una llamada a PerformancePoint.covers(PerformancePoint). Por ejemplo, UHD_60.covers(UHD_50) muestra el valor "true".

Se proporciona una lista de puntos de rendimiento para todos los códecs de aceleración de hardware. La lista podría estar vacía si el códec no cumple ni con el punto de rendimiento estándar más bajo.

Ten en cuenta que los dispositivos que se actualizaron a Q sin actualizar la imagen del proveedor no tendrán datos de punto de rendimiento, ya que estos datos provienen de la HAL del proveedor. En este caso, getSupportedPerformancePoints() muestra el valor "null".

ANGLE

Con el lanzamiento de Android Q, los desarrolladores y socios de Android tendrán la posibilidad de ejecutar el sistema operativo con ANGLE, un proyecto de la organización Chrome que pone ES por encima de Vulkan, en lugar de usar el controlador ES que proporciona el proveedor.

Para obtener más información, consulta ANGLE.

API térmica

Cuando los dispositivos se sobrecalientan, pueden acelerar la CPU o la GPU, lo que puede afectar a las apps y los juegos de forma inesperada. Las apps que usan gráficos complejos, cálculos exigentes o actividad de red constante son más propensas a tener problemas, que pueden variar en función de los dispositivos según la frecuencia del chipset y del núcleo, los niveles de integración, el embalaje del dispositivo y el factor de forma.

Ahora, en Android Q, las apps y los juegos pueden usar una API térmica para supervisar los cambios en el dispositivo y tomar medidas que permiten mantener un menor consumo de energía a fin de restaurar la temperatura normal. Las apps registran un objeto de escucha en PowerManager, mediante el cual el sistema informa el estado térmico actual que va desde leve y moderado a grave, crítico, emergencia y apagado.

Cuando el dispositivo informa sobre un aumento considerable de la temperatura, las apps y los juegos pueden interrumpir actividades en curso para ayudar a reducir el uso de energía de varias maneras. Por ejemplo, las apps de streaming podrían reducir la resolución, la tasa de bits o el tráfico de red; una app de cámara podría inhabilitar el flash o la mejora intensiva de imágenes; un juego podría reducir la velocidad de fotogramas o el teselado; una app de contenido multimedia podría reducir el volumen de las bocinas; y una app de mapas podría desactivar el GPS.

La API térmica requiere una nueva HAL para dispositivos: actualmente es compatible con dispositivos Pixel que ejecutan Android Q, y estamos trabajando con nuestros socios fabricantes para ampliar la compatibilidad en el ecosistema lo más rápido posible.

Imágenes y cámara

A continuación, se muestran las nuevas funciones relacionadas con las imágenes y la cámara que incluye Android Q:

Compatibilidad con la cámara monocromática

Android 9 (con nivel de API 28) fue la primera versión que introdujo la capacidad de cámara monocromática. En Android Q, se agregaron varias mejoras a la compatibilidad con la cámara monocromática:

  • Nueva compatibilidad con el formato de transmisión Y8 para mejorar la eficiencia de la memoria
  • Compatibilidad con la captura DNG sin procesar monocromática
  • Introducción a las enumeraciones MONO y NIR CFA para distinguir entre la cámara monocromática regular y las cámaras casi infrarrojas

Puedes usar esta función para capturar una imagen monocromática nativa. Un dispositivo multicámara lógico puede usar una cámara monocromática como subcámara física para mejorar la calidad de la imagen cuando hay poca luz.

Formato de profundidad dinámica

A partir de Android Q, las cámaras pueden almacenar los datos de profundidad de una imagen en un archivo por separado, mediante un esquema nuevo llamado formato de profundidad dinámica (DDF). Las apps pueden solicitar la imagen JPG y sus metadatos de profundidad y usar esa información para aplicar un desenfoque deseado en el procesamiento posterior sin modificar los datos originales de la imagen.

Para leer las especificaciones del nuevo formato, consulta Formato de profundidad dinámica.

Formato de archivo de imagen de alta eficiencia

El formato de archivo de imagen de alta eficiencia (HEIF) es un formato estándar de imágenes y videos que introduce codificación de mejor calidad y un tamaño de archivo más pequeño en comparación con otros formatos de archivo.

Para obtener más información, consulta HEIC.

Mejoras en la función de varias cámaras

Android Q mejora la fusión de varias cámaras en una única cámara lógica, una función que se introdujo en Android 9 (nivel de API 28). Se agregó lo siguiente a la API de Camera2:

API de servicios de accesibilidad

En Android Q, se incluyen las siguientes API y funciones de servicios de accesibilidad nuevas:

Marca de clave de entrada de AccessibilityNodeInfo

En Android Q, se mejoró AccessibilityNodeInfo con una marca nueva que indica si representa una clave de entrada de texto. Puedes usar el método AccessibilityNodeInfo.isTextEntryKey() para acceder a esta marca.

Comentarios por voz del diálogo de accesibilidad

Cuando un servicio de accesibilidad requiere que el usuario repita el acceso directo de accesibilidad para iniciar el servicio, ahora el diálogo puede estar acompañado de un mensaje de texto a voz si el servicio lo solicita.

Acceso directo de accesibilidad para teclados físicos

En Android Q, ahora los usuarios pueden presionar Control+Alt+Z para activar el acceso directo de accesibilidad en un teclado físico.

Mejora del controlador de teclado en pantalla

En Android Q, los servicios de accesibilidad ahora pueden solicitar que se muestre el teclado en pantalla incluso cuando el dispositivo detecta un teclado físico conectado. Los usuarios no pueden anular este comportamiento.

Tiempos de espera de accesibilidad definidos por el usuario

En Android Q, se introdujo el método de API AccessibilityManager.getRecommendedTimeoutMillis(), que ofrece compatibilidad con los tiempos de espera definidos por el usuario para elementos de IU de accesibilidad interactivos y no interactivos. El valor que se muestra está basado en las preferencias del usuario y las API del servicio de accesibilidad.

Mejoras de autocompletar

En Android Q, se incluyen las siguientes mejoras para el servicio de autocompletar.

Ahora puedes usar el marcador FillRequest.FLAG_COMPATIBILITY_MODE_REQUEST para determinar si la solicitud de Autocompletar se generó mediante el modo de compatibilidad.

Guarda el nombre de usuario y la contraseña de manera simultánea

Ahora puedes usar el marcador SaveInfo.FLAG_DELAY_SAVE para admitir los casos en los que una app usa varias actividades a fin de mostrar campos de nombre de usuario y de contraseña, entre otros.

Interacción del usuario con la IU de guardar

Ahora puedes mostrar y ocultar un campo de contraseña en un diálogo de guardado estableciendo un objeto de escucha en el diálogo y cambiando la visibilidad de la vista remota de contraseña correspondiente.

Compatibilidad con la actualización de conjuntos de datos

Ahora se pueden actualizar contraseñas en Autocompletar. Por ejemplo, si un usuario ya almacenó una contraseña y guarda una nueva, Autocompletar le pedirá al usuario que actualice la contraseña existente en lugar de guardar una nueva.

Mejoras de clasificación de campos

En Android Q, se incluyen las siguientes mejoras a la API de clasificación de campos.

Constructor UserData.Builder

Se modificó el constructor UserData.Builder para que se alinee mejor con el patrón Builder.

Permite que un valor se asigne a varios tipos de ID de categoría

En Android Q, ahora puedes asignar un valor a varios tipos de ID de categoría cuando usas UserData.Builder. En las versiones anteriores, se mostraba una excepción si agregabas un valor más de una vez.

Compatibilidad mejorada con números de tarjetas de crédito

La clasificación de campos ahora puede detectar números de cuatro dígitos como los cuatro últimos dígitos del número de una tarjeta de crédito.

Compatibilidad con la clasificación de campos específicos de la app

En Android Q, se agregó FillResponse.setUserData(), que te permite configurar datos de usuario específicos de la app para la duración de la sesión. Esto ayuda al servicio de autocompletar a detectar tipos para los campos con contenido específico de la app.

Controles del sistema y de IU

En Android Q, se ofrecen las siguientes mejoras de la interfaz del usuario:

Compatibilidad con limitaciones de JVMTI PopFrame

En Android Q, se agregó la compatibilidad con la capacidad can_pop_frames en la implementación de Android JVMTI. Durante la depuración, esta función te permite volver a ejecutar funciones después de pausar debido a una interrupción y ajustar las configuraciones locales o globales, o bien la implementación de una función. Para obtener más información, consulta la página de referencia de Pop Frame de Oracle.

API de control de superficie

En Android Q, se proporciona una API de SurfaceControl para el acceso de bajo nivel al compositor del sistema (SurfaceFlinger). Para la mayoría de los usuarios, SurfaceView es la manera correcta de aprovechar el compositor. La API SurfaceControl puede resultar útil en determinados casos para, por ejemplo:

  • Sincronizar varias superficies
  • Incorporar superficies con un proceso cruzado
  • Administrar el tiempo de vida de bajo nivel

La API de SurfaceControl está disponible en vinculaciones de SDK y NDK. La implementación de NDK incluye una API para el intercambio manual de búferes con el compositor. Esta es una alternativa para los usuarios que se encontraron con las limitaciones de BufferQueue.

Detección del procesador de inactividad de WebView

En Android Q, se introdujo una nueva clase abstracta WebViewRenderProcessClient, que las apps pueden usar para detectar si WebView no responde. Para usar esta clase:

  1. Define tu propia subclase y, luego, implementa los métodos onRenderProcessResponsive() y onRenderProcessUnresponsive().
  2. Adjunta una instancia de tu WebViewRenderProcessClient a uno o varios objetos WebView.
  3. Si WebView deja de responder, el sistema llama al método onRenderProcessUnresponsive() del cliente y agrega los objetos WebView y WebViewRenderProcess. (Si el objeto WebView es un solo proceso, el parámetro WebViewRenderProcess es nulo). Tu app puede llevar a cabo una acción apropiada, como mostrarle al usuario un cuadro de diálogo donde se le pregunte si quiere detener el procesamiento.

Si WebView sigue sin responder, el sistema llama a onRenderProcessUnresponsive() periódicamente (no más de una vez cada cinco segundos), pero no toma ninguna otra medida. Si el WebView vuelve a responder, el sistema solo llama a onRenderProcessResponsive() una vez.

Paneles de configuración

En Android Q, se presentan los Paneles de configuración, una API que permite que las apps muestren la configuración a los usuarios en el contexto de su app. Esto evita que los usuarios tengan que ir a Configuración para cambiar parámetros como NFC o Datos móviles a fin de usar la app.

Figura 1: El usuario intenta abrir una página web mientras el dispositivo no está conectado a la red. Se abre el panel de configuración emergente Conectividad de Internet en Chrome.

Figura 2: El usuario puede activar el Wi-Fi y seleccionar una red sin salir de la app de Chrome.

Por ejemplo, imagina que un usuario abre un navegador web mientras el dispositivo está en modo de avión. Antes de Android Q, la app solo podía mostrar un mensaje genérico que le pedía al usuario que abra la Configuración para restaurar la conectividad. Con Android Q, la app de navegador puede mostrar un panel entre líneas que muestra ajustes clave de la configuración de conectividad, como el modo de avión, Wi-Fi (incluidas las redes cercanas) y datos móviles. Mediante este panel, los usuarios pueden restablecer la conectividad sin salir de la app.

Para mostrar un panel de configuración, activa un intent con una de las nuevas acciones de Settings.Panel que se muestran a continuación:

Kotlin

    val panelIntent = Intent(Settings.Panel.settings_panel_type)
    startActivityForResult(panelIntent)
    

Java

    Intent panelIntent = new Intent(Settings.Panel.settings_panel_type);
    startActivityForResult(panelIntent);
    

settings_panel_type puede ser una de las siguientes opciones:

ACTION_INTERNET_CONNECTIVITY
Muestra la configuración relacionada con la conexión a Internet, como el modo de avión, el Wi-Fi y los datos móviles.
ACTION_WIFI:
Muestra la configuración de Wi-Fi, pero no las otras opciones de configuración de conectividad. Esta opción es útil para las apps que necesitan una conexión Wi-Fi para realizar cargas o descargas de gran tamaño.
ACTION_NFC
Muestra todas las opciones de configuración relacionadas con la comunicación de campo cercano (NFC).
ACTION_VOLUME
Muestra la configuración de volumen de todas las transmisiones de audio.

Tenemos planificado agregar un wrapper de AndroidX para esta funcionalidad. El wrapper abrirá la página más apropiada en la app de Configuración cuando se lo llame en dispositivos que ejecutan Android 9 (con nivel de API 28).

Mejoras de uso compartido

En Android Q, se ofrecen varias mejoras para el uso compartido. Para obtener la información completa, consulta Mejoras de uso compartido en Android Q.

Tema oscuro

En Android Q, se ofrece un nuevo tema oscuro que se aplica tanto a la IU del sistema Android como a las apps que se ejecutan en el dispositivo. Para obtener la información completa, consulta Tema oscuro.

Tipos de servicios en primer plano

En Android Q, se introdujo un nuevo atributo de manifiesto XML, foregroundServiceType, que se incluye en la definición de varios servicios específicos. Es posible, aunque rara vez es apropiado, asignar múltiples tipos de servicios en primer plano a un servicio en particular.

En la siguiente tabla, se muestran los diferentes tipos de servicios en primer plano y los servicios en los que es apropiado declarar un tipo específico:

Tipo de servicio en primer plano Ejemplo de caso práctico para un servicio que debería declarar este tipo
connectedDevice Supervisar un wearable que registra la actividad física
dataSync Descargar archivos desde una red
location Continuar una acción que inició el usuario
mediaPlayback Reproducir un audiolibro, un podcast o música
mediaProjection Grabar un video de la pantalla del dispositivo durante un período breve
phoneCall Encargarse de una llamada telefónica en curso

Kotlin

En Android Q, se incluyen las siguientes actualizaciones para el desarrollo en Kotlin.

Anotaciones de nulidad para API de libcore

En Android Q, se mejoró la cobertura de las anotaciones de nulidad en el SDK para las API de libcore. Estas anotaciones permiten que los desarrolladores de apps que usan el análisis de nulidad de Kotlin o Java en Android Studio obtengan información sobre la nulidad cuando interactúan con estas API.

Normalmente, las infracciones del contrato de nulidad en Kotlin dan como resultado errores de compilación. Para garantizar la compatibilidad con tu código existente, las anotaciones nuevas se limitan a @RecentlyNullable y @RecentlyNonNull, lo que quiere decir que las infracciones de nulidad dan como resultado advertencias en lugar de errores.

Además, cualquier anotación de @RecentlyNullable o @RecentlyNonNull que se haya agregado en Android 9 cambiará por @Nullable y @NonNull, respectivamente. Esto quiere decir que las infracciones de nulidad ahora dan lugar a errores en lugar de advertencias.

Para obtener más información sobre los cambios de nulidad, consulta El SDK de Android Pie ahora está optimizado para Kotlin en el blog de desarrolladores de Android.

NDK

En Android Q, se incluyen los siguientes cambios de NDK.

Depuración mejorada de la propiedad del descriptor de archivo

En Android Q, se agregó "fdsan", que te ayuda a encontrar y corregir los problemas de propiedad del descriptor de archivo con mayor facilidad.

Los errores relacionados con el mal manejo de la propiedad del descriptor de archivo, que suelen manifestarse como usar después de cerrar y cierre doble, son análogos a los errores de usar después de liberar y liberación doble de la asignación de la memoria, aunque suelen ser mucho más difíciles de diagnosticar y corregir. fdsan aplica la propiedad del descriptor de archivo para intentar detectar o prevenir su administración incorrecta.

Para obtener más información sobre las fallas relacionadas con estos problemas, consulta Error detectado por fdsan. Para obtener más información sobre fdsan, consulta la página sobre fdsan en Googlesource.

TLS de ELF

Las apps creadas mediante el NDK con un nivel de API mínimo de 29 ya no necesitan usar emutls, sino que pueden usar TLS de ELF en su lugar. Se agregó compatibilidad con el vinculador dinámico y estático a fin de admitir el método nuevo de manejo de variables a nivel de la conversación.

En el caso de las apps creadas para un nivel de API de 28 y niveles inferiores, se implementaron mejoras para que libgcc/compiler-rt funcione como solución alternativa a problemas de emutls.

Para obtener más información, consulta cambios de Android para desarrolladores de NDK.

Tiempo de ejecución

En Android Q, se incluye el siguiente cambio de tiempo de ejecución.

Activación de recolección de elementos no utilizados basada en mallinfo

Cuando los objetos Java de plataforma pequeña hacen referencia a objetos de gran tamaño en C++, a menudo los objetos C++ solo se pueden reclamar cuando el objeto Java se recolecta y, por ejemplo, finaliza. En las versiones anteriores, la plataforma calculaba los tamaños de muchos objetos C++ asociados a los objetos Java. Este cálculo no siempre era preciso y ocasionalmente generaba un uso exagerado de la memoria, ya que la plataforma no recolectaba elementos no utilizados cuando debería haberlo hecho.

En Q, el recolector de elementos no utilizados (GC) controla el tamaño total de la pila asignada por el sistema malloc() y garantiza que las asignaciones malloc() de mayor tamaño siempre se incluyan en los cálculos de activación del GC. Las apps que intercalan grandes cantidades de asignaciones C++ con la ejecución de Java podrían ver un aumento en la recolección de elementos no utilizados como resultado. Otras apps podrían notar una disminución leve.

Pruebas y depuración

En Android Q, se incluyen las siguientes mejoras para la prueba y la depuración:

Mejoras del registro del sistema en el dispositivo

Ahora puedes especificar límites para el tamaño y la duración del registro cuando realizas un registro del sistema en el dispositivo. Cuando especificas uno de los valores, el sistema realiza un registro largo y, a medida que se graba el registro, copia el búfer de registro en el archivo de destino de manera periódica. El registro se completa cuando se alcanzan los límites de duración o tamaño que especificaste.

Usa estos parámetros adicionales para probar casos prácticos diferentes de los que probarías con un registro estándar. Por ejemplo, podrías diagnosticar un error de rendimiento que solo ocurre después de que tu app se estuvo ejecutando por un período prolongado. En este caso, podrías grabar un registro largo durante todo un día y, luego, analizar el programador de CPU, la actividad del disco, los subprocesos de la app y otros datos en el informe que podrían ayudarte a determinar la causa del error.

Mejoras de TextClassifier

En Android Q, se proporciona una funcionalidad adicional de clasificación de textos en la interfaz de TextClassifier.

Detección de idioma

TextClassifier ahora incluye el método detectLanguage(), que funciona de manera similar a los métodos de clasificación existentes; es decir, recibe un objeto TextLanguage.Request y muestra un objeto TextLanguage.

El nuevo objeto TextLanguage consiste en una lista de pares ordenados. Cada par contiene una configuración regional y una puntuación de confianza correspondiente para la muestra de texto solicitada.

Acciones de conversación sugeridas

TextClassifier ahora incluye el método suggestConversationActions(), que funciona de manera similar a los métodos de clasificación existentes; es decir, recibe un objeto ConversationActions.Request y muestra un objeto ConversationActions.

El nuevo objeto ConversationActions consiste en una lista de objetos ConversationAction. En cada objeto ConversationAction, se incluye una acción potencial sugerida y su puntuación de confianza.

Respuestas inteligentes/acciones en notificaciones

En Android 9, se introdujo la opción de mostrar respuestas sugeridas dentro de una notificación. A partir de Android Q, las notificaciones también pueden incluir acciones sugeridas basadas en intents. Además, el sistema ahora puede generar estas sugerencias automáticamente. Las apps pueden seguir brindando sugerencias propias, o bien inhabilitar la opción para recibir sugerencias generadas por el sistema.

La API que se usó para generar estas respuestas es parte de TextClassifier, y también está disponible para los desarrolladores en Android Q. Lee la sección sobre las mejoras en TextClassifier para obtener más información.

Si tu app brinda sus propias sugerencias, la plataforma no genera sugerencias automáticas. Si no quieres que las notificaciones de tu app muestren respuestas o acciones sugeridas por el sistema, puedes inhabilitarlas con setAllowGeneratedReplies() y setAllowSystemGeneratedContextualActions().