From 4f3d42264d9d92a7b0c821c6cb95d8a96cb22c87 Mon Sep 17 00:00:00 2001 From: David Perez Date: Wed, 10 Jul 2024 11:40:46 -0500 Subject: [PATCH] Add support for AutoCompleteTextView as an input field (#3435) --- .../data/autofill/util/ViewNodeExtensions.kt | 19 ++++++++++----- .../autofill/util/ViewNodeExtensionsTest.kt | 24 ++++++++++++++++--- 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/com/x8bit/bitwarden/data/autofill/util/ViewNodeExtensions.kt b/app/src/main/java/com/x8bit/bitwarden/data/autofill/util/ViewNodeExtensions.kt index 985ec2048..2d39d623f 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/autofill/util/ViewNodeExtensions.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/autofill/util/ViewNodeExtensions.kt @@ -2,14 +2,10 @@ package com.x8bit.bitwarden.data.autofill.util import android.app.assist.AssistStructure import android.view.View +import android.widget.EditText import com.x8bit.bitwarden.data.autofill.model.AutofillView import com.x8bit.bitwarden.ui.platform.base.util.orNullIfBlank -/** - * The class name of the android edit text field. - */ -private const val ANDROID_EDIT_TEXT_CLASS_NAME: String = "android.widget.EditText" - /** * The default web URI scheme. */ @@ -59,7 +55,18 @@ private val SUPPORTED_VIEW_HINTS: List = listOf( * Whether this [AssistStructure.ViewNode] represents an input field. */ private val AssistStructure.ViewNode.isInputField: Boolean - get() = className == ANDROID_EDIT_TEXT_CLASS_NAME || htmlInfo.isInputField + get() { + val isEditText = className + ?.let { + try { + Class.forName(it) + } catch (e: ClassNotFoundException) { + null + } + } + ?.let { EditText::class.java.isAssignableFrom(it) } == true + return isEditText || htmlInfo.isInputField + } /** * Attempt to convert this [AssistStructure.ViewNode] into an [AutofillView]. If the view node diff --git a/app/src/test/java/com/x8bit/bitwarden/data/autofill/util/ViewNodeExtensionsTest.kt b/app/src/test/java/com/x8bit/bitwarden/data/autofill/util/ViewNodeExtensionsTest.kt index 319a2e2f5..09299d0dd 100644 --- a/app/src/test/java/com/x8bit/bitwarden/data/autofill/util/ViewNodeExtensionsTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/data/autofill/util/ViewNodeExtensionsTest.kt @@ -177,13 +177,32 @@ class ViewNodeExtensionsTest { @Suppress("MaxLineLength") @Test - fun `toAutofillView should return AutofillView Login Username when is android text field and is isUsernameField`() { + fun `toAutofillView should return AutofillView Login Username when is EditText and isUsernameField`() { // Setup val expected = AutofillView.Login.Username( data = autofillViewData, ) setupUnsupportedInputFieldViewNode() - every { viewNode.className } returns ANDROID_EDIT_TEXT_CLASS_NAME + every { viewNode.className } returns "android.widget.EditText" + every { any().isPasswordInputType } returns false + every { any().isUsernameInputType } returns true + + // Test + val actual = viewNode.toAutofillView() + + // Verify + assertEquals(expected, actual) + } + + @Suppress("MaxLineLength") + @Test + fun `toAutofillView should return AutofillView Login Username when is EditText subclass and isUsernameField`() { + // Setup + val expected = AutofillView.Login.Username( + data = autofillViewData, + ) + setupUnsupportedInputFieldViewNode() + every { viewNode.className } returns "android.widget.AutoCompleteTextView" every { any().isPasswordInputType } returns false every { any().isUsernameInputType } returns true @@ -532,7 +551,6 @@ private val AUTOFILL_OPTIONS_LIST: List = listOf( AUTOFILL_OPTION_TWO, ) private const val AUTOFILL_TYPE: Int = View.AUTOFILL_TYPE_LIST -private const val ANDROID_EDIT_TEXT_CLASS_NAME: String = "android.widget.EditText" private val IGNORED_RAW_HINTS: List = listOf( "search", "find",