mirror of
https://github.com/bitwarden/android.git
synced 2024-10-31 15:15:34 +03:00
BIT-1486: Use inline autofill based on user's setting (#702)
This commit is contained in:
parent
99f5325580
commit
4510695f76
5 changed files with 141 additions and 10 deletions
|
@ -13,6 +13,7 @@ import com.x8bit.bitwarden.data.autofill.processor.AutofillProcessorImpl
|
|||
import com.x8bit.bitwarden.data.autofill.provider.AutofillCipherProvider
|
||||
import com.x8bit.bitwarden.data.autofill.provider.AutofillCipherProviderImpl
|
||||
import com.x8bit.bitwarden.data.platform.manager.dispatcher.DispatcherManager
|
||||
import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
|
@ -34,7 +35,12 @@ object AutofillModule {
|
|||
): AutofillManager = context.getSystemService(AutofillManager::class.java)
|
||||
|
||||
@Provides
|
||||
fun providesAutofillParser(): AutofillParser = AutofillParserImpl()
|
||||
fun providesAutofillParser(
|
||||
settingsRepository: SettingsRepository,
|
||||
): AutofillParser =
|
||||
AutofillParserImpl(
|
||||
settingsRepository = settingsRepository,
|
||||
)
|
||||
|
||||
@Provides
|
||||
fun providesAutofillCipherProvider(): AutofillCipherProvider = AutofillCipherProviderImpl()
|
||||
|
|
|
@ -12,12 +12,15 @@ import com.x8bit.bitwarden.data.autofill.util.buildUriOrNull
|
|||
import com.x8bit.bitwarden.data.autofill.util.getInlinePresentationSpecs
|
||||
import com.x8bit.bitwarden.data.autofill.util.getMaxInlineSuggestionsCount
|
||||
import com.x8bit.bitwarden.data.autofill.util.toAutofillView
|
||||
import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
|
||||
|
||||
/**
|
||||
* The default [AutofillParser] implementation for the app. This is a tool for parsing autofill data
|
||||
* from the OS into domain models.
|
||||
*/
|
||||
class AutofillParserImpl : AutofillParser {
|
||||
class AutofillParserImpl(
|
||||
private val settingsRepository: SettingsRepository,
|
||||
) : AutofillParser {
|
||||
override fun parse(
|
||||
autofillAppInfo: AutofillAppInfo,
|
||||
fillRequest: FillRequest,
|
||||
|
@ -79,12 +82,15 @@ class AutofillParserImpl : AutofillParser {
|
|||
.map { it.ignoreAutofillIds }
|
||||
.flatten()
|
||||
|
||||
// Get inline information if available
|
||||
val isInlineAutofillEnabled = settingsRepository.isInlineAutofillEnabled
|
||||
val maxInlineSuggestionsCount = fillRequest.getMaxInlineSuggestionsCount(
|
||||
autofillAppInfo = autofillAppInfo,
|
||||
isInlineAutofillEnabled = isInlineAutofillEnabled,
|
||||
)
|
||||
|
||||
val inlinePresentationSpecs = fillRequest.getInlinePresentationSpecs(
|
||||
autofillAppInfo = autofillAppInfo,
|
||||
isInlineAutofillEnabled = isInlineAutofillEnabled,
|
||||
)
|
||||
|
||||
return AutofillRequest.Fillable(
|
||||
|
|
|
@ -12,8 +12,9 @@ import com.x8bit.bitwarden.data.autofill.model.AutofillAppInfo
|
|||
@SuppressLint("NewApi")
|
||||
fun FillRequest.getInlinePresentationSpecs(
|
||||
autofillAppInfo: AutofillAppInfo,
|
||||
isInlineAutofillEnabled: Boolean,
|
||||
): List<InlinePresentationSpec> =
|
||||
if (autofillAppInfo.sdkInt >= Build.VERSION_CODES.R) {
|
||||
if (isInlineAutofillEnabled && autofillAppInfo.sdkInt >= Build.VERSION_CODES.R) {
|
||||
inlineSuggestionsRequest?.inlinePresentationSpecs ?: emptyList()
|
||||
} else {
|
||||
emptyList()
|
||||
|
@ -26,8 +27,9 @@ fun FillRequest.getInlinePresentationSpecs(
|
|||
@SuppressLint("NewApi")
|
||||
fun FillRequest.getMaxInlineSuggestionsCount(
|
||||
autofillAppInfo: AutofillAppInfo,
|
||||
isInlineAutofillEnabled: Boolean,
|
||||
): Int =
|
||||
if (autofillAppInfo.sdkInt >= Build.VERSION_CODES.R) {
|
||||
if (isInlineAutofillEnabled && autofillAppInfo.sdkInt >= Build.VERSION_CODES.R) {
|
||||
inlineSuggestionsRequest?.maxSuggestionCount ?: 0
|
||||
} else {
|
||||
0
|
||||
|
|
|
@ -15,6 +15,7 @@ import com.x8bit.bitwarden.data.autofill.util.buildUriOrNull
|
|||
import com.x8bit.bitwarden.data.autofill.util.getInlinePresentationSpecs
|
||||
import com.x8bit.bitwarden.data.autofill.util.getMaxInlineSuggestionsCount
|
||||
import com.x8bit.bitwarden.data.autofill.util.toAutofillView
|
||||
import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.mockkStatic
|
||||
|
@ -64,6 +65,11 @@ class AutofillParserTests {
|
|||
every { this@mockk.fillContexts } returns listOf(fillContext)
|
||||
}
|
||||
private val inlinePresentationSpecs: List<InlinePresentationSpec> = mockk()
|
||||
private val settingsRepository: SettingsRepository = mockk {
|
||||
every { isInlineAutofillEnabled } answers { mockIsInlineAutofillEnabled }
|
||||
}
|
||||
|
||||
private var mockIsInlineAutofillEnabled = true
|
||||
|
||||
@BeforeEach
|
||||
fun setup() {
|
||||
|
@ -76,15 +82,31 @@ class AutofillParserTests {
|
|||
every {
|
||||
fillRequest.getInlinePresentationSpecs(
|
||||
autofillAppInfo = autofillAppInfo,
|
||||
isInlineAutofillEnabled = true,
|
||||
)
|
||||
} returns inlinePresentationSpecs
|
||||
every {
|
||||
fillRequest.getInlinePresentationSpecs(
|
||||
autofillAppInfo = autofillAppInfo,
|
||||
isInlineAutofillEnabled = false,
|
||||
)
|
||||
} returns emptyList()
|
||||
every {
|
||||
fillRequest.getMaxInlineSuggestionsCount(
|
||||
autofillAppInfo = autofillAppInfo,
|
||||
isInlineAutofillEnabled = true,
|
||||
)
|
||||
} returns MAX_INLINE_SUGGESTION_COUNT
|
||||
every {
|
||||
fillRequest.getMaxInlineSuggestionsCount(
|
||||
autofillAppInfo = autofillAppInfo,
|
||||
isInlineAutofillEnabled = false,
|
||||
)
|
||||
} returns 0
|
||||
every { any<List<ViewNodeTraversalData>>().buildUriOrNull(assistStructure) } returns URI
|
||||
parser = AutofillParserImpl()
|
||||
parser = AutofillParserImpl(
|
||||
settingsRepository = settingsRepository,
|
||||
)
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
|
@ -183,9 +205,11 @@ class AutofillParserTests {
|
|||
verify(exactly = 1) {
|
||||
fillRequest.getInlinePresentationSpecs(
|
||||
autofillAppInfo = autofillAppInfo,
|
||||
isInlineAutofillEnabled = true,
|
||||
)
|
||||
fillRequest.getMaxInlineSuggestionsCount(
|
||||
autofillAppInfo = autofillAppInfo,
|
||||
isInlineAutofillEnabled = true,
|
||||
)
|
||||
any<List<ViewNodeTraversalData>>().buildUriOrNull(assistStructure)
|
||||
}
|
||||
|
@ -231,9 +255,11 @@ class AutofillParserTests {
|
|||
verify(exactly = 1) {
|
||||
fillRequest.getInlinePresentationSpecs(
|
||||
autofillAppInfo = autofillAppInfo,
|
||||
isInlineAutofillEnabled = true,
|
||||
)
|
||||
fillRequest.getMaxInlineSuggestionsCount(
|
||||
autofillAppInfo = autofillAppInfo,
|
||||
isInlineAutofillEnabled = true,
|
||||
)
|
||||
any<List<ViewNodeTraversalData>>().buildUriOrNull(assistStructure)
|
||||
}
|
||||
|
@ -279,9 +305,11 @@ class AutofillParserTests {
|
|||
verify(exactly = 1) {
|
||||
fillRequest.getInlinePresentationSpecs(
|
||||
autofillAppInfo = autofillAppInfo,
|
||||
isInlineAutofillEnabled = true,
|
||||
)
|
||||
fillRequest.getMaxInlineSuggestionsCount(
|
||||
autofillAppInfo = autofillAppInfo,
|
||||
isInlineAutofillEnabled = true,
|
||||
)
|
||||
any<List<ViewNodeTraversalData>>().buildUriOrNull(assistStructure)
|
||||
}
|
||||
|
@ -327,9 +355,62 @@ class AutofillParserTests {
|
|||
verify(exactly = 1) {
|
||||
fillRequest.getInlinePresentationSpecs(
|
||||
autofillAppInfo = autofillAppInfo,
|
||||
isInlineAutofillEnabled = true,
|
||||
)
|
||||
fillRequest.getMaxInlineSuggestionsCount(
|
||||
autofillAppInfo = autofillAppInfo,
|
||||
isInlineAutofillEnabled = true,
|
||||
)
|
||||
any<List<ViewNodeTraversalData>>().buildUriOrNull(assistStructure)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `parse should return empty inline suggestions when inline autofill is disabled`() {
|
||||
// Setup
|
||||
mockIsInlineAutofillEnabled = false
|
||||
setupAssistStructureWithAllAutofillViewTypes()
|
||||
val cardAutofillView: AutofillView.Card = AutofillView.Card.ExpirationMonth(
|
||||
data = autofillViewData.copy(
|
||||
autofillId = cardAutofillId,
|
||||
isFocused = true,
|
||||
),
|
||||
)
|
||||
val loginAutofillView: AutofillView.Login = AutofillView.Login.Username(
|
||||
data = autofillViewData.copy(
|
||||
autofillId = loginAutofillId,
|
||||
isFocused = true,
|
||||
),
|
||||
)
|
||||
val autofillPartition = AutofillPartition.Card(
|
||||
views = listOf(cardAutofillView),
|
||||
)
|
||||
val expected = AutofillRequest.Fillable(
|
||||
ignoreAutofillIds = emptyList(),
|
||||
inlinePresentationSpecs = emptyList(),
|
||||
maxInlineSuggestionsCount = 0,
|
||||
partition = autofillPartition,
|
||||
uri = URI,
|
||||
)
|
||||
every { cardViewNode.toAutofillView() } returns cardAutofillView
|
||||
every { loginViewNode.toAutofillView() } returns loginAutofillView
|
||||
|
||||
// Test
|
||||
val actual = parser.parse(
|
||||
autofillAppInfo = autofillAppInfo,
|
||||
fillRequest = fillRequest,
|
||||
)
|
||||
|
||||
// Verify
|
||||
assertEquals(expected, actual)
|
||||
verify(exactly = 1) {
|
||||
fillRequest.getInlinePresentationSpecs(
|
||||
autofillAppInfo = autofillAppInfo,
|
||||
isInlineAutofillEnabled = false,
|
||||
)
|
||||
fillRequest.getMaxInlineSuggestionsCount(
|
||||
autofillAppInfo = autofillAppInfo,
|
||||
isInlineAutofillEnabled = false,
|
||||
)
|
||||
any<List<ViewNodeTraversalData>>().buildUriOrNull(assistStructure)
|
||||
}
|
||||
|
|
|
@ -20,7 +20,23 @@ class FillRequestExtensionsTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
fun `getInlinePresentationSpecs should return empty list when pre-R`() {
|
||||
fun `getInlinePresentationSpecs should return empty list when disabled`() {
|
||||
// Setup
|
||||
val autofillAppInfo: AutofillAppInfo = mockk()
|
||||
val expected: List<InlinePresentationSpec> = emptyList()
|
||||
|
||||
// Test
|
||||
val actual = fillRequest.getInlinePresentationSpecs(
|
||||
autofillAppInfo = autofillAppInfo,
|
||||
isInlineAutofillEnabled = false,
|
||||
)
|
||||
|
||||
// Verify
|
||||
assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getInlinePresentationSpecs should return empty list when enabled pre-R`() {
|
||||
// Setup
|
||||
val autofillAppInfo = AutofillAppInfo(
|
||||
context = mockk(),
|
||||
|
@ -32,6 +48,7 @@ class FillRequestExtensionsTest {
|
|||
// Test
|
||||
val actual = fillRequest.getInlinePresentationSpecs(
|
||||
autofillAppInfo = autofillAppInfo,
|
||||
isInlineAutofillEnabled = true,
|
||||
)
|
||||
|
||||
// Verify
|
||||
|
@ -39,7 +56,7 @@ class FillRequestExtensionsTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
fun `getInlinePresentationSpecs should return populated list when post-R`() {
|
||||
fun `getInlinePresentationSpecs should return populated list when enabled and post-R`() {
|
||||
// Setup
|
||||
val autofillAppInfo = AutofillAppInfo(
|
||||
context = mockk(),
|
||||
|
@ -51,6 +68,7 @@ class FillRequestExtensionsTest {
|
|||
// Test
|
||||
val actual = fillRequest.getInlinePresentationSpecs(
|
||||
autofillAppInfo = autofillAppInfo,
|
||||
isInlineAutofillEnabled = true,
|
||||
)
|
||||
|
||||
// Verify
|
||||
|
@ -58,7 +76,23 @@ class FillRequestExtensionsTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
fun `getMaxInlineSuggestionsCount should return 0 when pre-R`() {
|
||||
fun `getMaxInlineSuggestionsCount should return 0 when disabled`() {
|
||||
// Setup
|
||||
val autofillAppInfo: AutofillAppInfo = mockk()
|
||||
val expected = 0
|
||||
|
||||
// Test
|
||||
val actual = fillRequest.getMaxInlineSuggestionsCount(
|
||||
autofillAppInfo = autofillAppInfo,
|
||||
isInlineAutofillEnabled = false,
|
||||
)
|
||||
|
||||
// Verify
|
||||
assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getMaxInlineSuggestionsCount should return 0 when enabled and pre-R`() {
|
||||
// Setup
|
||||
val autofillAppInfo = AutofillAppInfo(
|
||||
context = mockk(),
|
||||
|
@ -70,6 +104,7 @@ class FillRequestExtensionsTest {
|
|||
// Test
|
||||
val actual = fillRequest.getMaxInlineSuggestionsCount(
|
||||
autofillAppInfo = autofillAppInfo,
|
||||
isInlineAutofillEnabled = true,
|
||||
)
|
||||
|
||||
// Verify
|
||||
|
@ -77,7 +112,7 @@ class FillRequestExtensionsTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
fun `getMaxInlineSuggestionsCount should return the max count when post-R`() {
|
||||
fun `getMaxInlineSuggestionsCount should return the max count when enabled and post-R`() {
|
||||
// Setup
|
||||
val autofillAppInfo = AutofillAppInfo(
|
||||
context = mockk(),
|
||||
|
@ -89,6 +124,7 @@ class FillRequestExtensionsTest {
|
|||
// Test
|
||||
val actual = fillRequest.getMaxInlineSuggestionsCount(
|
||||
autofillAppInfo = autofillAppInfo,
|
||||
isInlineAutofillEnabled = true,
|
||||
)
|
||||
|
||||
// Verify
|
||||
|
|
Loading…
Reference in a new issue