Cómo optimizar tu app para el autocompletado

Las apps que usan vistas estándar funcionan con Autofill Framework sin necesitar una configuración especial. También puedes optimizar el funcionamiento de tu app con el framework.

Cómo configurar el entorno de autocompletado

En esta sección, se describe cómo configurar la función básica de autocompletado para tu app.

Cómo configurar un servicio de autocompletado

Debes configurar el servicio de autocompletado en tu dispositivo para que tu app use Autofill Framework. Aunque la mayoría de los teléfonos y tablets que ejecutan Android 8.0 (nivel de API 26) y versiones posteriores incluyen un servicio de autocompletado, te recomendamos que uses un servicio de prueba cuando pruebes la app, como el servicio de autocompletado en la muestra de Autofill Framework de Android. Cuando uses un emulador, configura explícitamente un servicio de autocompletado, ya que es posible que el emulador no incluya un servicio predeterminado.

Después de instalar el servicio de autocompletado de prueba desde la app de ejemplo, habilítalo. Para ello, navega a Configuración > Sistema > Idiomas y entrada > Avanzado > Ayuda con métodos de entrada > Servicio Autocompletar.

Si deseas obtener más información sobre la configuración de un emulador para probar el autocompletado, consulta Cómo probar tu app con autocompletado.

Cómo proporcionar sugerencias de autocompletado

El servicio de autocompletado determina el tipo de cada vista con la heurística. Sin embargo, si tu app se basa en esas heurísticas, el comportamiento del autocompletado puede cambiar inesperadamente a medida que la actualizas. Para asegurarte de que el servicio de autocompletado identifique de manera correcta los factores de forma de tu app, proporciona sugerencias de autocompletado.

Puedes configurar sugerencias de autocompletado con el atributo android:autofillHints. En el siguiente ejemplo, se configura una sugerencia "password" en un EditText:

<EditText
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:autofillHints="password" />

También puedes configurar sugerencias de manera programática con el método setAutofillHints() como se muestra en el siguiente ejemplo:

Kotlin

val password = findViewById<EditText>(R.id.password)
password.setAutofillHints(View.AUTOFILL_HINT_PASSWORD)

Java

EditText password = findViewById(R.id.password);
password.setAutofillHints(View.AUTOFILL_HINT_PASSWORD);

Cómo incluir constantes de sugerencias predefinidas

Autofill Framework no valida las sugerencias; tan solo se pasan sin cambio ni validación al servicio de autocompletado. Si bien puedes usar cualquier valor, las clases View y HintConstants de AndroidX contienen listas de constantes de sugerencias compatibles oficialmente.

Con una combinación de esas constantes, puedes compilar diseños para situaciones comunes de autocompletado:

Credenciales de la cuenta

En un formulario de acceso, puedes incluir sugerencias de credenciales de cuenta, como AUTOFILL_HINT_USERNAME y AUTOFILL_HINT_PASSWORD.

Cuando se crea una cuenta nueva, o cuando alguien cambia su nombre de usuario y contraseña, puedes usar AUTOFILL_HINT_NEW_USERNAME y AUTOFILL_HINT_NEW_PASSWORD.

Información de tarjeta de crédito

Cuando solicites información de tarjetas de crédito, puedes usar sugerencias como AUTOFILL_HINT_CREDIT_CARD_NUMBER y AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE.

Para las fechas de vencimiento de las tarjetas de crédito, realiza una de las siguientes acciones:

Dirección física

Para los campos del formulario relacionados con la dirección física, puedes usar sugerencias como las siguientes:

Nombres de personas

Cuando solicites nombres de personas, puedes usar sugerencias como las siguientes:

Números de teléfono

Para números de teléfono, puedes usar lo siguiente:

Contraseña de un solo uso (OTP)

Para una contraseña de un solo uso en una vista única, puedes utilizar AUTOFILL_HINT_SMS_OTP.

Cuando se usan varias vistas y cada una se mapea a un solo dígito de la OTP, puedes utilizar el método generateSmsOtpHintForCharacterPosition() para generar sugerencias por carácter.

Cómo marcar campos como importantes para el autocompletado

