BIT-1486: Use inline autofill based on user's setting (#702)

This commit is contained in:
Brian Yencho 2024-01-21 13:31:26 -06:00 committed by Álison Fernandes
parent 99f5325580
commit 4510695f76
5 changed files with 141 additions and 10 deletions

View file

@ -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()

View file

@ -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(

View file

@ -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

View file

@ -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)
}

View file

@ -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