Características y API de Android 8.1

Android 8.1 (nivel de API 27) incluye 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 para optimizar la experiencia de Android para miles de millones de personas que se conectan en línea en todo el mundo. A partir de Android 8.1, estamos convirtiendo Android en una excelente plataforma para dispositivos básicos. Las funciones de la configuración de Android Oreo (edición Go) incluyen lo siguiente:

  • Optimizaciones de memoria. Se mejoró el uso de memoria en toda la plataforma para garantizar que las apps puedan ejecutarse de manera eficiente en dispositivos con 1 GB o menos de RAM.
  • Opciones de segmentación flexibles. Nuevas constantes de funciones de hardware para permitirte segmentar la distribución de tus apps para dispositivos con RAM normal o baja a través de Google Play
  • Google Play. Si bien todas las apps estarán disponibles en los dispositivos que ejecuten Android Oreo (edición Go), Google Play les dará visibilidad a las apps que los desarrolladores optimizaron específicamente para brindar una excelente experiencia a miles de millones de personas con los lineamientos de Building for Billions.

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

API de Neural Networks

La API de Neural Networks proporciona inferencias y procesamiento acelerados para frameworks de aprendizaje automático integrados en el dispositivo, como TensorFlow Lite, la biblioteca de AA multiplataforma de Google para dispositivos móviles, así como Caffe2 y otros. Visita el repositorio de código abierto de TensorFlow Lite para descargar y consultar la documentación. TensorFlow Lite funciona con la API de Neural Networks para ejecutar modelos como MobileNets, Inception v3 y Smart Reply de manera eficiente en tu dispositivo móvil.

Actualizaciones de Autofill Framework

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

La clase BaseAdapter ahora incluye el método setAutofillOptions(), que te permite proporcionar representaciones de cadenas de los valores en un adaptador. Esto es útil para los controles de spinner que generan de forma dinámica los valores en sus adaptadores. Por ejemplo, puedes usar el método setAutofillOptions() para proporcionar una representación de cadena de la lista de años que los usuarios pueden elegir como parte de la fecha de vencimiento de una tarjeta de crédito. Los servicios de autocompletado pueden usar la representación de cadena para completar de forma adecuada las vistas que requieren los datos.

Además, la clase AutofillManager incluye el método notifyViewVisibilityChanged(View, int, boolean), al que puedes llamar para notificar al framework sobre 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 no suelen requerir que notifiques explícitamente al framework, ya que la clase View ya llama al método.

Android 8.1 también les brinda a los servicios de autocompletado más capacidad para personalizar la IU de guardado, ya que agrega compatibilidad con CustomDescription and Validator dentro de SaveInfo.

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

Los objetos Validator se usan para evitar mostrar la IU de guardado de Autocompletar cuando no se cumple la condición del validador. 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 superen esta tasa 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 previsto.
  • NotificationListenerService y ConditionProviderService no son compatibles con dispositivos Android con poca RAM que devuelven true cuando se llama a ActivityManager.isLowRamDevice().

Actualización de EditText

A partir del nivel de API 27, el método EditText.getText() devuelve un Editable; anteriormente, devolvía un CharSequence. Este cambio es retrocompatible, ya que Editable implementa CharSequence.

La interfaz Editable proporciona una valiosa funcionalidad adicional. Por ejemplo, como Editable también implementa la interfaz Spannable, puedes aplicar un 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 cuando una instancia de WebView intenta navegar a una URL que Google clasificó como amenaza conocida. De forma predeterminada, WebView muestra un anuncio intersticial que advierte a los usuarios sobre la amenaza conocida. En esta pantalla, los usuarios pueden cargar la URL de todos modos o volver a una página anterior que sea segura.

En Android 8.1, puedes definir de forma programática cómo responde tu app a una amenaza conocida:

  • Puedes controlar si tu app informa sobre amenazas conocidas a la Navegación segura.
  • Puedes hacer que tu app realice automáticamente una acción en particular, como volver a la seguridad, cada vez que encuentre una URL que Navegación Segura clasifique como una amenaza conocida.

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

En los siguientes fragmentos de código, se muestra cómo puedes indicarle a las instancias de WebView de tu app que siempre vuelvan a un lugar seguro después de detectar 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 devuelve un mapa de bits con la misma relación de aspecto que el fotograma de origen, pero ajustado para que quepa en un rectángulo de ancho y alto determinados. Esto es útil para generar imágenes en miniatura de un video.

Te recomendamos que uses este método en lugar de getFrameAtTime(), que puede desperdiciar memoria porque devuelve un mapa de bits con la misma resolución que el video fuente. Por ejemplo, un fotograma de un video en 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 una nueva API de SharedMemory. Esta clase te permite crear, asignar y administrar una instancia anónima de SharedMemory. Estableces la protección de memoria en un objeto SharedMemory para lectura o escritura y, como el objeto SharedMemory es Parcelable, puedes pasarlo fácilmente a otro proceso a través de AIDL.

La API de SharedMemory interoperará con la instalación de 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 varios procesos dentro de una sola app.

API WallpaperColors

Android 8.1 (nivel de API 27) permite que tu fondo 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, haz una de las siguientes acciones:

  • Para crear un objeto WallpaperColors con tres colores, crea una instancia de la clase WallpaperColors pasando el color primario, el secundario y el terciario. El color principal no debe ser nulo.
  • Para crear un objeto WallpaperColors a partir de un mapa de bits, llama al método fromBitmap() y pasa la fuente 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() y pasa la fuente del elemento de diseño como parámetro.

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

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

Para notificar al sistema sobre cualquier cambio significativo de color en tu fondo 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 para los cambios de color, puedes llamar al método addOnColorsChangedListener(). También puedes llamar al método getWallpaperColors() para recuperar los colores principales de un fondo de pantalla.

Actualizaciones de huellas digitales

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

  • FINGERPRINT_ERROR_LOCKOUT_PERMANENT: El usuario intentó desbloquear el dispositivo demasiadas veces con el lector de huellas dactilares.
  • 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 de forma preferencial sobre la implementación existente de Bouncy Castle. Entre los algoritmos nuevos, se 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 los algoritmos que usan GCM. En su lugar, usa getParameterSpec(GCMParameterSpec.class).
  • Se refactorizaron muchas clases internas de Conscrypt asociadas con TLS. Dado que, a veces, los desarrolladores acceden a estos de forma reflexiva, se dejaron shims para admitir el uso anterior, pero cambiaron algunos detalles. Por ejemplo, antes los sockets eran de tipo OpenSSLSocketImpl, pero ahora son de tipo ConscryptFileDescriptorSocket o ConscryptEngineSocket, los cuales extienden OpenSSLSocketImpl.
  • Los métodos SSLSession que se usaban para arrojar IllegalArgumentException cuando se pasaba una referencia nula ahora arrojan NullPointerException.
  • El objeto KeyFactory de RSA ya no permite la generación de claves a partir de arrays de bytes que son más grandes que la clave codificada. Las llamadas a generatePrivate() y generatePublic() que proporcionan un KeySpec en el que la estructura de la clave no llena todo el búfer generarán un InvalidKeySpecException.
  • Cuando una lectura de socket se interrumpe porque se cierra el socket, Conscrypt solía devolver -1 desde la lectura. La lectura ahora arroja SocketException.
  • Se cambió el conjunto de certificados de CA raíz, principalmente quitando una gran cantidad de certificados obsoletos, pero también quitando los certificados raíz de WoSign y StartCom. Para obtener más información sobre esta decisión, consulta la entrada del blog de Google Security, Eliminación final de la confianza en los certificados de WoSign y StartCom.