Puedes incluir los campos individuales en tu app en una estructura de vistas para fines de autocompletado. De forma predeterminada, las vistas usan el modo IMPORTANT_FOR_AUTOFILL_AUTO, que le permite a Android usar su heurística para determinar si una vista es importante para el autocompletado.

Sin embargo, hay casos en los que una vista, una estructura de vistas o toda la actividad no son importantes para el autocompletado:

  • Un campo CAPTCHA en una actividad de acceso
  • Una vista en la que el usuario crea contenido, como un editor de texto o de hoja de cálculo
  • Las vistas en algunas actividades dentro de los juegos, como las que muestran contenido

Puedes establecer la importancia de una vista para el autocompletado con el atributo android:importantForAutofill:

<TextView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:importantForAutofill="no" />

El valor de importantForAutofill puede ser cualquiera de los siguientes:

auto
Deja que el sistema Android use su heurística para determinar si la vista es importante para el autocompletado.
no
Esta vista no es importante para el autocompletado.
noExcludeDescendants
Esta vista y sus elementos secundarios no son importantes para el autocompletado.
yes
Esta vista es importante para el autocompletado.
yesExcludeDescendants
Esta vista es importante para el autocompletado, pero sus elementos secundarios no lo son.

También puedes usar el método setImportantForAutofill():

Kotlin

val captcha = findViewById<TextView>(R.id.captcha)
captcha.setImportantForAutofill(View.IMPORTANT_FOR_AUTOFILL_NO)

Java

TextView captcha = findViewById(R.id.captcha);
captcha.setImportantForAutofill(View.IMPORTANT_FOR_AUTOFILL_NO);

Puedes declarar los casos de uso de ejemplo anteriores como no importantes para el autocompletado de la siguiente manera:

  • Un campo CAPTCHA en una actividad de acceso: usa android:importantForAutofill="no" o IMPORTANT_FOR_AUTOFILL_NO para marcar esta vista como no importante.
  • Una vista en la que el usuario crea contenido: usa android:importantForAutofill="noExcludeDescendants" o IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS para marcar toda la estructura de vistas como no importante.
  • Las vistas en algunas actividades dentro de los juegos: usa android:importantForAutofill="noExcludeDescendants" o IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS para marcar toda la estructura de vistas como no importante.

Cómo asociar datos de un sitio web y de apps para dispositivos móviles

Los servicios de autocompletado, como Autocompletar con Google, pueden compartir datos de acceso de usuarios entre navegadores y dispositivos Android después de asociar la app y un sitio web. Cuando un usuario selecciona el mismo servicio de autocompletado en ambas plataformas, el acceso a tu app web hace que sus credenciales de acceso estén disponibles para el autocompletado cuando accedan a tu app para Android correspondiente.

Para asociar tu app para Android con tu sitio web, debes alojar un vínculo de recursos digitales con la relación delegate_permission/common.get_login_creds en tu sitio. Luego, debes declarar la asociación en el archivo AndroidManifest.xml de tu app. Si deseas obtener instrucciones a fin de asociar tu sitio web con tu app para Android, consulta Cómo habilitar el acceso automático en todas las apps y sitios web.

Cómo completar un flujo de trabajo de autocompletado

En esta sección, se describen situaciones específicas en las que puedes seguir algunos pasos para mejorar la funcionalidad de autocompletado de los usuarios de tu app.

Cómo determinar si está habilitada la función de autocompletado

Los usuarios pueden habilitar o inhabilitar el autocompletado, así como cambiar el servicio de autocompletado, navegando a Configuración > Sistema > Idiomas y entrada > Avanzado > Ayuda con métodos de entrada > Servicio de autocompletado. Tu app no puede anular los parámetros de configuración de autocompletado del usuario, pero puedes implementar funciones de autocompletado adicionales en tu app, o en vistas específicas de esta, si la función de autocompletado está disponible para el usuario.

Por ejemplo, TextView muestra una entrada de autocompletado en el menú ampliado si el autocompletado está habilitado para el usuario. Para verificar si está habilitado, llama al método isEnabled() del objeto AutofillManager.

Para asegurarte de que tu experiencia de registro y acceso esté optimizada para los usuarios sin autocompletado, implementa el acceso con One Tap.

Cómo forzar una solicitud de autocompletado

