Оптимизируйте свое приложение для автозаполнения,Оптимизируйте свое приложение для автозаполнения

Приложения, использующие стандартные представления, работают с платформой автозаполнения, не требуя специальной настройки. Вы также можете оптимизировать работу вашего приложения с помощью платформы.

Настройте среду автозаполнения

В этом разделе описывается, как настроить базовые функции автозаполнения для вашего приложения.

Настройка службы автозаполнения

Чтобы ваше приложение могло использовать платформу автозаполнения, на вашем устройстве должна быть настроена служба автозаполнения. Хотя большинство телефонов и планшетов под управлением Android 8.0 (уровень API 26) и более поздних версий поставляются со службой автозаполнения, мы рекомендуем вам использовать тестовую службу при тестировании вашего приложения, например службу автозаполнения в примере платформы автозаполнения Android . При использовании эмулятора явно установите службу автозаполнения, поскольку в эмуляторе может отсутствовать служба по умолчанию.

После установки тестовой службы автозаполнения из примера приложения включите службу автозаполнения, перейдя в «Настройки» > «Система» > «Языки и ввод» > «Дополнительно» > «Помощь при вводе» > «Служба автозаполнения» .

Дополнительные сведения о настройке эмулятора для проверки автозаполнения см. в разделе Проверка приложения с помощью автозаполнения .

Предоставление подсказок для автозаполнения

Служба автозаполнения определяет тип каждого представления с помощью эвристики. Однако если ваше приложение использует эту эвристику, поведение автозаполнения может неожиданно измениться при обновлении приложения. Чтобы убедиться, что служба автозаполнения правильно определяет форм-факторы вашего приложения, предоставьте подсказки по автозаполнению.

Вы можете установить подсказки для автозаполнения, используя атрибут android:autofillHints . В следующем примере устанавливается подсказка "password" для EditText :

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

Вы также можете установить подсказки программно, используя метод setAutofillHints() , как показано в следующем примере:

Котлин

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

Ява

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

Включить предопределенные константы подсказок

Платформа автозаполнения не проверяет подсказки; они передаются без изменений и проверки в службу автозаполнения. Хотя вы можете использовать любое значение, классы View и AndroidX HintConstants содержат списки официально поддерживаемых констант подсказок.

Используя комбинацию этих констант, вы можете создавать макеты для распространенных сценариев автозаполнения:

Учетные данные учетной записи

В форме входа вы можете включить подсказки по учетным данным, например AUTOFILL_HINT_USERNAME и AUTOFILL_HINT_PASSWORD .

Для создания новой учетной записи или когда пользователи меняют свое имя пользователя и пароль, вы можете использовать AUTOFILL_HINT_NEW_USERNAME и AUTOFILL_HINT_NEW_PASSWORD .

Информация о кредитной карте

При запросе информации о кредитной карте вы можете использовать подсказки, такие как AUTOFILL_HINT_CREDIT_CARD_NUMBER и AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE .

Чтобы узнать дату истечения срока действия кредитной карты, выполните одно из следующих действий:

Физический адрес

Для полей формы физического адреса вы можете использовать подсказки, например следующие:

Имена людей

При запросе имен людей вы можете использовать такие подсказки:

Номера телефонов

Для телефонных номеров вы можете использовать следующее:

Одноразовый пароль (OTP)

Для одноразового пароля в одном представлении вы можете использовать AUTOFILL_HINT_SMS_OTP .

Для нескольких представлений, где каждое представление соответствует одной цифре OTP, вы можете использовать generateSmsOtpHintForCharacterPosition() для создания подсказок для каждого символа.

Отметьте поля как важные для автозаполнения

Вы можете включить отдельные поля вашего приложения в структуру представления для целей автозаполнения. По умолчанию представления используют режим IMPORTANT_FOR_AUTOFILL_AUTO , который позволяет Android использовать свою эвристику, чтобы определить, важно ли представление для автозаполнения.

Однако бывают случаи, когда представление, структура представления или вся активность не важны для автозаполнения:

  • Поле CAPTCHA при входе в систему
  • Представление, в котором пользователь создает контент, например текстовый редактор или редактор электронных таблиц.
  • Виды некоторых действий в играх, например тех, которые отображают игровой процесс.

