mirror of
https://github.com/bitwarden/android.git
synced 2024-12-18 07:11:51 +03:00
Create reusable isAccessibilityServiceEnabled extension (#3929)
This commit is contained in:
parent
76cc9c8579
commit
503c966177
4 changed files with 124 additions and 46 deletions
|
@ -1,9 +1,8 @@
|
|||
package com.x8bit.bitwarden.data.autofill.accessibility.manager
|
||||
|
||||
import android.content.Context
|
||||
import android.provider.Settings
|
||||
import androidx.lifecycle.LifecycleCoroutineScope
|
||||
import com.x8bit.bitwarden.LEGACY_ACCESSIBILITY_SERVICE_NAME
|
||||
import com.x8bit.bitwarden.data.autofill.accessibility.util.isAccessibilityServiceEnabled
|
||||
import com.x8bit.bitwarden.data.platform.manager.AppForegroundManager
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
|
@ -17,28 +16,12 @@ class AccessibilityActivityManagerImpl(
|
|||
appForegroundManager: AppForegroundManager,
|
||||
lifecycleScope: LifecycleCoroutineScope,
|
||||
) : AccessibilityActivityManager {
|
||||
private val isAccessibilityServiceEnabled: Boolean
|
||||
get() {
|
||||
val appContext = context.applicationContext
|
||||
val accessibilityService = appContext
|
||||
.packageName
|
||||
?.let { "$it/$LEGACY_ACCESSIBILITY_SERVICE_NAME" }
|
||||
?: return false
|
||||
return Settings
|
||||
.Secure
|
||||
.getString(
|
||||
appContext.contentResolver,
|
||||
Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
|
||||
)
|
||||
?.contains(accessibilityService)
|
||||
?: false
|
||||
}
|
||||
|
||||
init {
|
||||
appForegroundManager
|
||||
.appForegroundStateFlow
|
||||
.onEach {
|
||||
accessibilityEnabledManager.isAccessibilityEnabled = isAccessibilityServiceEnabled
|
||||
accessibilityEnabledManager.isAccessibilityEnabled =
|
||||
context.isAccessibilityServiceEnabled
|
||||
}
|
||||
.launchIn(lifecycleScope)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
package com.x8bit.bitwarden.data.autofill.accessibility.util
|
||||
|
||||
import android.content.Context
|
||||
import android.provider.Settings
|
||||
import com.x8bit.bitwarden.LEGACY_ACCESSIBILITY_SERVICE_NAME
|
||||
import com.x8bit.bitwarden.data.autofill.accessibility.BitwardenAccessibilityService
|
||||
|
||||
/**
|
||||
* Helper method to determine if the [BitwardenAccessibilityService] is enabled.
|
||||
*/
|
||||
val Context.isAccessibilityServiceEnabled: Boolean
|
||||
get() {
|
||||
val appContext = this.applicationContext
|
||||
val accessibilityServiceName = appContext
|
||||
.packageName
|
||||
?.let { "$it/$LEGACY_ACCESSIBILITY_SERVICE_NAME" }
|
||||
?: return false
|
||||
return Settings
|
||||
.Secure
|
||||
.getString(
|
||||
appContext.contentResolver,
|
||||
Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
|
||||
)
|
||||
?.contains(accessibilityServiceName)
|
||||
?: false
|
||||
}
|
|
@ -1,9 +1,9 @@
|
|||
package com.x8bit.bitwarden.data.autofill.accessibility.manager
|
||||
|
||||
import android.content.Context
|
||||
import android.provider.Settings
|
||||
import androidx.lifecycle.LifecycleCoroutineScope
|
||||
import app.cash.turbine.test
|
||||
import com.x8bit.bitwarden.data.autofill.accessibility.util.isAccessibilityServiceEnabled
|
||||
import com.x8bit.bitwarden.data.platform.manager.AppForegroundManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.model.AppForegroundState
|
||||
import io.mockk.every
|
||||
|
@ -22,11 +22,7 @@ import org.junit.jupiter.api.Test
|
|||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
class AccessibilityActivityManagerTest {
|
||||
private val context: Context = mockk {
|
||||
every { applicationContext } returns this
|
||||
every { packageName } returns "com.x8bit.bitwarden"
|
||||
every { contentResolver } returns mockk()
|
||||
}
|
||||
private val context: Context = mockk()
|
||||
private val accessibilityEnabledManager: AccessibilityEnabledManager =
|
||||
AccessibilityEnabledManagerImpl()
|
||||
private val mutableAppForegroundStateFlow = MutableStateFlow(AppForegroundState.BACKGROUNDED)
|
||||
|
@ -38,24 +34,23 @@ class AccessibilityActivityManagerTest {
|
|||
}
|
||||
|
||||
// We will construct an instance here just to hook the various dependencies together internally
|
||||
@Suppress("unused")
|
||||
private val autofillActivityManager: AccessibilityActivityManager =
|
||||
AccessibilityActivityManagerImpl(
|
||||
private lateinit var autofillActivityManager: AccessibilityActivityManager
|
||||
|
||||
@BeforeEach
|
||||
fun setup() {
|
||||
mockkStatic(Context::isAccessibilityServiceEnabled)
|
||||
every { context.isAccessibilityServiceEnabled } returns false
|
||||
autofillActivityManager = AccessibilityActivityManagerImpl(
|
||||
context = context,
|
||||
accessibilityEnabledManager = accessibilityEnabledManager,
|
||||
appForegroundManager = appForegroundManager,
|
||||
lifecycleScope = lifecycleScope,
|
||||
)
|
||||
|
||||
@BeforeEach
|
||||
fun setup() {
|
||||
mockkStatic(Settings.Secure::getString)
|
||||
mockkSettingsSecureGetString(value = null)
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
fun tearDown() {
|
||||
unmockkStatic(Settings.Secure::getString)
|
||||
unmockkStatic(Context::isAccessibilityServiceEnabled)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -66,10 +61,7 @@ class AccessibilityActivityManagerTest {
|
|||
|
||||
// An update is received when both the accessibility state and foreground state
|
||||
// change
|
||||
@Suppress("MaxLineLength")
|
||||
mockkSettingsSecureGetString(
|
||||
value = "com.x8bit.bitwarden/com.x8bit.bitwarden.Accessibility.AccessibilityService",
|
||||
)
|
||||
every { context.isAccessibilityServiceEnabled } returns true
|
||||
mutableAppForegroundStateFlow.value = AppForegroundState.FOREGROUNDED
|
||||
assertTrue(awaitItem())
|
||||
|
||||
|
@ -78,7 +70,7 @@ class AccessibilityActivityManagerTest {
|
|||
expectNoEvents()
|
||||
|
||||
// An update is not received when only the accessibility state changes
|
||||
mockkSettingsSecureGetString(value = "com.x8bit.bitwarden/AccessibilityService")
|
||||
every { context.isAccessibilityServiceEnabled } returns false
|
||||
expectNoEvents()
|
||||
|
||||
// An update is received after both states have changed
|
||||
|
@ -86,10 +78,4 @@ class AccessibilityActivityManagerTest {
|
|||
assertFalse(awaitItem())
|
||||
}
|
||||
}
|
||||
|
||||
private fun mockkSettingsSecureGetString(value: String?) {
|
||||
every {
|
||||
Settings.Secure.getString(any(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES)
|
||||
} returns value
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
package com.x8bit.bitwarden.data.autofill.accessibility.util
|
||||
|
||||
import android.content.Context
|
||||
import android.provider.Settings
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.mockkStatic
|
||||
import io.mockk.unmockkStatic
|
||||
import org.junit.jupiter.api.AfterEach
|
||||
import org.junit.jupiter.api.Assertions.assertFalse
|
||||
import org.junit.jupiter.api.Assertions.assertTrue
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
class ContextExtensionsTest {
|
||||
|
||||
@BeforeEach
|
||||
fun setup() {
|
||||
mockkStatic(Settings.Secure::getString)
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
fun tearDown() {
|
||||
unmockkStatic(Settings.Secure::getString)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `isAccessibilityServiceEnabled with null package name returns false`() {
|
||||
val context: Context = mockk {
|
||||
every { applicationContext } returns this
|
||||
every { packageName } returns null
|
||||
}
|
||||
|
||||
assertFalse(context.isAccessibilityServiceEnabled)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `isAccessibilityServiceEnabled with null secure string returns false`() {
|
||||
val context: Context = mockk {
|
||||
every { applicationContext } returns this
|
||||
every { packageName } returns "com.x8bit.bitwarden"
|
||||
every { contentResolver } returns mockk()
|
||||
}
|
||||
mockkSettingsSecureGetString(value = null)
|
||||
|
||||
assertFalse(context.isAccessibilityServiceEnabled)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `isAccessibilityServiceEnabled with incorrect secure string returns false`() {
|
||||
val context: Context = mockk {
|
||||
every { applicationContext } returns this
|
||||
every { packageName } returns "com.x8bit.bitwarden"
|
||||
every { contentResolver } returns mockk()
|
||||
}
|
||||
@Suppress("MaxLineLength")
|
||||
mockkSettingsSecureGetString(
|
||||
value = "com.x8bit.bitwarden.dev/com.x8bit.bitwarden.Accessibility.AccessibilityService",
|
||||
)
|
||||
|
||||
assertFalse(context.isAccessibilityServiceEnabled)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `isAccessibilityServiceEnabled with correct secure string returns true`() {
|
||||
val context: Context = mockk {
|
||||
every { applicationContext } returns this
|
||||
every { packageName } returns "com.x8bit.bitwarden"
|
||||
every { contentResolver } returns mockk()
|
||||
}
|
||||
mockkSettingsSecureGetString(
|
||||
value = "com.x8bit.bitwarden/com.x8bit.bitwarden.Accessibility.AccessibilityService",
|
||||
)
|
||||
|
||||
assertTrue(context.isAccessibilityServiceEnabled)
|
||||
}
|
||||
|
||||
private fun mockkSettingsSecureGetString(value: String?) {
|
||||
every {
|
||||
Settings.Secure.getString(any(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES)
|
||||
} returns value
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue