Как отключить новую функцию автозаполнения от Android Oreo для эспрессо-тестов

Выполнение тестов на устройствах Android с помощью sdk 26 приводит к сбою их из-за новой функции автозаполнения, которая скрывает поля, когда эспрессо пытается их щелкнуть.

Я запускаю свои тесты в тестовой лаборатории Firebase, поэтому я не могу отключить их вручную на своих тестовых устройствах.

Некоторые изображения:

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

enter image description here

2. После нажатия поля поля имени поля пользователя скрывается в этом диалоговом окне автозаполнения:

enter image description here

3. После входа в систему отображается другое диалоговое окно Fill:

enter image description here

Espresso can not click now password field, так как диалог автозаполнения скрывает мое поле и fail.

Использование AutofillManager#disableAutofillServices() отключено только # 2. диалога, но №3. все еще там.

Как отключить автозаполнение на тестовых устройствах?

Ответ 1

adb shell pm disable com.google.android.gms/com.google.android.gms.autofill.service.AutofillService

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

Другой способ отключить службу автозаполнения - изменить настройки autofill_service.

adb shell settings put secure autofill_service null

Ответ 2

На основе документации вы можете отключить службы AutofillManager#disableAutofillServices() используя API-интерфейс AutofillManager#disableAutofillServices():

Если приложение, вызывающее этот API, включило автозаполнение, они будут отключены.

Использование:


    val autofillManager: AutofillManager = context.getSystemService(AutofillManager::class.java)
    autofillManager.disableAutofillServices()

Вы можете сделать это в @Before теста.

Ответ 3

Мне повезло отключить автозаполнение во время тестов Espresso с помощью пользовательских ViewActions, применяемых при вводе текста.

            .onView(...)
            .perform(
                    new ViewAction() {
                        @Override
                        public Matcher<View> getConstraints() {
                            return Matchers.any(View.class);
                        }

                        @Override
                        public String getDescription() {
                            return "Marking view not important for autofill";
                        }

                        @Override
                        public void perform(UiController uiController, View view) {
                            // Required to disable autofill suggestions during tests on API 26+
                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                                view.setImportantForAutofill(View.IMPORTANT_FOR_AUTOFILL_NO);
                            }
                        }
                    })
            .perform(click())
            .perform(clearText())
            .perform(typeText(textToType))
            .perform(
                    new ViewAction() {
                        @Override
                        public Matcher<View> getConstraints() {
                            return Matchers.any(View.class);
                        }

                        @Override
                        public String getDescription() {
                            return "Dismissing autofill picker";
                        }

                        @Override
                        public void perform(UiController uiController, View view) {
                            // Required to dismiss the autofill picker during tests on API 26+
                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                                AutofillManager autofillManager =
                                        view.getContext()
                                                .getSystemService(AutofillManager.class);
                                if (autofillManager != null) autofillManager.cancel();
                            }
                        }
                    });

Ответ 4

Альтернативная организация кода, основанная на решении @Alan K.

Создайте класс DisableAutofillAction:

public class DisableAutofillAction implements ViewAction {

    @Override
    public Matcher<View> getConstraints() {
        return Matchers.any(View.class);
    }

    @Override
    public String getDescription() {
        return "Dismissing autofill picker";
    }

    @Override
    public void perform(UiController uiController, View view) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {

            AutofillManager autofillManager = view.getContext().getSystemService(AutofillManager.class);

            if (autofillManager != null) {
                autofillManager.cancel();
            }
        }
    }
}

И, в вашем коде, когда вам нужно отключить автозаполнение для editTextPassword...

editTextPassword.perform(..., ViewActions.closeSoftKeyboard(), DisableAutofillAction())

Ответ 5

Согласно документации: когда представление сосредоточено и является частью набора данных. Приложение может быть уведомлено, когда доступность показана путем регистрации AutofillManager.AutofillCallback через registerCallback (AutofillCallback). Когда пользователь выбирает набор данных из допущения, все виды, представленные в наборе данных, автоматически заполняются посредством вызовов автозаполнения (AutofillValue) или автозаполнения (SparseArray).

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

  1. Вызывается commit() или исчезают все полезные сведения.
  2. вызывается cancel().

Безопасно вызывать его методы из любого потока.

Экземпляры этого класса должны быть получены с помощью Context.getSystemService(Class) с аргументом AutofillManager.class.

Используйте метод disableAutofillServices() для отключения службы.

Ответ 6

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

getWindow().getDecorView().setImportantForAutofill(View.IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS);

Ответ 7

При тестировании отключите автозаполнение. Определить класс TestRunner в градиенте

defaultConfig {
    testInstrumentationRunner "com.cover.android.TestRunner"
}

затем

public class TestRunner extends AndroidJUnitRunner {

@Override
public void onCreate(Bundle arguments) {
    super.onCreate(arguments);
    CustomEditText.TESTING = TRUE;
    }

затем используйте пользовательскую версию EditText

public class CustomEditText extends AppCompatEditText {
public static boolean TESTING = false;
public CustomEditText(Context context) {
    super(context);
}

@Override
public int getAutofillType() {
    return TESTING? AUTOFILL_TYPE_NONE : super.getAutofillType();
}