Вы можете установить важность представления для автозаполнения, используя атрибут android:importantForAutofill :

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

Значение importantForAutofill может быть любым из следующих:

auto
Позвольте системе Android использовать свою эвристику, чтобы определить, важно ли представление для автозаполнения.
no
Это представление не важно для автозаполнения.
noExcludeDescendants
Это представление и его дочерние элементы не важны для автозаполнения.
yes
Это представление важно для автозаполнения.
yesExcludeDescendants
Это представление важно для автозаполнения, но его дочерние элементы для автозаполнения не важны.

Вы также можете использовать метод setImportantForAutofill() :

Котлин

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

Ява

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

Вы можете объявить приведенные выше примеры использования неважными для автозаполнения следующим образом:

  • Поле CAPTCHA при входе в систему: используйте android:importantForAutofill="no" или IMPORTANT_FOR_AUTOFILL_NO чтобы пометить это представление как неважное.
  • Представление, в котором пользователь создает контент: используйте android:importantForAutofill="noExcludeDescendants" или IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS чтобы пометить всю структуру представления как неважную.
  • Представления в некоторых действиях в играх: используйте android:importantForAutofill="noExcludeDescendants" или IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS чтобы пометить всю структуру представления как неважную.

Связывание данных веб-сайта и мобильного приложения

Службы автозаполнения, такие как «Автозаполнение через Google», могут обмениваться данными для входа в систему между браузерами и устройствами Android после того, как приложение и веб-сайт будут связаны. Когда пользователь выбирает одну и ту же службу автозаполнения на обеих платформах, вход в ваше веб-приложение делает его учетные данные для входа доступными для автозаполнения при входе в соответствующее приложение Android.

Чтобы связать приложение Android с вашим веб-сайтом, разместите на своем сайте ссылку на цифровой ресурс с отношением delegate_permission/common.get_login_creds . Затем объявите связь в файле AndroidManifest.xml вашего приложения. Подробные инструкции о том, как связать ваш веб-сайт с приложением Android, см. в разделе Включение автоматического входа в приложения и на веб-сайты .

Завершите рабочий процесс автозаполнения

В этом разделе описаны конкретные сценарии, в которых вы можете предпринять шаги по улучшению функции автозаполнения для пользователей вашего приложения.

Определите, включено ли автозаполнение

Пользователи могут включить или отключить автозаполнение, а также изменить службу автозаполнения, перейдя в «Настройки» > «Система» > «Языки и ввод» > «Дополнительно» > «Помощь при вводе» > «Служба автозаполнения» . Ваше приложение не может переопределить настройки автозаполнения пользователя, но вы можете реализовать дополнительные функции автозаполнения в своем приложении или в определенных представлениях вашего приложения, если автозаполнение доступно пользователю.

Например, TextView отображает запись автозаполнения в меню переполнения, если для пользователя включено автозаполнение. Чтобы проверить, включено ли для пользователя автозаполнение, вызовите метод isEnabled() объекта AutofillManager .

Чтобы ваша регистрация и вход в систему были оптимизированы для пользователей без автозаполнения, внедрите вход в одно касание .

Принудительно выполнить запрос автозаполнения

Иногда вам нужно принудительно выполнить запрос автозаполнения в ответ на действие пользователя. Например, TextView предлагает пункт меню автозаполнения, когда пользователь касается и удерживает представление. В следующем примере кода показано, как принудительно выполнить запрос автозаполнения:

Котлин

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

Ява

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

Вы также можете использовать метод cancel() для отмены текущего контекста автозаполнения. Это может быть полезно, если у вас есть кнопка, очищающая поля на странице входа.

Используйте правильный тип автозаполнения для данных в элементах управления сборщиком.

Средства выбора могут быть полезны при автозаполнении, предоставляя пользовательский интерфейс, который позволяет пользователям изменять значение поля, в котором хранятся данные даты или времени. Например, в форме кредитной карты средство выбора даты позволяет пользователям вводить или изменять дату истечения срока действия своей кредитной карты. Однако вам необходимо использовать другое представление, например EditText , для отображения данных, когда средство выбора не отображается.