En ocasiones, es posible que debas forzar una solicitud de autocompletado para que ocurra en respuesta a una acción del usuario. Por ejemplo, TextView ofrece un elemento de menú de autocompletado cuando el usuario mantiene presionada la vista. En el siguiente ejemplo de código, se muestra cómo forzar una solicitud de autocompletado:

Kotlin

fun eventHandler(view: View) {
    val afm = requireContext().getSystemService(AutofillManager::class.java)
    afm?.requestAutofill(view)
}

Java

public void eventHandler(View view) {
    AutofillManager afm = context.getSystemService(AutofillManager.class);
    if (afm != null) {
        afm.requestAutofill(view);
    }
}

También puedes usar el método cancel() para cancelar el contexto de autocompletado actual. Esto puede ser útil si tienes un botón que borra los campos de una página de acceso.

Cómo usar el tipo correcto de autocompletado para los datos en los controles del selector

Los selectores pueden ser útiles para el autocompletado, ya que proporcionan una IU que permite a los usuarios cambiar el valor de un campo que almacena datos de fecha y hora. Por ejemplo, en un formulario de tarjeta de crédito, un selector de fecha permite que los usuarios ingresen o cambien la fecha de vencimiento de su tarjeta de crédito. Sin embargo, debes usar otra vista, como EditText, para mostrar datos cuando no esté visible el selector.

De forma nativa, un objeto EditText espera autocompletar datos de tipo AUTOFILL_TYPE_TEXT. Si estás usando un tipo diferente de datos, crea una vista personalizada que herede contenido de EditText y use los métodos obligatorios para procesar el tipo de datos correspondiente. Por ejemplo, si tienes un campo de datos, implementa los métodos con una lógica que procese correctamente valores de tipo AUTOFILL_TYPE_DATE.

Cuando especificas el tipo de datos de autocompletado, el servicio de autocompletado puede crear una representación adecuada de los datos que se muestran en la vista. Para obtener más información, consulta Cómo usar los selectores con autocompletado.

Cómo finalizar el contexto de autocompletado

Autofill Framework guarda la entrada del usuario para usarla más tarde y muestra el diálogo "¿Save for autofill?" cuando finaliza el contexto de autocompletado. Por lo general, el contexto de autocompletado finaliza cuando se completa una actividad. Sin embargo, hay algunas situaciones en las que debes notificar al framework de forma explícita, por ejemplo, si usas la misma actividad, pero diferentes fragmentos para las pantallas de acceso y de contenido. En esas situaciones, puedes finalizar explícitamente el contexto llamando a AutofillManager.commit().

Compatibilidad para vistas personalizadas

Las vistas personalizadas pueden especificar los metadatos expuestos en Autofill Framework mediante la API de autocompletado. Algunas vistas actúan como un contenedor de elementos secundarios virtuales, como las que contienen una IU procesada por OpenGL. Esas vistas deben usar la API para especificar la estructura de la información que se usa en la app antes de que puedan trabajar con Autofill Framework.

Si tu app usa vistas personalizadas, ten en cuenta las siguientes situaciones:

  • La vista personalizada proporciona una estructura de vistas estándar o predeterminada.
  • La vista personalizada tiene una estructura virtual o una estructura de vistas que no está disponible para Autofill Framework.

Vistas personalizadas con estructura de vistas estándar

Las vistas personalizadas pueden definir los metadatos que el autocompletado necesita para funcionar. Asegúrate de que la vista personalizada administre los metadatos de forma correcta para trabajar con Autofill Framework. Tu vista personalizada debe realizar las siguientes acciones:

  • Procesar el valor de autocompletado que el framework envía a tu app
  • Proporcionar el tipo y el valor de autocompletado en el framework

Cuando se activa el autocompletado, Autofill Framework llama a autofill() en tu vista y envía el valor que se debe usar. Implementa autofill() para especificar cómo tu vista personalizada procesa el valor de autocompletado.

La vista debe especificar un tipo y valor de autocompletado anulando los métodos getAutofillType() y getAutofillValue(), respectivamente.

Por último, el autocompletado no debe llenar la vista si el usuario no puede proporcionar un valor para la vista en su estado actual (por ejemplo, si está inhabilitada). En estos casos, getAutofillType() debe mostrar AUTOFILL_TYPE_NONE, getAutofillValue() debe mostrar null y autofill() no debe hacer nada.

