Compare commits

...

2 Commits

Author SHA1 Message Date
David Perez
b497156302 🍒 PM-25143: Retain intent data on recreate (#5798) 2025-08-27 20:15:00 +00:00
Patrick Honkonen
ab90f5ff95 🍒[PM-25057] Refactor card restriction logic in AutofillCipherProvider (#5791) 2025-08-27 14:43:23 +00:00
3 changed files with 42 additions and 34 deletions

View File

@@ -43,8 +43,6 @@ import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.map
import javax.inject.Inject
private const val ANDROID_15_BUG_MAX_REVISION: Int = 241007
/**
* Primary entry point for the application.
*/
@@ -217,35 +215,7 @@ class MainActivity : AppCompatActivity() {
}
private fun handleRecreate() {
val isOldAndroidBuildRevision = {
// This fetches the date portion of the ID in order to determine the revision of
// Android 15 being used and whether we want to use the `recreate` API or not.
// If we fail to parse a date, we assume it is not an old revision.
"\\.([^.]+)\\."
.toRegex()
.find(Build.ID)
?.groups
?.get(1)
?.value
?.toIntOrNull()
?.let { it <= ANDROID_15_BUG_MAX_REVISION } == true
}
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.VANILLA_ICE_CREAM &&
isOldAndroidBuildRevision()
) {
// This is done to avoid a bug in specific older revisions of Android 15. The bug has
// been fixed but certain phones that are no longer supported will never get the fix.
// The OS bug is tracked here: https://issuetracker.google.com/issues/370180732
startActivity(
Intent
.makeMainActivity(componentName)
.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION),
)
finish()
overrideActivityTransition(OVERRIDE_TRANSITION_CLOSE, 0, 0)
} else {
ActivityCompat.recreate(this)
}
ActivityCompat.recreate(this)
}
private fun updateScreenCapture(isScreenCaptureAllowed: Boolean) {

View File

@@ -71,7 +71,9 @@ class AutofillCipherProviderImpl(
// Must not require a reprompt.
it.reprompt == CipherRepromptType.NONE &&
// Must not be restricted by organization.
it.organizationId !in organizationIdsWithCardTypeRestrictions
!it.isExcludedByOrgCardRestrictions(
organizationIdsWithCardTypeRestrictions,
)
}
?.let { nonNullCipherListView ->
nonNullCipherListView.id?.let { cipherId ->
@@ -154,4 +156,25 @@ class AutofillCipherProviderImpl(
is GetCipherResult.Success -> result.cipherView
}
/**
* Checks if this [CipherListView] item should be excluded from autofill due to
* organization-based card type restrictions.
*
* It's considered restricted if:
* 1. There are organizations with card type restrictions AND this item is a personal vault item
* (organizationId is null).
* 2. OR this item belongs to an organization that has card type restrictions.
*/
private fun CipherListView.isExcludedByOrgCardRestrictions(
restrictingOrgIds: List<String>,
): Boolean {
if (restrictingOrgIds.isEmpty()) {
return false
}
// If personal vault (no orgId), restricted if any org has restrictions.
return organizationId == null ||
// If part of an org, restricted if that org is in the restricting list.
organizationId in restrictingOrgIds
}
}

View File

@@ -279,7 +279,13 @@ class AutofillCipherProviderTest {
every { deletedDate } returns null
every { type } returns CipherListViewType.Card(cardListView)
every { reprompt } returns CipherRepromptType.NONE
every { organizationId } returns ORGANIZATION_ID
every { organizationId } returns ORGANIZATION_ID_WITH_CARD_TYPE_RESTRICTIONS
}
val personalVaultCardCipherView: CipherListView = mockk {
every { deletedDate } returns null
every { type } returns CipherListViewType.Card(cardListView)
every { reprompt } returns CipherRepromptType.NONE
every { organizationId } returns null
}
val decryptCipherListViewsResult = DecryptCipherListResult(
successes = listOf(
@@ -287,6 +293,7 @@ class AutofillCipherProviderTest {
deletedCardCipherView,
repromptCardCipherView,
restrictedCardCipherView,
personalVaultCardCipherView,
loginCipherListViewWithTotp,
loginCipherListViewWithoutTotp,
),
@@ -295,7 +302,12 @@ class AutofillCipherProviderTest {
every {
policyManager.getActivePolicies(PolicyTypeJson.RESTRICT_ITEM_TYPES)
} returns listOf(createMockPolicy(number = 1, organizationId = ORGANIZATION_ID))
} returns listOf(
createMockPolicy(
number = 1,
organizationId = ORGANIZATION_ID_WITH_CARD_TYPE_RESTRICTIONS,
),
)
coEvery {
vaultRepository.getCipher(CARD_CIPHER_ID)
} returns GetCipherResult.Success(
@@ -314,6 +326,7 @@ class AutofillCipherProviderTest {
val expected = listOf(
CARD_AUTOFILL_CIPHER,
)
every { cardCipherListView.organizationId } returns ORGANIZATION_ID
every { cardCipherListView.subtitle } returns CARD_SUBTITLE
// Test & Verify
@@ -563,6 +576,8 @@ class AutofillCipherProviderTest {
private const val ACTIVE_USER_ID = "activeUserId"
private const val ORGANIZATION_ID = "organizationId"
private const val ORGANIZATION_ID_WITH_CARD_TYPE_RESTRICTIONS =
"organizationIdWithCardTypeRestrictions"
private const val CARD_CARDHOLDER_NAME = "John Doe"
private const val CARD_CODE = "123"
private const val CARD_EXP_MONTH = "January"