Объект EditText изначально ожидает данные автозаполнения типа AUTOFILL_TYPE_TEXT . Если вы используете другой тип данных, создайте собственное представление, которое наследуется от EditText и реализует методы, необходимые для обработки соответствующего типа данных. Например, если у вас есть поле даты, реализуйте методы с логикой, которая правильно обрабатывает значения типа AUTOFILL_TYPE_DATE .

Когда вы указываете тип данных автозаполнения, служба автозаполнения может создать подходящее представление данных, отображаемых в представлении. Дополнительные сведения см. в разделе Использование средств выбора с автозаполнением .

Завершить контекст автозаполнения

Платформа автозаполнения сохраняет введенные пользователем данные для использования в будущем, показывая сообщение «Сохранить для автозаполнения?» диалоговое окно после завершения контекста автозаполнения. Обычно контекст автозаполнения завершается после завершения действия. Однако в некоторых ситуациях вам необходимо явно уведомить платформу — например, если вы используете одно и то же действие, но разные фрагменты как для экрана входа в систему, так и для экранов содержимого. В таких ситуациях вы можете явно завершить контекст, вызвав AutofillManager.commit() .

Поддержка пользовательских представлений

Пользовательские представления могут указывать метаданные, которые предоставляются платформе автозаполнения с помощью API автозаполнения. Некоторые представления действуют как контейнер виртуальных дочерних элементов, например представления, содержащие пользовательский интерфейс, отображаемый OpenGL. Эти представления должны использовать API для указания структуры информации, используемой в приложении, прежде чем они смогут работать с платформой автозаполнения.

Если ваше приложение использует пользовательские представления, рассмотрите следующие сценарии:

  • Пользовательское представление предоставляет стандартную структуру представления или структуру представления по умолчанию.
  • Пользовательское представление имеет виртуальную структуру или структуру представления, недоступную для платформы автозаполнения.

Пользовательские представления со стандартной структурой представления

Пользовательские представления могут определять метаданные, необходимые для работы автозаполнения. Убедитесь, что ваше пользовательское представление управляет метаданными надлежащим образом для работы с платформой автозаполнения. Ваше пользовательское представление должно выполнять следующие действия:

  • Обработайте значение автозаполнения, которое платформа отправляет в ваше приложение.
  • Укажите тип и значение автозаполнения для платформы.

Когда срабатывает автозаполнение, платформа автозаполнения вызывает autofill() вашего представления и отправляет значение, которое ваше представление должно использовать. Реализуйте autofill() чтобы указать, как ваше пользовательское представление обрабатывает значение автозаполнения.

Ваше представление должно указать тип и значение автозаполнения, переопределив методы getAutofillType() и getAutofillValue() соответственно.

Наконец, автозаполнение не должно заполнять представление, если пользователь не может предоставить значение для представления в его текущем состоянии — например, если представление отключено. В этих случаях getAutofillType() должен возвращать AUTOFILL_TYPE_NONE , getAutofillValue() должен возвращать null , а autofill() не должен ничего делать.

Следующие случаи требуют дополнительных действий для правильной работы в рамках:

  • Пользовательский вид доступен для редактирования.
  • Пользовательское представление содержит конфиденциальные данные.

Пользовательский вид доступен для редактирования

Если представление доступно для редактирования, уведомите платформу автозаполнения об изменениях, вызвав notifyValueChanged() для объекта AutofillManager .

Пользовательское представление содержит конфиденциальные данные.

Если представление содержит личную информацию (PII), такую ​​как адреса электронной почты, номера кредитных карт и пароли, оно должно быть помечено как конфиденциальное.

Как правило, представления, содержимое которых получено из статических ресурсов, не содержат конфиденциальных данных, тогда как представления, содержимое которых устанавливается динамически, могут содержать конфиденциальные данные. Например, метка, содержащая «Введите свое имя пользователя», не содержит конфиденциальных данных, а метка, содержащая «Привет, Джон» , — содержит.

Платформа автозаполнения предполагает, что все данные по умолчанию являются конфиденциальными. Вы можете пометить данные, которые не являются конфиденциальными.

Чтобы отметить, содержит ли представление конфиденциальные данные, реализуйте onProvideAutofillStructure() и вызовите setDataIsSensitive() для объекта ViewStructure .

В следующем примере кода показано, как пометить данные в структуре представления как неконфиденциальные:

Котлин

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

    structure.setDataIsSensitive(false)
}

Ява

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

    structure.setDataIsSensitive(false);
}

Если представление принимает только предопределенные значения, вы можете использовать метод setAutofillOptions() чтобы установить параметры, которые можно использовать для автозаполнения представления. В частности, представления, тип автозаполнения которых — AUTOFILL_TYPE_LIST должны использовать этот метод, поскольку служба автозаполнения может работать лучше, если ей известны параметры, доступные для заполнения представления.

Представления, использующие адаптер, например Spinner , представляют собой аналогичный случай. Например, счетчик, который предоставляет динамически создаваемые годы на основе текущего года для использования в полях срока действия кредитной карты, может реализовать метод getAutofillOptions() интерфейса Adapter для предоставления списка лет.

Представления, использующие ArrayAdapter также могут предоставлять списки значений. ArrayAdapter автоматически устанавливает параметры автозаполнения для статических ресурсов. Если вы предоставляете значения динамически, переопределите getAutofillOptions() .

Пользовательские представления с виртуальной структурой

Платформе автозаполнения требуется структура представления, прежде чем она сможет редактировать и сохранять информацию в пользовательском интерфейсе вашего приложения. Структура представления недоступна для платформы в следующих ситуациях:

  • Приложение использует механизм низкоуровневого рендеринга, такой как OpenGL , для рендеринга пользовательского интерфейса.
  • Приложение использует экземпляр Canvas для рисования пользовательского интерфейса.

В этих случаях вы можете указать структуру представления, реализовав onProvideAutofillVirtualStructure() и выполнив следующие шаги:

  1. Увеличьте количество дочерних элементов структуры представления, вызвав addChildCount() .
  2. Добавьте дочернего элемента, вызвав newChild() .
  3. Установите идентификатор автозаполнения для дочернего элемента, вызвав setAutofillId() .
  4. Установите соответствующие свойства, такие как значение и тип автозаполнения.
  5. Если данные в виртуальном дочернем элементе конфиденциальны, передайте true в setDataIsSensitive() ; в противном случае передайте false .

В следующем фрагменте кода показано, как создать новый дочерний элемент в виртуальной структуре:

Котлин

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)
}

Ява

@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);
}

При изменении элементов виртуальной структуры уведомите платформу, выполнив следующие задачи:

  • Если фокус внутри дочерних элементов изменится, вызовите notifyViewEntered() и notifyViewExited() для объекта AutofillManager .
  • Если значение дочернего элемента изменится, вызовите notifyValueChanged() для объекта AutofillManager .
  • Если иерархия представлений больше недоступна, поскольку пользователь выполнил шаг рабочего процесса, например, когда он входит в систему с помощью формы входа, вызовите commit() для объекта AutofillManager .
  • Если иерархия представлений недействительна, поскольку пользователь отменил шаг рабочего процесса, например, когда пользователь нажимает кнопку, которая очищает форму входа, вызовите метод cancel() для объекта AutofillManager .

Используйте обратные вызовы для событий автозаполнения

Если ваше приложение предоставляет собственные представления автозаполнения, вам нужен механизм, который сообщит приложению включать или отключать представления в ответ на изменения в возможностях автозаполнения пользовательского интерфейса. Платформа автозаполнения предоставляет этот механизм в форме AutofillCallback .

Этот класс предоставляет метод onAutofillEvent(View, int) , который приложение вызывает после изменения состояния автозаполнения, связанного с представлением. Существует также перегруженная версия этого метода, включающая параметр childId , который ваше приложение может использовать с виртуальными представлениями. Доступные состояния определяются как константы в обратном вызове.

Вы можете зарегистрировать обратный вызов с помощью метода registerCallback() класса AutofillManager . В следующем примере кода показано, как объявить обратный вызов для событий автозаполнения:

Котлин

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.
            }
        }

    }
})

Ява

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;
        }
    }
});

Когда придет время удалить обратный вызов, используйте метод unregisterCallback() .

Настройте выделенный элемент автозаполнения

Когда представление заполняется автоматически, платформа отображает объект Drawable поверх представления, чтобы указать, что содержимое представления заполняется автоматически. По умолчанию этот объект рисования представляет собой сплошной прямоугольник полупрозрачного цвета, который немного темнее цвета темы, используемой для рисования фона. Рисуемый объект не нужно изменять, но его можно настроить, переопределив элемент android:autofilledHighlight темы , используемой приложением или действием, как показано в этом примере:

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