Los siguientes casos requieren pasos adicionales para funcionar correctamente en el framework:

  • La vista personalizada se puede editar.
  • La vista personalizada contiene datos sensibles.

La vista personalizada se puede editar

Si se puede editar la vista, notifica a Autofill Framework acerca de los cambios llamando a notifyValueChanged() en el objeto AutofillManager.

La vista personalizada contiene datos sensibles

Si una vista contiene información de identificación personal (PII), como direcciones de correo electrónico, números de tarjeta de crédito y contraseñas, se debe marcar como sensible.

En general, las vistas cuyo contenido proviene de recursos estáticos no contienen datos sensibles, pero las vistas cuyo contenido se configura de forma dinámica pueden tenerlos. Por ejemplo, una etiqueta que dice Ingresa tu nombre de usuario no contiene datos sensibles, mientras que una etiqueta que dice Hola, Juan sí lo hace.

Nota: Autofill Framework supone que todos los datos son sensibles de forma predeterminada. Puedes marcar los datos que no son sensibles.

Para marcar si una vista contiene datos sensibles, implementa onProvideAutofillStructure() y llama a setDataIsSensitive() en el objeto ViewStructure.

En el siguiente ejemplo de código, se muestra cómo marcar los datos en la estructura de vistas como no sensibles:

Kotlin

override fun onProvideAutofillStructure(structure: ViewStructure, flags: Int) {
    super.onProvideAutofillStructure(structure, flags)

    structure.setDataIsSensitive(false)
}

Java

@Override
public void onProvideAutofillStructure(ViewStructure structure, int flags) {
    super.onProvideAutofillStructure(structure, flags);

    structure.setDataIsSensitive(false);
}

Si la vista solo acepta valores predefinidos, puedes usar el método setAutofillOptions() para configurar las opciones que se pueden usar para autocompletar la vista. En particular, las vistas cuyo tipo de autocompletado es AUTOFILL_TYPE_LIST deben usar este método, ya que el servicio de autocompletado funciona mejor si conoce las opciones disponibles para llenar la vista.

Las vistas que usan un adaptador, como un Spinner son un caso similar. Por ejemplo, un ícono giratorio que proporciona años creados de forma dinámica (según el año actual) para usar en campos de vencimiento de tarjetas de crédito puede implementar el método getAutofillOptions() de la interfaz Adapter para ofrecer una lista de años.

Las vistas que usan un ArrayAdapter también pueden proporcionar listas de valores. ArrayAdapter configura automáticamente las opciones de autocompletado para los recursos estáticos. Si proporcionas los valores de forma dinámica, anula getAutofillOptions().

Vistas personalizadas con estructura virtual

Autofill Framework requiere una estructura de vistas para poder editar y guardar la información en la IU de tu app. La estructura de vistas no está disponible para el framework en las siguientes situaciones:

  • La app usa un motor de renderización de bajo nivel, como OpenGL, para renderizar la IU.
  • La app usa una instancia de Canvas para dibujar la IU.

En esos casos, puedes especificar una estructura de vistas implementado onProvideAutofillVirtualStructure() y siguiendo estos pasos:

  1. Aumenta el recuento de elementos secundarios de la estructura de vistas llamando a addChildCount().
  2. Para agregar un elemento secundario, llama a newChild().
  3. Configura el ID de autocompletado para el elemento secundario llamando a setAutofillId().
  4. Configura las propiedades relevantes, como el valor y el tipo de autocompletado.
  5. Si los datos del elemento secundario virtual son sensibles, pasa true a setDataIsSensitive(). De lo contrario, pasa false.

En el siguiente fragmento de código, se muestra cómo crear un nuevo elemento secundario en la estructura virtual:

Kotlin

override fun onProvideAutofillVirtualStructure(structure: ViewStructure, flags: Int) {

    super.onProvideAutofillVirtualStructure(structure, flags)

    // Create a new child in the virtual structure.
    structure.addChildCount(1)
    val child = structure.newChild(childIndex)

    // Set the autofill ID for the child.
    child.setAutofillId(structure.autofillId!!, childVirtualId)

    // Populate the child by providing properties such as value and type.
    child.setAutofillValue(childAutofillValue)
    child.setAutofillType(childAutofillType)

    // Some children can provide a list of values, such as when the child is
    // a spinner.
    val childAutofillOptions = arrayOf<CharSequence>("option1", "option2")
    child.setAutofillOptions(childAutofillOptions)

    // Just like other types of views, mark the data as sensitive when
    // appropriate.
    val sensitive = !contentIsSetFromResources()
    child.setDataIsSensitive(sensitive)
}

