API y funciones de Android 8.1

Android 8.1 (nivel de API 27) presenta una variedad de funciones y capacidades nuevas para usuarios y desarrolladores. En este documento, se destacan las novedades para desarrolladores.

Android Oreo (edición Go)

Android Go es nuestra iniciativa que tiene como fin optimizar la experiencia de Android para miles de millones de personas que se conectan en todo el mundo. Desde Android 8.1, estamos haciendo de Android una gran plataforma para dispositivos de nivel de entrada. Entre las funciones de configuración de Android Oreo (edición Go), se incluyen las siguientes:

  • Optimizaciones de memoria. El uso de memoria mejorado en toda la plataforma garantiza que las apps puedan ejecutarse de manera eficiente en dispositivos con 1 GB o menos de RAM.
  • Opciones de orientación flexibles. Las nuevas constantes de funciones de hardware te permiten orientar la distribución de tus apps a dispositivos normales o con poca RAM mediante Google Play.
  • Google Play. Si bien todas las apps estarán disponibles en dispositivos con Android Oreo (edición Go), Google Play dará visibilidad a las apps específicamente optimizadas por los desarrolladores para proporcionar una gran experiencia a miles de millones de personas con la compilación de miles de millones de lineamientos.

Actualizamos la compilación para miles de millones de lineamientos con asistencia adicional acerca de cómo optimizar tu app para dispositivos que ejecutan Android Oreo (edición Go). Para la mayoría de los desarrolladores, la mejor manera de prepararse para dispositivos con Android Oreo (edición Go) es optimizar tu APK existente o usar la función de varios APK de Google Play para orientar una versión de tu APK a dispositivos con poca RAM. Recuerda que hacer que tu app sea más liviana y más eficiente beneficia a todo tu público, independientemente del dispositivo.

API de Neural Networks

La API de Neural Networks proporciona inferencias y cálculos acelerados para marcos de aprendizaje automático en dispositivos, como TensorFlow Lite, la biblioteca de AA multiplataforma de Google para dispositivos móviles, así como Caffe2 y otros. Para conocer los documentos y las descargas disponibles, visita el repositorio de código abierto de TensorFlow Lite. TensorFlow Lite funciona con la API de Neural Networks para ejecutar modelos como MobileNets, Inception v3 y Smart Reply de manera eficaz en tu dispositivo móvil.

Actualizaciones de Autofill Framework

Android 8.1 (nivel de API 27) proporciona varias mejoras a Autofill Framework que puedes incorporar a tus apps.

La clase BaseAdapter ahora incluye el método setAutofillOptions(), que te permite proporcionar representaciones de strings de los valores en un adaptador. Esto resulta útil para los controles de íconos giratorios que generan dinámicamente los valores en sus adaptadores. Por ejemplo, puedes usar el método setAutofillOptions() para proporcionar una representación de string de la lista de años que los usuarios pueden elegir como parte de una fecha de vencimiento de la tarjeta de crédito. Los servicios de autocompletar pueden usar la representación de string para llenar adecuadamente las vistas que requieren los datos.

Además, la clase AutofillManager incluye el método notifyViewVisibilityChanged(View, int, boolean), que se puede llamar para notificar al marco acerca de los cambios en la visibilidad de una vista en una estructura virtual. También hay una sobrecarga del método para estructuras no virtuales. Sin embargo, las estructuras no virtuales, por lo general, no requieren que notifiques explícitamente el marco porque la clase View ya llama al método.

Android 8.1 también ofrece a los servicios de autocompletado una mayor posibilidad de ahorrar prestación de IU cuando se agrega compatibilidad con CustomDescription andValidator dentro de SaveInfo.

Las descripciones personalizadas son útiles para ayudar al servicio de autocompletado a aclarar lo que se está guardando; por ejemplo, cuando la pantalla contiene una tarjeta de crédito, podría mostrar un logotipo del banco de la tarjeta de crédito, los últimos cuatro dígitos del número de la tarjeta y la fecha de vencimiento. Para obtener más información, consulta la clase CustomDescription.

Los objetos Validator se usan para evitar mostrar la IU guardada de autocompletar cuando la condición Validator no se cumple. Para obtener más información, consulta la clase Validator junto con sus subclases, LuhnChecksumValidator y RegexValidator.

Notificaciones

Android 8.1 incluye los siguientes cambios en las notificaciones:

  • Las apps ahora solo pueden hacer que suene una alerta de notificación una vez por segundo. Los sonidos de alerta que superan esa frecuencia no se ponen en cola y se pierden. Este cambio no afecta otros aspectos del comportamiento de las notificaciones, y los mensajes de notificación se siguen publicando según lo esperado.
  • NotificationListenerService y ConditionProviderService no son compatibles con dispositivos Android con poca RAM que muestran true cuando se llama a ActivityManager.isLowRamDevice().

Actualización de EditText

A partir del nivel de API 27, el método EditText.getText() muestra un objeto Editable; anteriormente, mostraba CharSequence. Este cambio es compatible con versiones anteriores, ya que Editable implementa CharSequence.

La interfaz Editable proporciona una valiosa funcionalidad adicional. Por ejemplo, dado que Editable también implementa la interfaz Spannable, puedes aplicar lenguaje de marcado al contenido dentro de una instancia de EditText.

Acciones programáticas de Navegación segura

Con la implementación de WebView de la API de Navegación segura, tu app puede detectar si una instancia de WebView intenta navegar hacia una URL que Google clasificó como amenaza conocida. De manera predeterminada, WebView muestra un intersticial que advierte a los usuarios acerca de la amenaza conocida. Esta pantalla da a los usuarios la opción de cargar la URL de todas maneras o regresar a una página anterior que sea segura.

En Android 8.1, puedes definir de manera programática cómo responde tu app ante una amenaza conocida.

  • Puedes controlar el hecho de que tu app informe amenazas conocidas a Navegación segura.
  • Puedes hacer que tu app realice automáticamente una acción específica, como regresar a un estado seguro, cada vez que encuentre una URL que se haya clasificado como amenaza conocida.

Nota: Para una protección óptima contra amenazas conocidas, espera hasta que hayas inicializado Navegación segura para invocar el método WebView de un objeto loadUrl().

En el siguiente fragmento de código, se muestra la instrucción que puedes dar a las instancias de WebView de tu app para que siempre regresen a un estado seguro después de encontrar una amenaza conocida:

AndroidManifest.xml

    <manifest>
        <application>
            ...
            <meta-data android:name="android.webkit.WebView.EnableSafeBrowsing"
                       android:value="true" />
        </application>
    </manifest>

MyWebActivity.java

Kotlin

    private var superSafeWebView: WebView? = null
    private var safeBrowsingIsInitialized: Boolean = false

    // ...

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        superSafeWebView = WebView(this).apply {
            webViewClient = MyWebViewClient()
            safeBrowsingIsInitialized = false
            startSafeBrowsing(this@SafeBrowsingActivity, { success ->
                safeBrowsingIsInitialized = true
                if (!success) {
                    Log.e("MY_APP_TAG", "Unable to initialize Safe Browsing!")
                }
            })
        }
    }
    

Java

    private WebView superSafeWebView;
    private boolean safeBrowsingIsInitialized;

    // ...

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        superSafeWebView = new WebView(this);
        superSafeWebView.setWebViewClient(new MyWebViewClient());
        safeBrowsingIsInitialized = false;

        superSafeWebView.startSafeBrowsing(this, new ValueCallback<Boolean>() {
            @Override
            public void onReceiveValue(Boolean success) {
                safeBrowsingIsInitialized = true;
                if (!success) {
                    Log.e("MY_APP_TAG", "Unable to initialize Safe Browsing!");
                }
            }
        });
    }
    

MyWebViewClient.java

Kotlin

    class MyWebViewClient : WebViewClient() {
        // Automatically go "back to safety" when attempting to load a website that
        // Safe Browsing has identified as a known threat. An instance of WebView
        // calls this method only after Safe Browsing is initialized, so there's no
        // conditional logic needed here.
        override fun onSafeBrowsingHit(
                view: WebView,
                request: WebResourceRequest,
                threatType: Int,
                callback: SafeBrowsingResponse
        ) {
            // The "true" argument indicates that your app reports incidents like
            // this one to Safe Browsing.
            callback.backToSafety(true)
            Toast.makeText(view.context, "Unsafe web page blocked.", Toast.LENGTH_LONG).show()
        }
    }
    

Java

    public class MyWebViewClient extends WebViewClient {
        // Automatically go "back to safety" when attempting to load a website that
        // Safe Browsing has identified as a known threat. An instance of WebView
        // calls this method only after Safe Browsing is initialized, so there's no
        // conditional logic needed here.
        @Override
        public void onSafeBrowsingHit(WebView view, WebResourceRequest request,
                int threatType, SafeBrowsingResponse callback) {
            // The "true" argument indicates that your app reports incidents like
            // this one to Safe Browsing.
            callback.backToSafety(true);
            Toast.makeText(view.getContext(), "Unsafe web page blocked.",
                    Toast.LENGTH_LONG).show();
        }
    }
    

Extractor de miniaturas de video

La clase MediaMetadataRetriever tiene un nuevo método, getScaledFrameAtTime(), que encuentra un fotograma cerca de una posición de tiempo determinada y muestra un mapa de bits con la misma relación de aspecto que el fotograma de origen, pero escalado para ajustarse a un rectángulo de ancho y alto determinados. Esto es útil para generar imágenes en miniatura de un video.

Recomendamos utilizar este método en lugar de getFrameAtTime(), que puede desperdiciar memoria porque muestra un mapa de bits con la misma resolución que el video de origen. Por ejemplo, un fotograma de un video 4K sería un mapa de bits de 16 MB, mucho más grande de lo que necesitarías para una imagen en miniatura.

API de memoria compartida

Android 8.1 (nivel de API 27) presenta la nueva API SharedMemory. Esta clase te permite crear, asignar y administrar una instancia anónima de SharedMemory. Puedes establecer la protección de la memoria en un objeto SharedMemory para lectura y escritura, y, puesto que el objeto SharedMemory se puede dividir en parcelas, puedes pasarlo fácilmente a otro proceso mediante AIDL.