Аутентификация для автозаполнения

Служба автозаполнения может потребовать от пользователя пройти аутентификацию, прежде чем служба сможет заполнить поля в вашем приложении. В этом случае система Android запускает действие проверки подлинности службы как часть стека ваших действий.

Вам не нужно обновлять приложение для поддержки аутентификации, поскольку аутентификация происходит внутри службы. Однако вы должны убедиться, что структура представления действия сохраняется при перезапуске действия, например, путем создания структуры представления в onCreate() , а не в onStart() или onResume() .

Вы можете проверить, как ведет себя ваше приложение, когда служба автозаполнения требует проверки подлинности, используя службу HeuristicsService из примера AutofillFramework и настроив ее на требование проверки подлинности ответа на заполнение. Вы также можете использовать образец BadViewStructureCreationSignInActivity для эмуляции этой проблемы.

Назначение идентификаторов автозаполнения переработанным представлениям

Контейнеры, которые перерабатывают представления, такие как класс RecyclerView , полезны для приложений, которым необходимо отображать прокручиваемые списки элементов на основе больших наборов данных. По мере прокрутки контейнера система повторно использует представления в макете, но затем представления содержат новый контент.

Если исходное содержимое переработанного представления заполнено, служба автозаполнения сохраняет логическое значение представлений, используя их идентификаторы автозаполнения. Проблема возникает, когда система повторно использует представления в макете, а логические идентификаторы представлений остаются прежними, в результате чего с идентификатором автозаполнения связываются неправильные пользовательские данные автозаполнения.

Чтобы решить эту проблему на устройствах под управлением Android 9 (уровень API 28) и выше, явно управляйте идентификатором автозаполнения представлений, используемых RecyclerView , с помощью следующих методов:

  • Метод getNextAutofillId() получает новый идентификатор автозаполнения, уникальный для данного действия.
  • Метод setAutofillId() устанавливает уникальный логический идентификатор автозаполнения этого представления в действии.

Устранение известных проблем

В этом разделе представлены обходные пути известных проблем в рамках автозаполнения.

Автозаполнение приводит к сбою приложений на Android 8.0, 8.1

В Android 8.0 (уровень API 26) и 8.1 (уровень API 27) автозаполнение может привести к сбою вашего приложения в определенных сценариях. Чтобы обойти потенциальные проблемы, пометьте все представления, которые не заполнены автоматически, с помощью importantForAutofill=no . Вы также можете пометить все действие с помощью importantForAutofill=noExcludeDescendants .

Диалоговые окна с измененным размером не учитываются для автозаполнения.

В Android 8.1 (уровень API 27) и более ранних версиях, если размер представления в диалоговом окне изменяется после того, как оно уже отображено, представление не учитывается для автозаполнения. Эти представления не включаются в объект AssistStructure , который система Android отправляет в службу автозаполнения. В результате служба не может заполнить представления.

Чтобы обойти эту проблему, замените свойство token параметров диалогового окна свойством token действия, создающего диалоговое окно. Убедившись, что автозаполнение включено, сохраните параметры окна в методе onWindowAttributesChanged() класса, который наследуется от Dialog . Затем замените свойство token сохраненных параметров свойством token родительского действия в методе onAttachedToWindow() .

В следующем фрагменте кода показан класс, реализующий этот обходной путь:

Котлин

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()
    }

}

Ява

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();
    }

}

Чтобы избежать ненужных операций, в следующем фрагменте кода показано, как проверить, поддерживается ли автозаполнение на устройстве и включено ли для текущего пользователя, и требуется ли это обходное решение:

Котлин

// 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
}

Ява

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();
    }
}

Проверьте свое приложение с помощью автозаполнения

После оптимизации приложения для работы со службами автозаполнения проверьте, работает ли оно должным образом со службами автозаполнения.

Используйте эмулятор или физическое устройство под управлением Android 8.0 (уровень API 26) или более поздней версии, чтобы протестировать свое приложение. Дополнительные сведения о создании эмулятора см. в разделе Создание виртуальных устройств и управление ими .

Установите сервис автозаполнения

Прежде чем вы сможете протестировать свое приложение с автозаполнением, вам необходимо установить другое приложение, предоставляющее услуги автозаполнения. Для этой цели вы можете использовать стороннее приложение, но проще использовать образец службы автозаполнения, чтобы вам не приходилось подписываться на сторонние службы.

Вы можете использовать пример платформы автозаполнения Android на Java , чтобы протестировать свое приложение с помощью служб автозаполнения. Пример приложения предоставляет службу автозаполнения и классы Activity клиента, которые можно использовать для тестирования рабочего процесса перед его использованием в приложении. Эта страница ссылается на пример приложения android-AutofillFramework .

После установки приложения включите службу автозаполнения в системных настройках эмулятора, перейдя в «Настройки» > «Система» > «Языки и ввод» > «Дополнительно» > «Помощь при вводе» > «Служба автозаполнения» .

Анализ требований к данным

Чтобы протестировать ваше приложение с помощью службы автозаполнения, у службы должны быть данные, которые она может использовать для заполнения вашего приложения. Службе также необходимо понимать, какой тип данных ожидается в представлениях вашего приложения. Например, если в вашем приложении есть представление, которое ожидает имя пользователя, у службы должен быть набор данных, содержащий имя пользователя, и какой-то механизм, позволяющий узнать, что представление ожидает такие данные.

Сообщите службе, какой тип данных ожидается в ваших представлениях, установив атрибут android:autofillHints . Некоторые службы используют сложную эвристику для определения типа данных, но другие, такие как пример приложения, полагаются на то, что разработчик предоставит эту информацию. Ваше приложение будет лучше работать со службами автозаполнения, если вы установите атрибут android:autofillHints в представлениях, соответствующих автозаполнению.

Запустите свой тест

После анализа требований к данным вы можете запустить тест, который включает сохранение тестовых данных в службе автозаполнения и запуск автозаполнения в вашем приложении.

Сохраняем данные в сервисе

Чтобы сохранить данные в активном в данный момент сервисе автозаполнения, выполните следующие действия:

  1. Откройте приложение, содержащее представление, которое ожидает тип данных, которые вы хотите использовать во время теста. Пример приложения android-AutofillFramework предоставляет пользовательский интерфейс с представлениями, которые ожидают несколько типов данных, таких как номера кредитных карт и имена пользователей.
  2. Коснитесь представления, содержащего нужный вам тип данных.
  3. Введите значение в представление.
  4. Нажмите кнопку подтверждения, например «Войти» или «Отправить» . Обычно вам необходимо отправить форму до того, как служба сохранит данные.
  5. Проверьте запрос разрешения в системном диалоговом окне. В системном диалоговом окне отображается имя активной в данный момент службы и спрашивается, хотите ли вы использовать эту службу в своем тесте. Если вы хотите воспользоваться услугой, нажмите « Сохранить» .

Если Android не отображает диалоговое окно разрешений или если служба не та, которую вы хотите использовать в своем тесте, проверьте, активна ли эта служба в настоящее время в настройках системы.

Включите автозаполнение в вашем приложении

Чтобы активировать автозаполнение в вашем приложении, выполните следующие действия:

  1. Откройте свое приложение и перейдите к действию, которое имеет представления, которые вы хотите протестировать.
  2. Нажмите на представление, которое необходимо заполнить.
  3. Система отображает пользовательский интерфейс автозаполнения, который содержит наборы данных, которые могут заполнить представление, как показано на рисунке 1.
  4. Коснитесь набора данных, содержащего данные, которые вы хотите использовать. В представлении отображаются данные, ранее хранившиеся в сервисе.
Пользовательский интерфейс автозаполнения, отображающий «набор данных-2» как доступный набор данных.
Рисунок 1. Пользовательский интерфейс автозаполнения, отображающий доступные наборы данных.

Если Android не отображает пользовательский интерфейс автозаполнения, вы можете попробовать следующие варианты устранения неполадок:

  • Убедитесь, что представления в вашем приложении используют правильное значение атрибута android:autofillHints . Список возможных значений атрибута см. в константах с префиксом AUTOFILL_HINT в классе View .
  • Убедитесь, что атрибуту android:importantForAutofill присвоено значение, отличное от no в представлении, которое необходимо заполнить, или установлено значение, отличное от noExcludeDescendants в представлении или одном из его родительских элементов.