Java

@Override
public void onProvideAutofillVirtualStructure(ViewStructure structure, int flags) {

    super.onProvideAutofillVirtualStructure(structure, flags);

    // Create a new child in the virtual structure.
    structure.addChildCount(1);
    ViewStructure child =
            structure.newChild(childIndex);

    // Set the autofill ID for the child.
    child.setAutofillId(structure.getAutofillId(), childVirtualId);

    // Populate the child by providing properties such as value and type.
    child.setAutofillValue(childAutofillValue);
    child.setAutofillType(childAutofillType);

    // Some children can provide a list of values, such as when the child is
    // a spinner.
    CharSequence childAutofillOptions[] = { "option1", "option2" };
    child.setAutofillOptions(childAutofillOptions);

    // Just like other types of views, mark the data as sensitive when
    // appropriate.
    boolean sensitive = !contentIsSetFromResources();
    child.setDataIsSensitive(sensitive);
}

Cuando cambian los elementos de una estructura virtual, notifica al framework con la realización de las siguientes tareas:

  • Si cambia el foco de los elementos secundarios, llama a notifyViewEntered() y notifyViewExited() en el objeto AutofillManager.
  • Si cambia el valor de un elemento secundario, llama a notifyValueChanged() en el objeto AutofillManager.
  • Si la jerarquía de vistas ya no está disponible porque el usuario completó un paso del flujo de trabajo, como cuando accede mediante un formulario de acceso, llama a commit() en el objeto AutofillManager.
  • Si la jerarquía de vistas no es válida porque el usuario canceló un paso del flujo de trabajo, como cuando presiona un botón que borra un formulario de acceso, llama a cancel() en el objeto AutofillManager.

Cómo usar devoluciones de llamada en eventos de autocompletado

Si tu app proporciona sus propias vistas de autocompletado, necesitas un mecanismo que le indique que habilite o inhabilite las vistas en respuesta a los cambios en la indicación visual de autocompletado de la IU. Autofill Framework proporciona este mecanismo en la forma de AutofillCallback.

Esta clase proporciona el método onAutofillEvent(View, int), al que la app llama después de un cambio en el estado de autocompletado asociado a una vista. También hay una versión sobrecargada de este método, que incluye un parámetro childId que tu app puede usar con vistas virtuales. Los estados disponibles se definen como constantes en la devolución de llamada.

Puedes registrar una devolución de llamada con un método registerCallback() de la clase AutofillManager. En el siguiente ejemplo de código, se muestra cómo declarar una devolución de llamada para eventos de autocompletado:

Kotlin

val afm = context.getSystemService(AutofillManager::class.java)

afm?.registerCallback(object : AutofillManager.AutofillCallback() {
    // For virtual structures, override
    // onAutofillEvent(View view, int childId, int event) instead.
    override fun onAutofillEvent(view: View, event: Int) {
        super.onAutofillEvent(view, event)
        when (event) {
            EVENT_INPUT_HIDDEN -> {
                // The autofill affordance associated with the view was hidden.
            }
            EVENT_INPUT_SHOWN -> {
                // The autofill affordance associated with the view was shown.
            }
            EVENT_INPUT_UNAVAILABLE -> {
                // Autofill isn't available.
            }
        }

    }
})

Java

AutofillManager afm = getContext().getSystemService(AutofillManager.class);

afm.registerCallback(new AutofillManager.AutofillCallback() {
    // For virtual structures, override
    // onAutofillEvent(View view, int childId, int event) instead.
    @Override
    public void onAutofillEvent(@NonNull View view, int event) {
        super.onAutofillEvent(view, event);
        switch (event) {
            case EVENT_INPUT_HIDDEN:
                // The autofill affordance associated with the view was hidden.
                break;
            case EVENT_INPUT_SHOWN:
                // The autofill affordance associated with the view was shown.
                break;
            case EVENT_INPUT_UNAVAILABLE:
                // Autofill isn't available.
                break;
        }
    }
});

Cuando llegue el momento de quitar la devolución de llamada, usa el método unregisterCallback().

Cómo personalizar el elemento de diseño destacado del autocompletado

Cuando se autocompleta una vista, la plataforma renderiza un Drawable sobre la vista para indicar que se autocompletó su contenido. De forma predeterminada, el elemento de diseño es un rectángulo sólido con un color translúcido apenas más oscuro que el color del tema que se usa para dibujar fondos. No es necesario cambiar el elemento de diseño, pero se puede personalizar con la anulación del elemento android:autofilledHighlight del tema que usa la aplicación o la actividad, como se muestra en este ejemplo:

res/values/styles.xml

<resources>
    <style name="MyAutofilledHighlight" parent="...">
        <item name="android:autofilledHighlight">@drawable/my_drawable</item>
    </style>
</resources>

res/drawable/my_drawable.xml

<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="#4DFF0000" />
</shape>

AndroidManifest.xml

<application ...
    android:theme="@style/MyAutofilledHighlight">
<!-- or -->
<activity ...
    android:theme="@style/MyAutofilledHighlight">

Cómo autenticar para el autocompletado

Un servicio de autocompletado puede requerir que el usuario se autentique antes de que el servicio pueda completar campos en tu app, en cuyo caso el sistema Android inicia la actividad de autenticación del servicio como parte de la pila de tu actividad.

No necesitas actualizar tu app para admitir la autenticación, porque esta ocurre dentro del servicio. Sin embargo, debes asegurarte de que la estructura de vistas de la actividad se conserve cuando se reinicie la actividad (por ejemplo, creando la estructura de vistas en onCreate(), no en onStart() ni onResume()).

Puedes verificar cómo se comporta tu app cuando un servicio de autocompletado requiere autenticación. Para ello, utiliza HeuristicsService de la muestra AutofillFramework y configúralo para requerir autenticación de respuesta de completado. También puedes usar la muestra BadViewStructureCreationSignInActivity para emular esta cuestión.

Cómo asignar IDs de autocompletado a vistas recicladas

Los contenedores que reciclan vistas, como la clase RecyclerView, son útiles para las apps que necesitan mostrar listas de desplazamiento de elementos basadas en grandes conjuntos de datos. A medida que el contenedor se desplaza, el sistema reutiliza las vistas del diseño, pero las vistas tienen contenido nuevo.

Si se completa el contenido inicial de una vista reciclada, el servicio de autocompletado retiene el significado lógico de las vistas utilizando sus IDs de autocompletado. Surge un problema cuando, a medida que el sistema reutiliza las vistas del diseño, los IDs lógicos de las vistas siguen siendo iguales, lo que provoca que los datos de autocompletado incorrectos del usuario se asocien con un ID de autocompletado.

Para solucionar este problema en dispositivos que ejecutan Android 9 (nivel de API 28) y versiones posteriores, puedes administrar explícitamente el ID de autocompletado de las vistas que usa RecyclerView con estos métodos:

  • El método getNextAutofillId() obtiene un nuevo ID de autocompletado que es exclusivo de la actividad.
  • El método setAutofillId() configura el ID de autocompletado único y lógico de esta vista en la actividad.

Cómo abordar problemas conocidos

En esta sección, se presentan soluciones alternativas a problemas conocidos dentro de Autofill Framework.

La función Autocompletar hace que las apps fallen en Android 8.0 y 8.1

En Android 8.0 (nivel de API 26) y 8.1 (nivel de API 27), el autocompletado puede hacer que tu app falle en determinadas situaciones. Para solucionar cualquier problema potencial, etiqueta las vistas que no se autocompletan con importantForAutofill=no. También puedes etiquetar toda la actividad con importantForAutofill=noExcludeDescendants.

Los diálogos que cambiaron de tamaño no se tienen en cuenta para el autocompletado

En Android 8.1 (nivel de API 27) y versiones anteriores, si una vista de un diálogo cambia de tamaño después de mostrarse, no se considera para autocompletado. Esas vistas no están incluidas en el objeto AssistStructure que el sistema Android envía al servicio de autocompletado. Como resultado, el servicio no puede completar las vistas.