La API SharedMemory interopera con la facilidad ASharedMemory en el NDK. ASharedMemory da acceso a un descriptor de archivo, que luego se puede asignar para leer y escribir. Es una excelente manera de compartir grandes cantidades de datos entre apps o entre múltiples procesos dentro de una sola app.

API WallpaperColors

Android 8.1 (nivel de API 27) permite que tu fondo de pantalla animado proporcione información de color a la IU del sistema. Para ello, crea un objeto WallpaperColors a partir de un mapa de bits o un elemento de diseño, o usando tres colores seleccionados manualmente. También puedes recuperar esta información de color.

Para crear un objeto WallpaperColors, realiza una de las siguientes acciones:

  • Para crear un objeto WallpaperColors con tres colores, crea una instancia de la clase WallpaperColors. Para ello, pasa el color primario, el secundario y el terciario. El color primario no debe ser nulo.
  • Para crear un objeto WallpaperColors a partir de un mapa de bits, llama al método fromBitmap(). Para ello, pasa el origen del mapa de bits como parámetro.
  • Para crear un objeto WallpaperColors a partir de un elemento de diseño, llama al método fromDrawable(). Para ello, pasa el elemento de diseño de origen como parámetro.

Para recuperar los detalles de color primario, secundario o terciario del fondo de pantalla, llama a los siguientes métodos:

  • getPrimaryColor() muestra el color más representativo visualmente del fondo de pantalla.
  • getSecondaryColor() muestra el segundo color más preeminente del fondo de pantalla.
  • El método getTertiaryColor() muestra el tercer color más preeminente del fondo de pantalla.

Para notificar al sistema sobre cualquier cambio significativo de color en tu fondo de pantalla animado, llama al método notifyColorsChanged(). Este método activa un evento de ciclo de vida onComputeColors() en el que tienes la oportunidad de proporcionar un nuevo objeto WallpaperColors.

Para agregar un objeto de escucha de cambios de color, puedes llamar al método addOnColorsChangedListener(). También puedes llamar al método getWallpaperColors() para recuperar los colores primarios de un fondo de pantalla.

Actualizaciones de huellas digitales

La clase FingerprintManager incorporó los siguientes códigos de error:

  • FINGERPRINT_ERROR_LOCKOUT_PERMANENT: El usuario intentó desbloquear su dispositivo demasiadas veces con el lector de huellas digitales.
  • FINGERPRINT_ERROR_VENDOR: Se produjo un error específico del proveedor en el lector de huellas digitales.

Actualizaciones de criptografía

En Android 8.1, se realizaron los siguientes cambios de criptografía:

  • Se implementaron nuevos algoritmos en Conscrypt. La implementación de Conscrypt se usa preferentemente sobre la implementación existente de Bouncy Castle. Los nuevos algoritmos incluyen los siguientes:
    • AlgorithmParameters:GCM
    • KeyGenerator:AES
    • KeyGenerator:DESEDE
    • KeyGenerator:HMACMD5
    • KeyGenerator:HMACSHA1
    • KeyGenerator:HMACSHA224
    • KeyGenerator:HMACSHA256
    • KeyGenerator:HMACSHA384
    • KeyGenerator:HMACSHA512
    • SecretKeyFactory:DESEDE
    • Signature:NONEWITHECDSA
  • Cipher.getParameters().getParameterSpec(IvParameterSpec.class) ya no funciona para algoritmos que usan GCM. En su lugar, usa getParameterSpec(GCMParameterSpec.class).
  • Se refactorizaron muchas clases internas de Conscrypt asociadas con TLS. Dado que los desarrolladores a veces acceden a estas de manera reflexiva, se dejaron correcciones para admitir el uso anterior, pero cambiaron algunos detalles. Por ejemplo, los sockets anteriormente eran del tipo OpenSSLSocketImpl, pero ahora son del tipo ConscryptFileDescriptorSocket o ConscryptEngineSocket, los cuales extienden OpenSSLSocketImpl.
  • Los métodos SSLSession que se usaban para arrojar IllegalArgumentException al pasar una referencia nula ahorra arrojan NullPointerException.
  • El RSA KeyFactory ya no permite la generación de claves a partir de conjuntos de bytes que son más grandes que la clave codificada. Las llamadas a generatePrivate() y generatePublic() que proporcionen una KeySpec donde la estructura de la clave no llene todo el búfer darán como resultado una InvalidKeySpecException.
  • Cuando una lectura de socket se interrumpía al cerrar el socket, Conscrypt solía mostrar -1 de la lectura. La lectura ahora arroja SocketException.
  • Se cambió el conjunto de certificados de CA raíz, lo cual, principalmente, quita una gran cantidad de certificados obsoletos, pero también quita los certificados raíz para WoSign y StartCom. Para obtener más información sobre esta decisión, consulta la entrada del blog de seguridad de Google, Eliminación final de la confianza en los certificados de WoSign y StartCom.