1. Move entry and ProviderInfo to shared.
2. renaming BaseEntry as open class to EntryInfo as Sealed class.
3. resolved smart cast issue introduced by splitting module: http://shortn/_OwZQl2mAo4
BUG: 313497665
Test: Manual with DeveloperTestApp.
Change-Id: I54be7effe26e7265ff853d086f3f24d450cc7e71
diff --git a/packages/CredentialManager/Android.bp b/packages/CredentialManager/Android.bp
index fe26dc3..991fe41 100644
--- a/packages/CredentialManager/Android.bp
+++ b/packages/CredentialManager/Android.bp
@@ -16,10 +16,12 @@
dex_preopt: {
profile_guided: true,
+ //TODO: b/312357299 - Update baseline profile
profile: "profile.txt.prof",
},
static_libs: [
+ "CredentialManagerShared",
"PlatformComposeCore",
"androidx.activity_activity-compose",
"androidx.appcompat_appcompat",
diff --git a/packages/CredentialManager/shared/src/com/android/credentialmanager/model/ActionEntryInfo.kt b/packages/CredentialManager/shared/src/com/android/credentialmanager/model/ActionEntryInfo.kt
new file mode 100644
index 0000000..330b522
--- /dev/null
+++ b/packages/CredentialManager/shared/src/com/android/credentialmanager/model/ActionEntryInfo.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.credentialmanager.model
+
+import android.app.PendingIntent
+import android.content.Intent
+import android.graphics.drawable.Drawable
+
+class ActionEntryInfo(
+ providerId: String,
+ entryKey: String,
+ entrySubkey: String,
+ pendingIntent: PendingIntent?,
+ fillInIntent: Intent?,
+ val title: String,
+ val icon: Drawable,
+ val subTitle: String?,
+) : EntryInfo(
+ providerId,
+ entryKey,
+ entrySubkey,
+ pendingIntent,
+ fillInIntent,
+ shouldTerminateUiUponSuccessfulProviderResult = true,
+)
\ No newline at end of file
diff --git a/packages/CredentialManager/shared/src/com/android/credentialmanager/model/AuthenticationEntryInfo.kt b/packages/CredentialManager/shared/src/com/android/credentialmanager/model/AuthenticationEntryInfo.kt
new file mode 100644
index 0000000..4772285
--- /dev/null
+++ b/packages/CredentialManager/shared/src/com/android/credentialmanager/model/AuthenticationEntryInfo.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.credentialmanager.model
+
+import android.app.PendingIntent
+import android.content.Intent
+import android.graphics.drawable.Drawable
+
+class AuthenticationEntryInfo(
+ providerId: String,
+ entryKey: String,
+ entrySubkey: String,
+ pendingIntent: PendingIntent?,
+ fillInIntent: Intent?,
+ val title: String,
+ val providerDisplayName: String,
+ val icon: Drawable,
+ // The entry had been unlocked and turned out to be empty. Used to determine whether to
+ // show "Tap to unlock" or "No sign-in info" for this entry.
+ val isUnlockedAndEmpty: Boolean,
+ // True if the entry was the last one unlocked. Used to show the no sign-in info snackbar.
+ val isLastUnlocked: Boolean,
+) : EntryInfo(
+ providerId,
+ entryKey, entrySubkey,
+ pendingIntent,
+ fillInIntent,
+ shouldTerminateUiUponSuccessfulProviderResult = false,
+)
\ No newline at end of file
diff --git a/packages/CredentialManager/shared/src/com/android/credentialmanager/model/CreateOptionInfo.kt b/packages/CredentialManager/shared/src/com/android/credentialmanager/model/CreateOptionInfo.kt
new file mode 100644
index 0000000..d1800fd
--- /dev/null
+++ b/packages/CredentialManager/shared/src/com/android/credentialmanager/model/CreateOptionInfo.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.credentialmanager.model
+
+import android.app.PendingIntent
+import android.content.Intent
+import android.graphics.drawable.Drawable
+import java.time.Instant
+
+class CreateOptionInfo(
+ providerId: String,
+ entryKey: String,
+ entrySubkey: String,
+ pendingIntent: PendingIntent?,
+ fillInIntent: Intent?,
+ val userProviderDisplayName: String,
+ val profileIcon: Drawable?,
+ val passwordCount: Int?,
+ val passkeyCount: Int?,
+ val totalCredentialCount: Int?,
+ val lastUsedTime: Instant,
+ val footerDescription: String?,
+ val allowAutoSelect: Boolean,
+) : EntryInfo(
+ providerId,
+ entryKey,
+ entrySubkey,
+ pendingIntent,
+ fillInIntent,
+ shouldTerminateUiUponSuccessfulProviderResult = true,
+)
\ No newline at end of file
diff --git a/packages/CredentialManager/shared/src/com/android/credentialmanager/model/CredentialEntryInfo.kt b/packages/CredentialManager/shared/src/com/android/credentialmanager/model/CredentialEntryInfo.kt
new file mode 100644
index 0000000..0f34aee
--- /dev/null
+++ b/packages/CredentialManager/shared/src/com/android/credentialmanager/model/CredentialEntryInfo.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.credentialmanager.model
+
+import android.app.PendingIntent
+import android.content.Intent
+import android.graphics.drawable.Drawable
+import java.time.Instant
+
+class CredentialEntryInfo(
+ providerId: String,
+ entryKey: String,
+ entrySubkey: String,
+ pendingIntent: PendingIntent?,
+ fillInIntent: Intent?,
+ /** Type of this credential used for sorting. Not localized so must not be directly displayed. */
+ val credentialType: CredentialType,
+ /** Localized type value of this credential used for display purpose. */
+ val credentialTypeDisplayName: String,
+ val providerDisplayName: String,
+ val userName: String,
+ val displayName: String?,
+ val icon: Drawable?,
+ val shouldTintIcon: Boolean,
+ val lastUsedTimeMillis: Instant?,
+ val isAutoSelectable: Boolean,
+) : EntryInfo(
+ providerId,
+ entryKey,
+ entrySubkey,
+ pendingIntent,
+ fillInIntent,
+ shouldTerminateUiUponSuccessfulProviderResult = true,
+)
\ No newline at end of file
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/CredentialType.kt b/packages/CredentialManager/shared/src/com/android/credentialmanager/model/CredentialType.kt
similarity index 93%
rename from packages/CredentialManager/src/com/android/credentialmanager/common/CredentialType.kt
rename to packages/CredentialManager/shared/src/com/android/credentialmanager/model/CredentialType.kt
index cc92f60..3f85192 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/CredentialType.kt
+++ b/packages/CredentialManager/shared/src/com/android/credentialmanager/model/CredentialType.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.credentialmanager.common
+package com.android.credentialmanager.model
enum class CredentialType {
UNKNOWN, PASSKEY, PASSWORD,
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/BaseEntry.kt b/packages/CredentialManager/shared/src/com/android/credentialmanager/model/EntryInfo.kt
similarity index 92%
rename from packages/CredentialManager/src/com/android/credentialmanager/common/BaseEntry.kt
rename to packages/CredentialManager/shared/src/com/android/credentialmanager/model/EntryInfo.kt
index ee36989..8fa0a5c 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/BaseEntry.kt
+++ b/packages/CredentialManager/shared/src/com/android/credentialmanager/model/EntryInfo.kt
@@ -14,12 +14,12 @@
* limitations under the License.
*/
-package com.android.credentialmanager.common
+package com.android.credentialmanager.model
import android.app.PendingIntent
import android.content.Intent
-open class BaseEntry (
+sealed class EntryInfo (
val providerId: String,
val entryKey: String,
val entrySubkey: String,
diff --git a/packages/CredentialManager/shared/src/com/android/credentialmanager/model/ProviderInfo.kt b/packages/CredentialManager/shared/src/com/android/credentialmanager/model/ProviderInfo.kt
new file mode 100644
index 0000000..1f52af4
--- /dev/null
+++ b/packages/CredentialManager/shared/src/com/android/credentialmanager/model/ProviderInfo.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.credentialmanager.model
+
+import android.graphics.drawable.Drawable
+
+data class ProviderInfo(
+ /**
+ * Unique id (component name) of this provider.
+ * Not for display purpose - [displayName] should be used for ui rendering.
+ */
+ val id: String,
+ val icon: Drawable,
+ val displayName: String,
+ val credentialEntryList: List<CredentialEntryInfo>,
+ val authenticationEntryList: List<AuthenticationEntryInfo>,
+ val remoteEntry: RemoteEntryInfo?,
+ val actionEntryList: List<ActionEntryInfo>,
+)
\ No newline at end of file
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/BaseEntry.kt b/packages/CredentialManager/shared/src/com/android/credentialmanager/model/RemoteEntryInfo.kt
similarity index 65%
copy from packages/CredentialManager/src/com/android/credentialmanager/common/BaseEntry.kt
copy to packages/CredentialManager/shared/src/com/android/credentialmanager/model/RemoteEntryInfo.kt
index ee36989..8dbf613 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/BaseEntry.kt
+++ b/packages/CredentialManager/shared/src/com/android/credentialmanager/model/RemoteEntryInfo.kt
@@ -14,16 +14,22 @@
* limitations under the License.
*/
-package com.android.credentialmanager.common
+package com.android.credentialmanager.model
import android.app.PendingIntent
import android.content.Intent
-open class BaseEntry (
- val providerId: String,
- val entryKey: String,
- val entrySubkey: String,
- val pendingIntent: PendingIntent?,
- val fillInIntent: Intent?,
- val shouldTerminateUiUponSuccessfulProviderResult: Boolean,
+class RemoteEntryInfo(
+ providerId: String,
+ entryKey: String,
+ entrySubkey: String,
+ pendingIntent: PendingIntent?,
+ fillInIntent: Intent?,
+) : EntryInfo(
+ providerId,
+ entryKey,
+ entrySubkey,
+ pendingIntent,
+ fillInIntent,
+ shouldTerminateUiUponSuccessfulProviderResult = true,
)
\ No newline at end of file
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/BaseEntry.kt b/packages/CredentialManager/shared/src/com/android/credentialmanager/model/RemoteInfo.kt
similarity index 65%
copy from packages/CredentialManager/src/com/android/credentialmanager/common/BaseEntry.kt
copy to packages/CredentialManager/shared/src/com/android/credentialmanager/model/RemoteInfo.kt
index ee36989..7161cb8 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/BaseEntry.kt
+++ b/packages/CredentialManager/shared/src/com/android/credentialmanager/model/RemoteInfo.kt
@@ -14,16 +14,22 @@
* limitations under the License.
*/
-package com.android.credentialmanager.common
+package com.android.credentialmanager.model
import android.app.PendingIntent
import android.content.Intent
-open class BaseEntry (
- val providerId: String,
- val entryKey: String,
- val entrySubkey: String,
- val pendingIntent: PendingIntent?,
- val fillInIntent: Intent?,
- val shouldTerminateUiUponSuccessfulProviderResult: Boolean,
+class RemoteInfo(
+ providerId: String,
+ entryKey: String,
+ entrySubkey: String,
+ pendingIntent: PendingIntent?,
+ fillInIntent: Intent?,
+) : EntryInfo(
+ providerId,
+ entryKey,
+ entrySubkey,
+ pendingIntent,
+ fillInIntent,
+ shouldTerminateUiUponSuccessfulProviderResult = true,
)
\ No newline at end of file
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt
index bce86c4..6c5a984 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt
@@ -28,7 +28,7 @@
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel
-import com.android.credentialmanager.common.BaseEntry
+import com.android.credentialmanager.model.EntryInfo
import com.android.credentialmanager.common.Constants
import com.android.credentialmanager.common.DialogState
import com.android.credentialmanager.common.ProviderActivityResult
@@ -47,7 +47,7 @@
data class UiState(
val createCredentialUiState: CreateCredentialUiState?,
val getCredentialUiState: GetCredentialUiState?,
- val selectedEntry: BaseEntry? = null,
+ val selectedEntry: EntryInfo? = null,
val providerActivityState: ProviderActivityState = ProviderActivityState.NOT_APPLICABLE,
val dialogState: DialogState = DialogState.ACTIVE,
// True if the UI has one and only one auto selectable entry. Its provider activity will be
@@ -115,12 +115,13 @@
launcher: ManagedActivityResultLauncher<IntentSenderRequest, ActivityResult>
) {
val entry = uiState.selectedEntry
- if (entry != null && entry.pendingIntent != null) {
+ val pendingIntent = entry?.pendingIntent
+ if (pendingIntent != null) {
Log.d(Constants.LOG_TAG, "Launching provider activity")
uiState = uiState.copy(providerActivityState = ProviderActivityState.PENDING)
val entryIntent = entry.fillInIntent
entryIntent?.putExtra(Constants.IS_AUTO_SELECTED_KEY, uiState.isAutoSelectFlow)
- val intentSenderRequest = IntentSenderRequest.Builder(entry.pendingIntent)
+ val intentSenderRequest = IntentSenderRequest.Builder(pendingIntent)
.setFillInIntent(entryIntent).build()
try {
launcher.launch(intentSenderRequest)
@@ -201,7 +202,7 @@
/**************************************************************************/
/***** Get Flow Callbacks *****/
/**************************************************************************/
- fun getFlowOnEntrySelected(entry: BaseEntry) {
+ fun getFlowOnEntrySelected(entry: EntryInfo) {
Log.d(Constants.LOG_TAG, "credential selected: {provider=${entry.providerId}" +
", key=${entry.entryKey}, subkey=${entry.entrySubkey}}")
uiState = if (entry.pendingIntent != null) {
@@ -363,7 +364,7 @@
)
}
- fun createFlowOnEntrySelected(selectedEntry: BaseEntry) {
+ fun createFlowOnEntrySelected(selectedEntry: EntryInfo) {
val providerId = selectedEntry.providerId
val entryKey = selectedEntry.entryKey
val entrySubkey = selectedEntry.entrySubkey
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
index f0fa6c5..ed92efe 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
@@ -32,20 +32,20 @@
import android.text.TextUtils
import android.util.Log
import com.android.credentialmanager.common.Constants
-import com.android.credentialmanager.common.CredentialType
+import com.android.credentialmanager.model.CredentialType
import com.android.credentialmanager.createflow.ActiveEntry
import com.android.credentialmanager.createflow.CreateCredentialUiState
-import com.android.credentialmanager.createflow.CreateOptionInfo
+import com.android.credentialmanager.model.CreateOptionInfo
import com.android.credentialmanager.createflow.CreateScreenState
import com.android.credentialmanager.createflow.DisabledProviderInfo
import com.android.credentialmanager.createflow.EnabledProviderInfo
-import com.android.credentialmanager.createflow.RemoteInfo
+import com.android.credentialmanager.model.RemoteInfo
import com.android.credentialmanager.createflow.RequestDisplayInfo
-import com.android.credentialmanager.getflow.ActionEntryInfo
-import com.android.credentialmanager.getflow.AuthenticationEntryInfo
-import com.android.credentialmanager.getflow.CredentialEntryInfo
-import com.android.credentialmanager.getflow.ProviderInfo
-import com.android.credentialmanager.getflow.RemoteEntryInfo
+import com.android.credentialmanager.model.ActionEntryInfo
+import com.android.credentialmanager.model.AuthenticationEntryInfo
+import com.android.credentialmanager.model.CredentialEntryInfo
+import com.android.credentialmanager.model.ProviderInfo
+import com.android.credentialmanager.model.RemoteEntryInfo
import com.android.credentialmanager.getflow.TopBrandingContent
import androidx.credentials.CreateCredentialRequest
import androidx.credentials.CreateCustomCredentialRequest
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt b/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
index 281696d..a991294 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
@@ -48,9 +48,9 @@
import androidx.credentials.provider.PasswordCredentialEntry
import androidx.credentials.provider.PublicKeyCredentialEntry
import com.android.credentialmanager.GetFlowUtils
-import com.android.credentialmanager.getflow.CredentialEntryInfo
+import com.android.credentialmanager.model.CredentialEntryInfo
import com.android.credentialmanager.getflow.ProviderDisplayInfo
-import com.android.credentialmanager.getflow.ProviderInfo
+import com.android.credentialmanager.model.ProviderInfo
import com.android.credentialmanager.getflow.toProviderDisplayInfo
import org.json.JSONObject
import java.util.concurrent.Executors
@@ -200,7 +200,8 @@
providerDisplayInfo.sortedUserNameToCredentialEntryList.forEach usernameLoop@ {
val primaryEntry = it.sortedCredentialEntryList.first()
val pendingIntent = primaryEntry.pendingIntent
- if (pendingIntent == null || primaryEntry.fillInIntent == null) {
+ val fillInIntent = primaryEntry.fillInIntent
+ if (pendingIntent == null || fillInIntent == null) {
// FillInIntent will not be null because autofillId was retrieved from it.
Log.e(TAG, "PendingIntent was missing from the entry.")
return@usernameLoop
@@ -245,7 +246,7 @@
presentationBuilder.build())
.build())
.setAuthentication(pendingIntent.intentSender)
- .setAuthenticationExtras(primaryEntry.fillInIntent.extras)
+ .setAuthenticationExtras(fillInIntent.extras)
.build())
datasetAdded = true
}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
index d45b6f6..c3a4db6 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
@@ -48,8 +48,8 @@
import androidx.core.graphics.drawable.toBitmap
import com.android.credentialmanager.CredentialSelectorViewModel
import com.android.credentialmanager.R
-import com.android.credentialmanager.common.BaseEntry
-import com.android.credentialmanager.common.CredentialType
+import com.android.credentialmanager.model.EntryInfo
+import com.android.credentialmanager.model.CredentialType
import com.android.credentialmanager.common.ProviderActivityState
import com.android.credentialmanager.common.material.ModalBottomSheetDefaults
import com.android.credentialmanager.common.ui.ActionButton
@@ -68,6 +68,8 @@
import com.android.credentialmanager.common.ui.PasskeyBenefitRow
import com.android.credentialmanager.common.ui.HeadlineText
import com.android.credentialmanager.logging.CreateCredentialEvent
+import com.android.credentialmanager.model.CreateOptionInfo
+import com.android.credentialmanager.model.RemoteInfo
import com.android.credentialmanager.ui.theme.LocalAndroidColorScheme
import com.android.internal.logging.UiEventLogger.UiEventEnum
@@ -259,15 +261,15 @@
@Composable
fun MoreOptionsSelectionCard(
- requestDisplayInfo: RequestDisplayInfo,
- enabledProviderList: List<EnabledProviderInfo>,
- disabledProviderList: List<DisabledProviderInfo>?,
- sortedCreateOptionsPairs: List<Pair<CreateOptionInfo, EnabledProviderInfo>>,
- onBackCreationSelectionButtonSelected: () -> Unit,
- onOptionSelected: (ActiveEntry) -> Unit,
- onDisabledProvidersSelected: () -> Unit,
- onRemoteEntrySelected: (BaseEntry) -> Unit,
- onLog: @Composable (UiEventEnum) -> Unit,
+ requestDisplayInfo: RequestDisplayInfo,
+ enabledProviderList: List<EnabledProviderInfo>,
+ disabledProviderList: List<DisabledProviderInfo>?,
+ sortedCreateOptionsPairs: List<Pair<CreateOptionInfo, EnabledProviderInfo>>,
+ onBackCreationSelectionButtonSelected: () -> Unit,
+ onOptionSelected: (ActiveEntry) -> Unit,
+ onDisabledProvidersSelected: () -> Unit,
+ onRemoteEntrySelected: (EntryInfo) -> Unit,
+ onLog: @Composable (UiEventEnum) -> Unit,
) {
SheetContainerCard(topAppBar = {
MoreOptionTopAppBar(
@@ -378,14 +380,14 @@
@Composable
fun CreationSelectionCard(
- requestDisplayInfo: RequestDisplayInfo,
- enabledProviderList: List<EnabledProviderInfo>,
- providerInfo: EnabledProviderInfo,
- createOptionInfo: CreateOptionInfo,
- onOptionSelected: (BaseEntry) -> Unit,
- onConfirm: () -> Unit,
- onMoreOptionsSelected: () -> Unit,
- onLog: @Composable (UiEventEnum) -> Unit,
+ requestDisplayInfo: RequestDisplayInfo,
+ enabledProviderList: List<EnabledProviderInfo>,
+ providerInfo: EnabledProviderInfo,
+ createOptionInfo: CreateOptionInfo,
+ onOptionSelected: (EntryInfo) -> Unit,
+ onConfirm: () -> Unit,
+ onMoreOptionsSelected: () -> Unit,
+ onLog: @Composable (UiEventEnum) -> Unit,
) {
SheetContainerCard {
item {
@@ -474,11 +476,11 @@
@Composable
fun ExternalOnlySelectionCard(
- requestDisplayInfo: RequestDisplayInfo,
- activeRemoteEntry: BaseEntry,
- onOptionSelected: (BaseEntry) -> Unit,
- onConfirm: () -> Unit,
- onLog: @Composable (UiEventEnum) -> Unit,
+ requestDisplayInfo: RequestDisplayInfo,
+ activeRemoteEntry: EntryInfo,
+ onOptionSelected: (EntryInfo) -> Unit,
+ onConfirm: () -> Unit,
+ onLog: @Composable (UiEventEnum) -> Unit,
) {
SheetContainerCard {
item { HeadlineIcon(imageVector = Icons.Outlined.QrCodeScanner) }
@@ -575,17 +577,14 @@
@Composable
fun PrimaryCreateOptionRow(
requestDisplayInfo: RequestDisplayInfo,
- entryInfo: BaseEntry,
- onOptionSelected: (BaseEntry) -> Unit
+ entryInfo: EntryInfo,
+ onOptionSelected: (EntryInfo) -> Unit
) {
Entry(
onClick = { onOptionSelected(entryInfo) },
- iconImageBitmap =
- if (entryInfo is CreateOptionInfo && entryInfo.profileIcon != null) {
- entryInfo.profileIcon.toBitmap().asImageBitmap()
- } else {
- requestDisplayInfo.typeIcon.toBitmap().asImageBitmap()
- },
+ iconImageBitmap = ((entryInfo as? CreateOptionInfo)?.profileIcon
+ ?: requestDisplayInfo.typeIcon)
+ .toBitmap().asImageBitmap(),
shouldApplyIconImageBitmapTint = !(entryInfo is CreateOptionInfo &&
entryInfo.profileIcon != null),
entryHeadlineText = requestDisplayInfo.title,
@@ -627,32 +626,33 @@
entryThirdLineText =
if (requestDisplayInfo.type == CredentialType.PASSKEY ||
requestDisplayInfo.type == CredentialType.PASSWORD) {
- if (createOptionInfo.passwordCount != null &&
- createOptionInfo.passkeyCount != null
- ) {
+ val passwordCount = createOptionInfo.passwordCount
+ val passkeyCount = createOptionInfo.passkeyCount
+ if (passwordCount != null && passkeyCount != null) {
stringResource(
R.string.more_options_usage_passwords_passkeys,
- createOptionInfo.passwordCount,
- createOptionInfo.passkeyCount
+ passwordCount,
+ passkeyCount
)
- } else if (createOptionInfo.passwordCount != null) {
+ } else if (passwordCount != null) {
stringResource(
R.string.more_options_usage_passwords,
- createOptionInfo.passwordCount
+ passwordCount
)
- } else if (createOptionInfo.passkeyCount != null) {
+ } else if (passkeyCount != null) {
stringResource(
R.string.more_options_usage_passkeys,
- createOptionInfo.passkeyCount
+ passkeyCount
)
} else {
null
}
} else {
- if (createOptionInfo.totalCredentialCount != null) {
+ val totalCredentialCount = createOptionInfo.totalCredentialCount
+ if (totalCredentialCount != null) {
stringResource(
R.string.more_options_usage_credentials,
- createOptionInfo.totalCredentialCount
+ totalCredentialCount
)
} else {
null
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt
index e9e8c2e..57de33a 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt
@@ -16,12 +16,11 @@
package com.android.credentialmanager.createflow
-import android.app.PendingIntent
-import android.content.Intent
import android.graphics.drawable.Drawable
-import com.android.credentialmanager.common.BaseEntry
-import com.android.credentialmanager.common.CredentialType
-import java.time.Instant
+import com.android.credentialmanager.model.EntryInfo
+import com.android.credentialmanager.model.CredentialType
+import com.android.credentialmanager.model.CreateOptionInfo
+import com.android.credentialmanager.model.RemoteInfo
data class CreateCredentialUiState(
val enabledProviders: List<EnabledProviderInfo>,
@@ -75,44 +74,6 @@
displayName: String,
) : ProviderInfo(icon, id, displayName)
-class CreateOptionInfo(
- providerId: String,
- entryKey: String,
- entrySubkey: String,
- pendingIntent: PendingIntent?,
- fillInIntent: Intent?,
- val userProviderDisplayName: String,
- val profileIcon: Drawable?,
- val passwordCount: Int?,
- val passkeyCount: Int?,
- val totalCredentialCount: Int?,
- val lastUsedTime: Instant,
- val footerDescription: String?,
- val allowAutoSelect: Boolean,
-) : BaseEntry(
- providerId,
- entryKey,
- entrySubkey,
- pendingIntent,
- fillInIntent,
- shouldTerminateUiUponSuccessfulProviderResult = true,
-)
-
-class RemoteInfo(
- providerId: String,
- entryKey: String,
- entrySubkey: String,
- pendingIntent: PendingIntent?,
- fillInIntent: Intent?,
-) : BaseEntry(
- providerId,
- entryKey,
- entrySubkey,
- pendingIntent,
- fillInIntent,
- shouldTerminateUiUponSuccessfulProviderResult = true,
-)
-
data class RequestDisplayInfo(
val title: String,
val subtitle: String?,
@@ -131,8 +92,8 @@
* user selects a different entry on the more option page.
*/
data class ActiveEntry (
- val activeProvider: EnabledProviderInfo,
- val activeEntryInfo: BaseEntry,
+ val activeProvider: EnabledProviderInfo,
+ val activeEntryInfo: EntryInfo,
)
/** The name of the current screen. */
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt
index 72d030b..0c89639 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt
@@ -48,8 +48,9 @@
import androidx.core.graphics.drawable.toBitmap
import com.android.credentialmanager.CredentialSelectorViewModel
import com.android.credentialmanager.R
-import com.android.credentialmanager.common.BaseEntry
-import com.android.credentialmanager.common.CredentialType
+import com.android.credentialmanager.model.EntryInfo
+import com.android.credentialmanager.model.CredentialType
+import com.android.credentialmanager.model.ProviderInfo
import com.android.credentialmanager.common.ProviderActivityState
import com.android.credentialmanager.common.material.ModalBottomSheetDefaults
import com.android.credentialmanager.common.ui.ActionButton
@@ -68,6 +69,10 @@
import com.android.credentialmanager.common.ui.LargeLabelTextOnSurfaceVariant
import com.android.credentialmanager.common.ui.Snackbar
import com.android.credentialmanager.logging.GetCredentialEvent
+import com.android.credentialmanager.model.ActionEntryInfo
+import com.android.credentialmanager.model.AuthenticationEntryInfo
+import com.android.credentialmanager.model.CredentialEntryInfo
+import com.android.credentialmanager.model.RemoteEntryInfo
import com.android.credentialmanager.userAndDisplayNameForPasskey
import com.android.internal.logging.UiEventLogger.UiEventEnum
@@ -175,8 +180,8 @@
requestDisplayInfo: RequestDisplayInfo,
providerDisplayInfo: ProviderDisplayInfo,
providerInfoList: List<ProviderInfo>,
- activeEntry: BaseEntry?,
- onEntrySelected: (BaseEntry) -> Unit,
+ activeEntry: EntryInfo?,
+ onEntrySelected: (EntryInfo) -> Unit,
onConfirm: () -> Unit,
onMoreOptionSelected: () -> Unit,
onLog: @Composable (UiEventEnum) -> Unit,
@@ -358,7 +363,7 @@
fun AllSignInOptionCard(
providerInfoList: List<ProviderInfo>,
providerDisplayInfo: ProviderDisplayInfo,
- onEntrySelected: (BaseEntry) -> Unit,
+ onEntrySelected: (EntryInfo) -> Unit,
onBackButtonClicked: () -> Unit,
onCancel: () -> Unit,
onLog: @Composable (UiEventEnum) -> Unit,
@@ -436,7 +441,7 @@
@Composable
fun ActionChips(
providerInfoList: List<ProviderInfo>,
- onEntrySelected: (BaseEntry) -> Unit,
+ onEntrySelected: (EntryInfo) -> Unit,
isFirstSection: Boolean,
) {
val actionChips = providerInfoList.flatMap { it.actionEntryList }
@@ -460,7 +465,7 @@
@Composable
fun RemoteEntryCard(
remoteEntry: RemoteEntryInfo,
- onEntrySelected: (BaseEntry) -> Unit,
+ onEntrySelected: (EntryInfo) -> Unit,
isFirstSection: Boolean,
) {
CredentialListSectionHeader(
@@ -486,7 +491,7 @@
@Composable
fun LockedCredentials(
authenticationEntryList: List<AuthenticationEntryInfo>,
- onEntrySelected: (BaseEntry) -> Unit,
+ onEntrySelected: (EntryInfo) -> Unit,
isFirstSection: Boolean,
) {
CredentialListSectionHeader(
@@ -508,7 +513,7 @@
@Composable
fun PerUserNameCredentials(
perUserNameCredentialEntryList: PerUserNameCredentialEntryList,
- onEntrySelected: (BaseEntry) -> Unit,
+ onEntrySelected: (EntryInfo) -> Unit,
isFirstSection: Boolean,
) {
CredentialListSectionHeader(
@@ -532,7 +537,7 @@
@Composable
fun CredentialEntryRow(
credentialEntryInfo: CredentialEntryInfo,
- onEntrySelected: (BaseEntry) -> Unit,
+ onEntrySelected: (EntryInfo) -> Unit,
enforceOneLine: Boolean = false,
onTextLayout: (TextLayoutResult) -> Unit = {},
) {
@@ -571,7 +576,7 @@
@Composable
fun AuthenticationEntryRow(
authenticationEntryInfo: AuthenticationEntryInfo,
- onEntrySelected: (BaseEntry) -> Unit,
+ onEntrySelected: (EntryInfo) -> Unit,
enforceOneLine: Boolean = false,
) {
Entry(
@@ -596,7 +601,7 @@
@Composable
fun ActionEntryRow(
actionEntryInfo: ActionEntryInfo,
- onEntrySelected: (BaseEntry) -> Unit,
+ onEntrySelected: (EntryInfo) -> Unit,
) {
ActionEntry(
iconImageBitmap = actionEntryInfo.icon.toBitmap().asImageBitmap(),
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt
index 447a9d2..cf28a56 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt
@@ -16,21 +16,21 @@
package com.android.credentialmanager.getflow
-import android.app.PendingIntent
-import android.content.Intent
import android.graphics.drawable.Drawable
-import com.android.credentialmanager.common.BaseEntry
-import com.android.credentialmanager.common.CredentialType
+import com.android.credentialmanager.model.ProviderInfo
+import com.android.credentialmanager.model.EntryInfo
+import com.android.credentialmanager.model.CredentialType
+import com.android.credentialmanager.model.AuthenticationEntryInfo
+import com.android.credentialmanager.model.CredentialEntryInfo
+import com.android.credentialmanager.model.RemoteEntryInfo
import com.android.internal.util.Preconditions
-import java.time.Instant
-
data class GetCredentialUiState(
val providerInfoList: List<ProviderInfo>,
val requestDisplayInfo: RequestDisplayInfo,
val providerDisplayInfo: ProviderDisplayInfo = toProviderDisplayInfo(providerInfoList),
val currentScreenState: GetScreenState = toGetScreenState(providerDisplayInfo),
- val activeEntry: BaseEntry? = toActiveEntry(providerDisplayInfo),
+ val activeEntry: EntryInfo? = toActiveEntry(providerDisplayInfo),
val isNoAccount: Boolean = false,
)
@@ -58,20 +58,6 @@
return null
}
-data class ProviderInfo(
- /**
- * Unique id (component name) of this provider.
- * Not for display purpose - [displayName] should be used for ui rendering.
- */
- val id: String,
- val icon: Drawable,
- val displayName: String,
- val credentialEntryList: List<CredentialEntryInfo>,
- val authenticationEntryList: List<AuthenticationEntryInfo>,
- val remoteEntry: RemoteEntryInfo?,
- val actionEntryList: List<ActionEntryInfo>,
-)
-
/** Display-centric data structure derived from the [ProviderInfo]. This abstraction is not grouping
* by the provider id but instead focuses on structures convenient for display purposes. */
data class ProviderDisplayInfo(
@@ -84,87 +70,6 @@
val remoteEntry: RemoteEntryInfo?
)
-class CredentialEntryInfo(
- providerId: String,
- entryKey: String,
- entrySubkey: String,
- pendingIntent: PendingIntent?,
- fillInIntent: Intent?,
- /** Type of this credential used for sorting. Not localized so must not be directly displayed. */
- val credentialType: CredentialType,
- /** Localized type value of this credential used for display purpose. */
- val credentialTypeDisplayName: String,
- val providerDisplayName: String,
- val userName: String,
- val displayName: String?,
- val icon: Drawable?,
- val shouldTintIcon: Boolean,
- val lastUsedTimeMillis: Instant?,
- val isAutoSelectable: Boolean,
-) : BaseEntry(
- providerId,
- entryKey,
- entrySubkey,
- pendingIntent,
- fillInIntent,
- shouldTerminateUiUponSuccessfulProviderResult = true,
-)
-
-class AuthenticationEntryInfo(
- providerId: String,
- entryKey: String,
- entrySubkey: String,
- pendingIntent: PendingIntent?,
- fillInIntent: Intent?,
- val title: String,
- val providerDisplayName: String,
- val icon: Drawable,
- // The entry had been unlocked and turned out to be empty. Used to determine whether to
- // show "Tap to unlock" or "No sign-in info" for this entry.
- val isUnlockedAndEmpty: Boolean,
- // True if the entry was the last one unlocked. Used to show the no sign-in info snackbar.
- val isLastUnlocked: Boolean,
-) : BaseEntry(
- providerId,
- entryKey, entrySubkey,
- pendingIntent,
- fillInIntent,
- shouldTerminateUiUponSuccessfulProviderResult = false,
-)
-
-class RemoteEntryInfo(
- providerId: String,
- entryKey: String,
- entrySubkey: String,
- pendingIntent: PendingIntent?,
- fillInIntent: Intent?,
-) : BaseEntry(
- providerId,
- entryKey,
- entrySubkey,
- pendingIntent,
- fillInIntent,
- shouldTerminateUiUponSuccessfulProviderResult = true,
-)
-
-class ActionEntryInfo(
- providerId: String,
- entryKey: String,
- entrySubkey: String,
- pendingIntent: PendingIntent?,
- fillInIntent: Intent?,
- val title: String,
- val icon: Drawable,
- val subTitle: String?,
-) : BaseEntry(
- providerId,
- entryKey,
- entrySubkey,
- pendingIntent,
- fillInIntent,
- shouldTerminateUiUponSuccessfulProviderResult = true,
-)
-
data class RequestDisplayInfo(
val appName: String,
val preferImmediatelyAvailableCredentials: Boolean,
@@ -218,8 +123,8 @@
val remoteEntryList = mutableListOf<RemoteEntryInfo>()
providerInfoList.forEach { providerInfo ->
authenticationEntryList.addAll(providerInfo.authenticationEntryList)
- if (providerInfo.remoteEntry != null) {
- remoteEntryList.add(providerInfo.remoteEntry)
+ providerInfo.remoteEntry?.let {
+ remoteEntryList.add(it)
}
// There can only be at most one remote entry
Preconditions.checkState(remoteEntryList.size <= 1)
@@ -260,11 +165,11 @@
private fun toActiveEntry(
providerDisplayInfo: ProviderDisplayInfo,
-): BaseEntry? {
+): EntryInfo? {
val sortedUserNameToCredentialEntryList =
providerDisplayInfo.sortedUserNameToCredentialEntryList
val authenticationEntryList = providerDisplayInfo.authenticationEntryList
- var activeEntry: BaseEntry? = null
+ var activeEntry: EntryInfo? = null
if (sortedUserNameToCredentialEntryList
.size == 1 && authenticationEntryList.isEmpty()
) {
@@ -302,17 +207,18 @@
return 1
}
}
-
+ val p0LastUsedTimeMillis = p0.lastUsedTimeMillis
+ val p1LastUsedTimeMillis = p1.lastUsedTimeMillis
// Then order by last used timestamp
- if (p0.lastUsedTimeMillis != null && p1.lastUsedTimeMillis != null) {
- if (p0.lastUsedTimeMillis < p1.lastUsedTimeMillis) {
+ if (p0LastUsedTimeMillis != null && p1LastUsedTimeMillis != null) {
+ if (p0LastUsedTimeMillis < p1LastUsedTimeMillis) {
return 1
- } else if (p0.lastUsedTimeMillis > p1.lastUsedTimeMillis) {
+ } else if (p0LastUsedTimeMillis > p1LastUsedTimeMillis) {
return -1
}
- } else if (p0.lastUsedTimeMillis != null) {
+ } else if (p0LastUsedTimeMillis != null) {
return -1
- } else if (p1.lastUsedTimeMillis != null) {
+ } else if (p1LastUsedTimeMillis != null) {
return 1
}
return 0