mirror of
https://github.com/bitwarden/android.git
synced 2024-12-18 07:11:51 +03:00
PM-12397: Clear accessibility action when on launcher or Bitwarden App (#3947)
This commit is contained in:
parent
5667a1cfd0
commit
d0c2bb5b7e
4 changed files with 101 additions and 20 deletions
|
@ -10,6 +10,7 @@ import com.x8bit.bitwarden.data.autofill.accessibility.manager.LauncherPackageNa
|
|||
import com.x8bit.bitwarden.data.autofill.accessibility.model.AccessibilityAction
|
||||
import com.x8bit.bitwarden.data.autofill.accessibility.parser.AccessibilityParser
|
||||
import com.x8bit.bitwarden.data.autofill.accessibility.util.fillTextField
|
||||
import com.x8bit.bitwarden.data.autofill.accessibility.util.isSystemPackage
|
||||
import com.x8bit.bitwarden.data.autofill.accessibility.util.shouldSkipPackage
|
||||
import com.x8bit.bitwarden.data.autofill.model.AutofillSelectionData
|
||||
import com.x8bit.bitwarden.data.autofill.util.createAutofillSelectionIntent
|
||||
|
@ -28,10 +29,16 @@ class BitwardenAccessibilityProcessorImpl(
|
|||
val rootNode = rootAccessibilityNodeInfo ?: return
|
||||
// Ignore the event when the phone is inactive
|
||||
if (!powerManager.isInteractive) return
|
||||
// We skip if the package is not supported
|
||||
if (rootNode.shouldSkipPackage) return
|
||||
// We skip any package that is a launcher
|
||||
if (launcherPackageNameManager.launcherPackages.any { it == rootNode.packageName }) return
|
||||
// We skip if the system package
|
||||
if (rootNode.isSystemPackage) return
|
||||
// We skip any package that is a launcher or unsupported
|
||||
if (rootNode.shouldSkipPackage ||
|
||||
launcherPackageNameManager.launcherPackages.any { it == rootNode.packageName }
|
||||
) {
|
||||
// Clear the action since this event needs to be ignored completely
|
||||
accessibilityAutofillManager.accessibilityAction = null
|
||||
return
|
||||
}
|
||||
|
||||
// Only process the event if the tile was clicked
|
||||
val accessibilityAction = accessibilityAutofillManager.accessibilityAction ?: return
|
||||
|
|
|
@ -33,15 +33,19 @@ private val PACKAGE_NAME_BLOCK_LIST: List<String> = listOf(
|
|||
val AccessibilityNodeInfo.shouldSkipPackage: Boolean
|
||||
get() {
|
||||
val packageName = this.packageName.takeUnless { it.isNullOrBlank() } ?: return true
|
||||
if (packageName == PACKAGE_NAME_SYSTEM_UI) return true
|
||||
if (packageName.startsWith(prefix = PACKAGE_NAME_BITWARDEN_PREFIX)) return true
|
||||
if (packageName.contains(other = PACKAGE_NAME_LAUNCHER_PARTIAL, ignoreCase = true)) {
|
||||
return true
|
||||
}
|
||||
if (PACKAGE_NAME_BLOCK_LIST.contains(packageName)) return true
|
||||
return false
|
||||
return PACKAGE_NAME_BLOCK_LIST.contains(packageName)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the event is from the system UI package.
|
||||
*/
|
||||
val AccessibilityNodeInfo.isSystemPackage: Boolean
|
||||
get() = this.packageName == PACKAGE_NAME_SYSTEM_UI
|
||||
|
||||
/**
|
||||
* Fills the [AccessibilityNodeInfo] text field with the [value] provided.
|
||||
*/
|
||||
|
|
|
@ -14,6 +14,7 @@ import com.x8bit.bitwarden.data.autofill.accessibility.model.AccessibilityAction
|
|||
import com.x8bit.bitwarden.data.autofill.accessibility.model.FillableFields
|
||||
import com.x8bit.bitwarden.data.autofill.accessibility.parser.AccessibilityParser
|
||||
import com.x8bit.bitwarden.data.autofill.accessibility.util.fillTextField
|
||||
import com.x8bit.bitwarden.data.autofill.accessibility.util.isSystemPackage
|
||||
import com.x8bit.bitwarden.data.autofill.accessibility.util.shouldSkipPackage
|
||||
import com.x8bit.bitwarden.data.autofill.model.AutofillSelectionData
|
||||
import com.x8bit.bitwarden.data.autofill.util.createAutofillSelectionIntent
|
||||
|
@ -49,7 +50,10 @@ class BitwardenAccessibilityProcessorTest {
|
|||
|
||||
@BeforeEach
|
||||
fun setup() {
|
||||
mockkStatic(AccessibilityNodeInfo::shouldSkipPackage)
|
||||
mockkStatic(
|
||||
AccessibilityNodeInfo::isSystemPackage,
|
||||
AccessibilityNodeInfo::shouldSkipPackage,
|
||||
)
|
||||
mockkStatic(::createAutofillSelectionIntent)
|
||||
mockkStatic(Toast::class)
|
||||
every {
|
||||
|
@ -61,7 +65,10 @@ class BitwardenAccessibilityProcessorTest {
|
|||
|
||||
@AfterEach
|
||||
fun tearDown() {
|
||||
unmockkStatic(AccessibilityNodeInfo::shouldSkipPackage)
|
||||
unmockkStatic(
|
||||
AccessibilityNodeInfo::isSystemPackage,
|
||||
AccessibilityNodeInfo::shouldSkipPackage,
|
||||
)
|
||||
unmockkStatic(::createAutofillSelectionIntent)
|
||||
unmockkStatic(Toast::class)
|
||||
}
|
||||
|
@ -92,9 +99,9 @@ class BitwardenAccessibilityProcessorTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
fun `processAccessibilityEvent with skippable package should return`() {
|
||||
fun `processAccessibilityEvent with system package should return`() {
|
||||
val rootNode = mockk<AccessibilityNodeInfo> {
|
||||
every { shouldSkipPackage } returns true
|
||||
every { isSystemPackage } returns true
|
||||
}
|
||||
every { powerManager.isInteractive } returns true
|
||||
|
||||
|
@ -104,7 +111,28 @@ class BitwardenAccessibilityProcessorTest {
|
|||
|
||||
verify(exactly = 1) {
|
||||
powerManager.isInteractive
|
||||
rootNode.isSystemPackage
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `processAccessibilityEvent with skippable package should return`() {
|
||||
val rootNode = mockk<AccessibilityNodeInfo> {
|
||||
every { isSystemPackage } returns false
|
||||
every { shouldSkipPackage } returns true
|
||||
}
|
||||
every { powerManager.isInteractive } returns true
|
||||
every { accessibilityAutofillManager.accessibilityAction = null } just runs
|
||||
|
||||
bitwardenAccessibilityProcessor.processAccessibilityEvent(
|
||||
rootAccessibilityNodeInfo = rootNode,
|
||||
)
|
||||
|
||||
verify(exactly = 1) {
|
||||
powerManager.isInteractive
|
||||
rootNode.isSystemPackage
|
||||
rootNode.shouldSkipPackage
|
||||
accessibilityAutofillManager.accessibilityAction = null
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -112,11 +140,13 @@ class BitwardenAccessibilityProcessorTest {
|
|||
fun `processAccessibilityEvent with launcher package should return`() {
|
||||
val testPackageName = "com.google.android.launcher"
|
||||
val rootNode = mockk<AccessibilityNodeInfo> {
|
||||
every { isSystemPackage } returns false
|
||||
every { shouldSkipPackage } returns false
|
||||
every { packageName } returns testPackageName
|
||||
}
|
||||
every { launcherPackageNameManager.launcherPackages } returns listOf(testPackageName)
|
||||
every { powerManager.isInteractive } returns true
|
||||
every { accessibilityAutofillManager.accessibilityAction = null } just runs
|
||||
|
||||
bitwardenAccessibilityProcessor.processAccessibilityEvent(
|
||||
rootAccessibilityNodeInfo = rootNode,
|
||||
|
@ -124,8 +154,10 @@ class BitwardenAccessibilityProcessorTest {
|
|||
|
||||
verify(exactly = 1) {
|
||||
powerManager.isInteractive
|
||||
rootNode.isSystemPackage
|
||||
rootNode.shouldSkipPackage
|
||||
launcherPackageNameManager.launcherPackages
|
||||
accessibilityAutofillManager.accessibilityAction = null
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -133,6 +165,7 @@ class BitwardenAccessibilityProcessorTest {
|
|||
fun `processAccessibilityEvent without accessibility action should return`() {
|
||||
val testPackageName = "com.android.chrome"
|
||||
val rootNode = mockk<AccessibilityNodeInfo> {
|
||||
every { isSystemPackage } returns false
|
||||
every { shouldSkipPackage } returns false
|
||||
every { packageName } returns testPackageName
|
||||
}
|
||||
|
@ -147,6 +180,7 @@ class BitwardenAccessibilityProcessorTest {
|
|||
verify(exactly = 1) {
|
||||
powerManager.isInteractive
|
||||
rootNode.shouldSkipPackage
|
||||
rootNode.isSystemPackage
|
||||
launcherPackageNameManager.launcherPackages
|
||||
accessibilityAutofillManager.accessibilityAction
|
||||
}
|
||||
|
@ -156,6 +190,7 @@ class BitwardenAccessibilityProcessorTest {
|
|||
fun `processAccessibilityEvent with AttemptParseUri and a invalid uri should show a toast`() {
|
||||
val testPackageName = "com.android.chrome"
|
||||
val rootNode = mockk<AccessibilityNodeInfo> {
|
||||
every { isSystemPackage } returns false
|
||||
every { shouldSkipPackage } returns false
|
||||
every { packageName } returns testPackageName
|
||||
}
|
||||
|
@ -173,6 +208,7 @@ class BitwardenAccessibilityProcessorTest {
|
|||
|
||||
verify(exactly = 1) {
|
||||
powerManager.isInteractive
|
||||
rootNode.isSystemPackage
|
||||
rootNode.shouldSkipPackage
|
||||
launcherPackageNameManager.launcherPackages
|
||||
accessibilityAutofillManager.accessibilityAction
|
||||
|
@ -189,6 +225,7 @@ class BitwardenAccessibilityProcessorTest {
|
|||
fun `processAccessibilityEvent with AttemptParseUri and a valid uri should start the main activity`() {
|
||||
val testPackageName = "com.android.chrome"
|
||||
val rootNode = mockk<AccessibilityNodeInfo> {
|
||||
every { isSystemPackage } returns false
|
||||
every { shouldSkipPackage } returns false
|
||||
every { packageName } returns testPackageName
|
||||
}
|
||||
|
@ -214,6 +251,7 @@ class BitwardenAccessibilityProcessorTest {
|
|||
|
||||
verify(exactly = 1) {
|
||||
powerManager.isInteractive
|
||||
rootNode.isSystemPackage
|
||||
rootNode.shouldSkipPackage
|
||||
launcherPackageNameManager.launcherPackages
|
||||
accessibilityAutofillManager.accessibilityAction
|
||||
|
@ -238,6 +276,7 @@ class BitwardenAccessibilityProcessorTest {
|
|||
val uri = mockk<Uri>()
|
||||
val attemptFill = AccessibilityAction.AttemptFill(cipherView = cipherView, uri = uri)
|
||||
val rootNode = mockk<AccessibilityNodeInfo> {
|
||||
every { isSystemPackage } returns false
|
||||
every { shouldSkipPackage } returns false
|
||||
every { packageName } returns testPackageName
|
||||
}
|
||||
|
@ -252,6 +291,7 @@ class BitwardenAccessibilityProcessorTest {
|
|||
|
||||
verify(exactly = 1) {
|
||||
powerManager.isInteractive
|
||||
rootNode.isSystemPackage
|
||||
rootNode.shouldSkipPackage
|
||||
launcherPackageNameManager.launcherPackages
|
||||
accessibilityAutofillManager.accessibilityAction
|
||||
|
@ -285,6 +325,7 @@ class BitwardenAccessibilityProcessorTest {
|
|||
val uri = mockk<Uri>()
|
||||
val attemptFill = AccessibilityAction.AttemptFill(cipherView = cipherView, uri = uri)
|
||||
val rootNode = mockk<AccessibilityNodeInfo> {
|
||||
every { isSystemPackage } returns false
|
||||
every { shouldSkipPackage } returns false
|
||||
every { packageName } returns testPackageName
|
||||
}
|
||||
|
@ -302,6 +343,7 @@ class BitwardenAccessibilityProcessorTest {
|
|||
|
||||
verify(exactly = 1) {
|
||||
powerManager.isInteractive
|
||||
rootNode.isSystemPackage
|
||||
rootNode.shouldSkipPackage
|
||||
launcherPackageNameManager.launcherPackages
|
||||
accessibilityAutofillManager.accessibilityAction
|
||||
|
|
|
@ -105,6 +105,43 @@ class AccessibilityNodeInfoExtensionsTest {
|
|||
assertTrue(accessibilityNodeInfo.isEditText)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `isSystemPackage when packageName is null should return false`() {
|
||||
val accessibilityNodeInfo = mockk<AccessibilityNodeInfo> {
|
||||
every { packageName } returns null
|
||||
}
|
||||
|
||||
assertFalse(accessibilityNodeInfo.isSystemPackage)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `isSystemPackage when packageName is blank should return false`() {
|
||||
val accessibilityNodeInfo = mockk<AccessibilityNodeInfo> {
|
||||
every { packageName } returns ""
|
||||
}
|
||||
|
||||
assertFalse(accessibilityNodeInfo.isSystemPackage)
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `isSystemPackage when packageName is populated with non system UI package should return false`() {
|
||||
val accessibilityNodeInfo = mockk<AccessibilityNodeInfo> {
|
||||
every { packageName } returns "com.x8bit.bitwarden.beta"
|
||||
}
|
||||
|
||||
assertFalse(accessibilityNodeInfo.isSystemPackage)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `isSystemPackage when packageName is system UI package should return true`() {
|
||||
val accessibilityNodeInfo = mockk<AccessibilityNodeInfo> {
|
||||
every { packageName } returns "com.android.systemui"
|
||||
}
|
||||
|
||||
assertTrue(accessibilityNodeInfo.isSystemPackage)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `shouldSkipPackage when packageName is null should return true`() {
|
||||
val accessibilityNodeInfo = mockk<AccessibilityNodeInfo> {
|
||||
|
@ -123,15 +160,6 @@ class AccessibilityNodeInfoExtensionsTest {
|
|||
assertTrue(accessibilityNodeInfo.shouldSkipPackage)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `shouldSkipPackage when packageName is system UI package should return true`() {
|
||||
val accessibilityNodeInfo = mockk<AccessibilityNodeInfo> {
|
||||
every { packageName } returns "com.android.systemui"
|
||||
}
|
||||
|
||||
assertTrue(accessibilityNodeInfo.shouldSkipPackage)
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `shouldSkipPackage when packageName is prefixed with bitwarden package should return true`() {
|
||||
|
|
Loading…
Reference in a new issue