PM-10855: Update the minimum SDK to API 29 (Android 10) (#3723)

This commit is contained in:
David Perez 2024-08-14 09:23:13 -05:00 committed by GitHub
parent 151b081161
commit 2bed4986a1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 6 additions and 272 deletions

View file

@ -11,7 +11,7 @@
## Compatibility ## Compatibility
- **Minimum SDK**: 28 - **Minimum SDK**: 29
- **Target SDK**: 34 - **Target SDK**: 34
- **Device Types Supported**: Phone and Tablet - **Device Types Supported**: Phone and Tablet
- **Orientations Supported**: Portrait and Landscape - **Orientations Supported**: Portrait and Landscape

View file

@ -2,7 +2,6 @@ package com.x8bit.bitwarden.data.autofill.builder
import android.service.autofill.FillRequest import android.service.autofill.FillRequest
import android.service.autofill.SaveInfo import android.service.autofill.SaveInfo
import com.x8bit.bitwarden.data.autofill.model.AutofillAppInfo
import com.x8bit.bitwarden.data.autofill.model.AutofillPartition import com.x8bit.bitwarden.data.autofill.model.AutofillPartition
/** /**
@ -12,13 +11,11 @@ interface SaveInfoBuilder {
/** /**
* Build a save info out the provided data. If that isn't possible, return null. * Build a save info out the provided data. If that isn't possible, return null.
* *
* @param autofillAppInfo App data that is required for building the [SaveInfo].
* @param autofillPartition The portion of the processed [FillRequest] that will be filled. * @param autofillPartition The portion of the processed [FillRequest] that will be filled.
* @param fillRequest The [FillRequest] that initiated the autofill flow. * @param fillRequest The [FillRequest] that initiated the autofill flow.
* @param packageName The package name that was extracted from the [FillRequest]. * @param packageName The package name that was extracted from the [FillRequest].
*/ */
fun build( fun build(
autofillAppInfo: AutofillAppInfo,
autofillPartition: AutofillPartition, autofillPartition: AutofillPartition,
fillRequest: FillRequest, fillRequest: FillRequest,
packageName: String?, packageName: String?,

View file

@ -1,10 +1,7 @@
package com.x8bit.bitwarden.data.autofill.builder package com.x8bit.bitwarden.data.autofill.builder
import android.annotation.SuppressLint
import android.os.Build
import android.service.autofill.FillRequest import android.service.autofill.FillRequest
import android.service.autofill.SaveInfo import android.service.autofill.SaveInfo
import com.x8bit.bitwarden.data.autofill.model.AutofillAppInfo
import com.x8bit.bitwarden.data.autofill.model.AutofillPartition import com.x8bit.bitwarden.data.autofill.model.AutofillPartition
import com.x8bit.bitwarden.data.platform.repository.SettingsRepository import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
@ -16,9 +13,7 @@ class SaveInfoBuilderImpl(
val settingsRepository: SettingsRepository, val settingsRepository: SettingsRepository,
) : SaveInfoBuilder { ) : SaveInfoBuilder {
@SuppressLint("InlinedApi")
override fun build( override fun build(
autofillAppInfo: AutofillAppInfo,
autofillPartition: AutofillPartition, autofillPartition: AutofillPartition,
fillRequest: FillRequest, fillRequest: FillRequest,
packageName: String?, packageName: String?,
@ -29,12 +24,8 @@ class SaveInfoBuilderImpl(
// Docs state that password fields cannot be reliably saved // Docs state that password fields cannot be reliably saved
// in Compat mode since they show as masked values. // in Compat mode since they show as masked values.
val isInCompatMode = if (autofillAppInfo.sdkInt >= Build.VERSION_CODES.Q) { val isInCompatMode = (fillRequest.flags or
// Attempt to automatically establish compat request mode on Android 10+ FillRequest.FLAG_COMPATIBILITY_MODE_REQUEST) == fillRequest.flags
(fillRequest.flags or FillRequest.FLAG_COMPATIBILITY_MODE_REQUEST) == fillRequest.flags
} else {
COMPAT_BROWSERS.contains(packageName)
}
// If login and compat mode, the password might be obfuscated, // If login and compat mode, the password might be obfuscated,
// in which case we should skip the save request. // in which case we should skip the save request.
@ -58,103 +49,3 @@ class SaveInfoBuilderImpl(
} }
} }
} }
/**
* These browsers function using the compatibility shim for the Autofill Framework.
*
* Ensure that these entries are sorted alphabetically and keep this list synchronized with the
* values in /xml/autofill_service_configuration.xml and
* /xml-v30/autofill_service_configuration.xml.
*/
private val COMPAT_BROWSERS: List<String> = listOf(
"alook.browser",
"alook.browser.google",
"app.vanadium.browser",
"com.amazon.cloud9",
"com.android.browser",
"com.android.chrome",
"com.android.htmlviewer",
"com.avast.android.secure.browser",
"com.avg.android.secure.browser",
"com.brave.browser",
"com.brave.browser_beta",
"com.brave.browser_default",
"com.brave.browser_dev",
"com.brave.browser_nightly",
"com.chrome.beta",
"com.chrome.canary",
"com.chrome.dev",
"com.cookiegames.smartcookie",
"com.cookiejarapps.android.smartcookieweb",
"com.ecosia.android",
"com.google.android.apps.chrome",
"com.google.android.apps.chrome_dev",
"com.google.android.captiveportallogin",
"com.iode.firefox",
"com.jamal2367.styx",
"com.kiwibrowser.browser",
"com.kiwibrowser.browser.dev",
"com.lemurbrowser.exts",
"com.microsoft.emmx",
"com.microsoft.emmx.beta",
"com.microsoft.emmx.canary",
"com.microsoft.emmx.dev",
"com.mmbox.browser",
"com.mmbox.xbrowser",
"com.mycompany.app.soulbrowser",
"com.naver.whale",
"com.neeva.app",
"com.opera.browser",
"com.opera.browser.beta",
"com.opera.gx",
"com.opera.mini.native",
"com.opera.mini.native.beta",
"com.opera.touch",
"com.qflair.browserq",
"com.qwant.liberty",
"com.rainsee.create",
"com.sec.android.app.sbrowser",
"com.sec.android.app.sbrowser.beta",
"com.stoutner.privacybrowser.free",
"com.stoutner.privacybrowser.standard",
"com.vivaldi.browser",
"com.vivaldi.browser.snapshot",
"com.vivaldi.browser.sopranos",
"com.yandex.browser",
"com.yjllq.internet",
"com.yjllq.kito",
"com.yujian.ResideMenuDemo",
"com.z28j.feel",
"idm.internet.download.manager",
"idm.internet.download.manager.adm.lite",
"idm.internet.download.manager.plus",
"io.github.forkmaintainers.iceraven",
"mark.via",
"mark.via.gp",
"net.dezor.browser",
"net.slions.fulguris.full.download",
"net.slions.fulguris.full.download.debug",
"net.slions.fulguris.full.playstore",
"net.slions.fulguris.full.playstore.debug",
"org.adblockplus.browser",
"org.adblockplus.browser.beta",
"org.bromite.bromite",
"org.bromite.chromium",
"org.chromium.chrome",
"org.codeaurora.swe.browser",
"org.cromite.cromite",
"org.gnu.icecat",
"org.mozilla.fenix",
"org.mozilla.fenix.nightly",
"org.mozilla.fennec_aurora",
"org.mozilla.fennec_fdroid",
"org.mozilla.firefox",
"org.mozilla.firefox_beta",
"org.mozilla.reference.browser",
"org.mozilla.rocket",
"org.torproject.torbrowser",
"org.torproject.torbrowser_alpha",
"org.ungoogled.chromium.extensions.stable",
"org.ungoogled.chromium.stable",
"us.spotco.fennec_dos",
)

View file

@ -128,7 +128,6 @@ class AutofillProcessorImpl(
autofillRequest = autofillRequest, autofillRequest = autofillRequest,
) )
val saveInfo = saveInfoBuilder.build( val saveInfo = saveInfoBuilder.build(
autofillAppInfo = autofillAppInfo,
autofillPartition = autofillRequest.partition, autofillPartition = autofillRequest.partition,
fillRequest = fillRequest, fillRequest = fillRequest,
packageName = autofillRequest.packageName, packageName = autofillRequest.packageName,

View file

@ -3,8 +3,7 @@
android:supportsInlineSuggestions="true"> android:supportsInlineSuggestions="true">
<!-- <!--
"Maintain alphabetical order for these compatibility packages and ensure synchronization with "Maintain alphabetical order for these compatibility packages and ensure synchronization with
both /xml/autofill_service_configuration.xml and the COMPAT_BROWSERS list within /xml/autofill_service_configuration.xml.
SaveInfoBuilderImpl.kt."
--> -->
<compatibility-package <compatibility-package
android:name="alook.browser" android:name="alook.browser"

View file

@ -2,8 +2,7 @@
<autofill-service xmlns:android="http://schemas.android.com/apk/res/android"> <autofill-service xmlns:android="http://schemas.android.com/apk/res/android">
<!-- <!--
"Maintain alphabetical order for these compatibility packages and ensure synchronization with "Maintain alphabetical order for these compatibility packages and ensure synchronization with
both /xml-v30/autofill_service_configuration.xml and the COMPAT_BROWSERS list within /xml-v30/autofill_service_configuration.xml.
SaveInfoBuilderImpl.kt."
--> -->
<compatibility-package <compatibility-package
android:name="alook.browser" android:name="alook.browser"

View file

@ -1,11 +1,9 @@
package com.x8bit.bitwarden.data.autofill.builder package com.x8bit.bitwarden.data.autofill.builder
import android.os.Build
import android.service.autofill.FillRequest import android.service.autofill.FillRequest
import android.service.autofill.SaveInfo import android.service.autofill.SaveInfo
import android.view.View import android.view.View
import android.view.autofill.AutofillId import android.view.autofill.AutofillId
import com.x8bit.bitwarden.data.autofill.model.AutofillAppInfo
import com.x8bit.bitwarden.data.autofill.model.AutofillPartition import com.x8bit.bitwarden.data.autofill.model.AutofillPartition
import com.x8bit.bitwarden.data.autofill.model.AutofillView import com.x8bit.bitwarden.data.autofill.model.AutofillView
import com.x8bit.bitwarden.data.platform.repository.SettingsRepository import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
@ -26,7 +24,6 @@ class SaveInfoBuilderTest {
private val settingsRepository: SettingsRepository = mockk() private val settingsRepository: SettingsRepository = mockk()
private val autofillAppInfo: AutofillAppInfo = mockk()
private val fillRequest: FillRequest = mockk() private val fillRequest: FillRequest = mockk()
private val autofillIdOptional: AutofillId = mockk() private val autofillIdOptional: AutofillId = mockk()
private val autofillViewDataOptional = AutofillView.Data( private val autofillViewDataOptional = AutofillView.Data(
@ -89,7 +86,6 @@ class SaveInfoBuilderTest {
// Test // Test
val actual = saveInfoBuilder.build( val actual = saveInfoBuilder.build(
autofillAppInfo = autofillAppInfo,
autofillPartition = autofillPartitionCard, autofillPartition = autofillPartitionCard,
fillRequest = fillRequest, fillRequest = fillRequest,
packageName = PACKAGE_NAME, packageName = PACKAGE_NAME,
@ -106,7 +102,6 @@ class SaveInfoBuilderTest {
// Test // Test
val actual = saveInfoBuilder.build( val actual = saveInfoBuilder.build(
autofillAppInfo = autofillAppInfo,
autofillPartition = AUTOFILL_PARTITION_LOGIN_EMPTY, autofillPartition = AUTOFILL_PARTITION_LOGIN_EMPTY,
fillRequest = fillRequest, fillRequest = fillRequest,
packageName = PACKAGE_NAME, packageName = PACKAGE_NAME,
@ -122,11 +117,9 @@ class SaveInfoBuilderTest {
// Setup // Setup
every { settingsRepository.isAutofillSavePromptDisabled } returns false every { settingsRepository.isAutofillSavePromptDisabled } returns false
every { fillRequest.flags } returns FillRequest.FLAG_COMPATIBILITY_MODE_REQUEST every { fillRequest.flags } returns FillRequest.FLAG_COMPATIBILITY_MODE_REQUEST
every { autofillAppInfo.sdkInt } returns Build.VERSION_CODES.TIRAMISU
// Test // Test
val actual = saveInfoBuilder.build( val actual = saveInfoBuilder.build(
autofillAppInfo = autofillAppInfo,
autofillPartition = autofillPartitionLogin, autofillPartition = autofillPartitionLogin,
fillRequest = fillRequest, fillRequest = fillRequest,
packageName = PACKAGE_NAME, packageName = PACKAGE_NAME,
@ -136,35 +129,12 @@ class SaveInfoBuilderTest {
assertNull(actual) assertNull(actual)
} }
@Suppress("MaxLineLength")
@Test
fun `build should return null if autofill possible but package name is in compat list and is login`() {
// Setup
every { settingsRepository.isAutofillSavePromptDisabled } returns false
every { autofillAppInfo.sdkInt } returns Build.VERSION_CODES.P
// Test
COMPAT_BROWSERS
.forEach { packageName ->
val actual = saveInfoBuilder.build(
autofillAppInfo = autofillAppInfo,
autofillPartition = autofillPartitionLogin,
fillRequest = fillRequest,
packageName = packageName,
)
// Verify
assertNull(actual)
}
}
@Suppress("MaxLineLength") @Suppress("MaxLineLength")
@Test @Test
fun `build should return SaveInfo with flag set if autofill possible, flags indicate compat mode, and is card`() { fun `build should return SaveInfo with flag set if autofill possible, flags indicate compat mode, and is card`() {
// Setup // Setup
every { settingsRepository.isAutofillSavePromptDisabled } returns false every { settingsRepository.isAutofillSavePromptDisabled } returns false
every { fillRequest.flags } returns FillRequest.FLAG_COMPATIBILITY_MODE_REQUEST every { fillRequest.flags } returns FillRequest.FLAG_COMPATIBILITY_MODE_REQUEST
every { autofillAppInfo.sdkInt } returns Build.VERSION_CODES.TIRAMISU
mockBuilder<SaveInfo.Builder> { mockBuilder<SaveInfo.Builder> {
it.setOptionalIds(arrayOf(autofillIdOptional)) it.setOptionalIds(arrayOf(autofillIdOptional))
} }
@ -174,7 +144,6 @@ class SaveInfoBuilderTest {
// Test // Test
val actual = saveInfoBuilder.build( val actual = saveInfoBuilder.build(
autofillAppInfo = autofillAppInfo,
autofillPartition = autofillPartitionCard, autofillPartition = autofillPartitionCard,
fillRequest = fillRequest, fillRequest = fillRequest,
packageName = PACKAGE_NAME, packageName = PACKAGE_NAME,
@ -187,126 +156,9 @@ class SaveInfoBuilderTest {
anyConstructed<SaveInfo.Builder>().setFlags(SaveInfo.FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE) anyConstructed<SaveInfo.Builder>().setFlags(SaveInfo.FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE)
} }
} }
@Suppress("MaxLineLength")
@Test
fun `build should return SaveInfo if autofill possible, packageName is not in compat list, and is login`() {
// Setup
every { settingsRepository.isAutofillSavePromptDisabled } returns false
every { autofillAppInfo.sdkInt } returns Build.VERSION_CODES.P
mockBuilder<SaveInfo.Builder> {
it.setOptionalIds(arrayOf(autofillIdOptional))
}
// Test
val actual = saveInfoBuilder.build(
autofillAppInfo = autofillAppInfo,
autofillPartition = autofillPartitionLogin,
fillRequest = fillRequest,
packageName = PACKAGE_NAME,
)
// Verify
assertEquals(saveInfo, actual)
verify(exactly = 1) {
anyConstructed<SaveInfo.Builder>().setOptionalIds(arrayOf(autofillIdOptional))
}
}
} }
private const val PACKAGE_NAME: String = "com.google" private const val PACKAGE_NAME: String = "com.google"
private val AUTOFILL_PARTITION_LOGIN_EMPTY: AutofillPartition.Login = AutofillPartition.Login( private val AUTOFILL_PARTITION_LOGIN_EMPTY: AutofillPartition.Login = AutofillPartition.Login(
views = listOf(), views = listOf(),
) )
private val COMPAT_BROWSERS: List<String> = listOf(
"alook.browser",
"alook.browser.google",
"app.vanadium.browser",
"com.amazon.cloud9",
"com.android.browser",
"com.android.chrome",
"com.android.htmlviewer",
"com.avast.android.secure.browser",
"com.avg.android.secure.browser",
"com.brave.browser",
"com.brave.browser_beta",
"com.brave.browser_default",
"com.brave.browser_dev",
"com.brave.browser_nightly",
"com.chrome.beta",
"com.chrome.canary",
"com.chrome.dev",
"com.cookiegames.smartcookie",
"com.cookiejarapps.android.smartcookieweb",
"com.ecosia.android",
"com.google.android.apps.chrome",
"com.google.android.apps.chrome_dev",
"com.google.android.captiveportallogin",
"com.iode.firefox",
"com.jamal2367.styx",
"com.kiwibrowser.browser",
"com.kiwibrowser.browser.dev",
"com.lemurbrowser.exts",
"com.microsoft.emmx",
"com.microsoft.emmx.beta",
"com.microsoft.emmx.canary",
"com.microsoft.emmx.dev",
"com.mmbox.browser",
"com.mmbox.xbrowser",
"com.mycompany.app.soulbrowser",
"com.naver.whale",
"com.neeva.app",
"com.opera.browser",
"com.opera.browser.beta",
"com.opera.gx",
"com.opera.mini.native",
"com.opera.mini.native.beta",
"com.opera.touch",
"com.qflair.browserq",
"com.qwant.liberty",
"com.rainsee.create",
"com.sec.android.app.sbrowser",
"com.sec.android.app.sbrowser.beta",
"com.stoutner.privacybrowser.free",
"com.stoutner.privacybrowser.standard",
"com.vivaldi.browser",
"com.vivaldi.browser.snapshot",
"com.vivaldi.browser.sopranos",
"com.yandex.browser",
"com.yjllq.internet",
"com.yjllq.kito",
"com.yujian.ResideMenuDemo",
"com.z28j.feel",
"idm.internet.download.manager",
"idm.internet.download.manager.adm.lite",
"idm.internet.download.manager.plus",
"io.github.forkmaintainers.iceraven",
"mark.via",
"mark.via.gp",
"net.dezor.browser",
"net.slions.fulguris.full.download",
"net.slions.fulguris.full.download.debug",
"net.slions.fulguris.full.playstore",
"net.slions.fulguris.full.playstore.debug",
"org.adblockplus.browser",
"org.adblockplus.browser.beta",
"org.bromite.bromite",
"org.bromite.chromium",
"org.chromium.chrome",
"org.codeaurora.swe.browser",
"org.cromite.cromite",
"org.gnu.icecat",
"org.mozilla.fenix",
"org.mozilla.fenix.nightly",
"org.mozilla.fennec_aurora",
"org.mozilla.fennec_fdroid",
"org.mozilla.firefox",
"org.mozilla.firefox_beta",
"org.mozilla.reference.browser",
"org.mozilla.rocket",
"org.torproject.torbrowser",
"org.torproject.torbrowser_alpha",
"org.ungoogled.chromium.extensions.stable",
"org.ungoogled.chromium.stable",
"us.spotco.fennec_dos",
)

View file

@ -157,7 +157,6 @@ class AutofillProcessorTest {
} returns autofillRequest } returns autofillRequest
every { every {
saveInfoBuilder.build( saveInfoBuilder.build(
autofillAppInfo = appInfo,
autofillPartition = autofillPartition, autofillPartition = autofillPartition,
fillRequest = fillRequest, fillRequest = fillRequest,
packageName = PACKAGE_NAME, packageName = PACKAGE_NAME,
@ -233,7 +232,6 @@ class AutofillProcessorTest {
} returns autofillRequest } returns autofillRequest
every { every {
saveInfoBuilder.build( saveInfoBuilder.build(
autofillAppInfo = appInfo,
autofillPartition = autofillPartition, autofillPartition = autofillPartition,
fillRequest = fillRequest, fillRequest = fillRequest,
packageName = PACKAGE_NAME, packageName = PACKAGE_NAME,
@ -494,7 +492,6 @@ class AutofillProcessorTest {
coEvery { filledDataBuilder.build(autofillRequest = autofillRequest) } returns filledData coEvery { filledDataBuilder.build(autofillRequest = autofillRequest) } returns filledData
every { every {
saveInfoBuilder.build( saveInfoBuilder.build(
autofillAppInfo = appInfo,
autofillPartition = autofillPartition, autofillPartition = autofillPartition,
fillRequest = fillRequest, fillRequest = fillRequest,
packageName = PACKAGE_NAME, packageName = PACKAGE_NAME,

View file

@ -4,7 +4,7 @@
# SDK Versions # SDK Versions
compileSdk = "34" compileSdk = "34"
targetSdk = "34" targetSdk = "34"
minSdk = "28" minSdk = "29"
# Dependency Versions # Dependency Versions
androidGradlePlugin = "8.5.1" androidGradlePlugin = "8.5.1"