Para evitar ese problema, reemplaza la propiedad token de los parámetros de la ventana de diálogo con la propiedad token de la actividad que crea el diálogo. Después de validar la habilitación del autocompletado, guarda los parámetros de la ventana en el método onWindowAttributesChanged() de la clase que hereda de Dialog. Luego, reemplaza la propiedad token de los parámetros guardados con la propiedad token de la actividad superior en el método onAttachedToWindow().

En el siguiente fragmento de código, se muestra una clase que implementa la solución alternativa:

Kotlin

class MyDialog(context: Context) : Dialog(context) {

    // Used to store the dialog window parameters.
    private var token: IBinder? = null

    private val isDialogResizedWorkaroundRequired: Boolean
        get() {
            if (Build.VERSION.SDK_INT != Build.VERSION_CODES.O || Build.VERSION.SDK_INT != Build.VERSION_CODES.O_MR1) {
                return false
            }
            val autofillManager = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                context.getSystemService(AutofillManager::class.java)
            } else {
                null
            }
            return autofillManager?.isEnabled ?: false
        }

    override fun onWindowAttributesChanged(params: WindowManager.LayoutParams) {
        if (params.token == null && token != null) {
            params.token = token
        }

        super.onWindowAttributesChanged(params)
    }

    override fun onAttachedToWindow() {
        if (isDialogResizedWorkaroundRequired) {
            token = ownerActivity!!.window.attributes.token
        }

        super.onAttachedToWindow()
    }

}

Java

public class MyDialog extends Dialog {

    public MyDialog(Context context) {
        super(context);
    }

    // Used to store the dialog window parameters.
    private IBinder token;

    @Override
    public void onWindowAttributesChanged(WindowManager.LayoutParams params) {
        if (params.token == null && token != null) {
            params.token = token;
        }

        super.onWindowAttributesChanged(params);
    }

    @Override
    public void onAttachedToWindow() {
        if (isDialogResizedWorkaroundRequired()) {
            token = getOwnerActivity().getWindow().getAttributes().token;
        }

        super.onAttachedToWindow();
    }

    private boolean isDialogResizedWorkaroundRequired() {
        if (Build.VERSION.SDK_INT != Build.VERSION_CODES.O
                || Build.VERSION.SDK_INT != Build.VERSION_CODES.O_MR1) {
            return false;
        }
        AutofillManager autofillManager =
                null;
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
            autofillManager = getContext().getSystemService(AutofillManager.class);
        }
        return autofillManager != null && autofillManager.isEnabled();
    }

}

Para evitar operaciones innecesarias, el siguiente fragmento de código muestra cómo verificar si el autocompletado es compatible con el dispositivo y si está habilitado para el usuario actual, además de si se requiere esta solución alternativa:

Kotlin

// AutofillExtensions.kt

fun Context.isDialogResizedWorkaroundRequired(): Boolean {
    // After the issue is resolved on Android, check whether the
    // workaround is still required for the current device.
    return isAutofillAvailable()
}

fun Context.isAutofillAvailable(): Boolean {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
        // The autofill framework is available on Android 8.0
        // or higher.
        return false
    }

    val afm = getSystemService(AutofillManager::class.java)
    // Return true if autofill is supported by the device and enabled
    // for the current user.
    return afm != null && afm.isEnabled
}

Java

public class AutofillHelper {

    public static boolean isDialogResizedWorkaroundRequired(Context context) {
        // After the issue is resolved on Android, check whether the
        // workaround is still required for the current device.
        return isAutofillAvailable(context);
    }

    public static boolean isAutofillAvailable(Context context) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
            // The autofill framework is available on Android 8.0
            // or higher.
            return false;
        }

        AutofillManager afm = context.getSystemService(AutofillManager.class);
        // Return true if autofill is supported by the device and enabled
        // for the current user.
        return afm != null && afm.isEnabled();
    }
}

Cómo probar tu app con autocompletado

Después de optimizar tu app para que funcione con los servicios de autocompletado, prueba si funciona según lo previsto con los servicios de autocompletado.

Para poder probar tu app, debes usar un emulador o un dispositivo físico que ejecute Android 8.0 (nivel de API 26) o versiones posteriores. Si deseas obtener más información para crear un emulador, consulta Cómo crear y administrar dispositivos virtuales.

Cómo instalar un servicio de autocompletado

Antes de poder probar tu app con autocompletado, debes instalar otra app que ofrezca esos servicios. Puede usar una app de terceros para este propósito, pero es más fácil usar un servicio de autocompletado de muestra para que no debas registrarte en ningún servicio de terceros.

Puedes usar la muestra de Autofill Framework de Android en Java para probar tu app con los servicios de autocompletado. La app de ejemplo proporciona un servicio de autocompletado y clases Activity de cliente que puedes usar para probar el flujo de trabajo antes de usarlo con tu app. En esta página, se hace referencia a la app de ejemplo android-AutofillFramework.

Después de instalar la app, habilita el servicio de autocompletado en la configuración del sistema del emulador. Para ello, navega aConfiguración > Sistema > Idiomas y entrada > Avanzado > Ayuda con métodos de entrada > Servicio Autocompletar.

Cómo analizar requisitos de datos

Para probar tu app con el servicio de autocompletado, este debe tener datos que se puedan usar para tal fin. El servicio también debe comprender qué tipo de datos se esperan en las vistas de tu app. Por ejemplo, si la app tiene una vista que espera un nombre de usuario, el servicio debe tener un conjunto de datos que contenga un nombre de usuario y algún mecanismo para saber que la vista espera esos datos.

Para indicarle al servicio qué tipo de datos se esperan en tus vistas, configura el atributo android:autofillHints. Algunos servicios usan heurísticas sofisticadas para determinar el tipo de datos, pero otros, como la app de ejemplo, confían en el desarrollador para proporcionar esta información. Tu app funciona mejor con los servicios de autocompletado si configuras el atributo android:autofillHints en las vistas que son relevantes para ello.

Cómo realizar la prueba

Después de analizar los requisitos de datos, puedes realizar tu prueba, que incluye guardar los datos de la prueba en el servicio de autocompletado y activar el autocompletado en tu app.

Cómo guardar datos en el servicio

Para guardar datos en el servicio de autocompletado actualmente activo, haz lo siguiente:

  1. Abre una app que contenga una vista que espere el tipo de datos que quieres usar durante tu prueba. La app de muestra android-AutofillFramework proporciona a la IU vistas que esperan varios tipos de datos, como números de tarjeta de crédito y nombres de usuario.
  2. Presiona la vista que tiene el tipo de datos que necesitas.
  3. Ingresa un valor en la vista.
  4. Presiona el botón de confirmación, como Acceder o Enviar. Por lo general, debes enviar el formulario antes de que el servicio guarde los datos.
  5. Verifica la solicitud de permiso del diálogo del sistema. El diálogo del sistema muestra el nombre del servicio que está activo y pregunta si es el servicio que deseas utilizar en tu prueba. Si quieres usar el servicio, presiona Guardar.

Si Android no muestra el diálogo de permisos o si el servicio no es el que quieres usar en tu prueba, comprueba que el servicio esté activo en la configuración del sistema.

Cómo activar el autocompletado en tu app

Para activar el autocompletado en tu app, haz lo siguiente:

  1. Abre la app y busca la actividad que tenga las vistas que quieras probar.
  2. Presiona la vista que se debe completar.
  3. El sistema muestra la IU de autocompletado, que contiene los conjuntos de datos que pueden llenar la vista, como se muestra en la Figura 1.
  4. Presiona el conjunto de datos que contenga los datos que quieras usar. La vista muestra los datos almacenados previamente en el servicio.
IU de autocompletado que muestra "dataset-2" como un conjunto de datos disponible
Figura 1: IU de autocompletado que muestra los conjuntos de datos disponibles

Si Android no muestra la IU de autocompletado, puedes probar las siguientes opciones para solucionar problemas:

  • Comprueba que las vistas de tu app utilicen el valor correcto en el atributo android:autofillHints. Para obtener una lista de posibles valores para el atributo, consulta las constantes con el prefijo AUTOFILL_HINT en la clase View.
  • Comprueba que el atributo android:importantForAutofill esté configurado en un valor diferente a no en la vista que se debe completar, o configura un valor diferente a noExcludeDescendants en la vista o uno de sus elementos superiores.