Merge "Change the entry id to key + subkey."
This commit is contained in:
@@ -82,32 +82,46 @@ public class Entry implements Parcelable {
|
||||
public static final String EXTRA_ENTRY_AUTHENTICATION_ACTION =
|
||||
"android.credentials.ui.extra.ENTRY_AUTHENTICATION_ACTION";
|
||||
|
||||
// TODO: change to string key + string subkey.
|
||||
private final int mId;
|
||||
@NonNull private final String mKey;
|
||||
@NonNull private final String mSubkey;
|
||||
|
||||
@NonNull
|
||||
private final Slice mSlice;
|
||||
|
||||
protected Entry(@NonNull Parcel in) {
|
||||
int entryId = in.readInt();
|
||||
String key = in.readString8();
|
||||
String subkey = in.readString8();
|
||||
Slice slice = Slice.CREATOR.createFromParcel(in);
|
||||
|
||||
mId = entryId;
|
||||
mKey = key;
|
||||
AnnotationValidations.validate(NonNull.class, null, mKey);
|
||||
mSubkey = subkey;
|
||||
AnnotationValidations.validate(NonNull.class, null, mSubkey);
|
||||
mSlice = slice;
|
||||
AnnotationValidations.validate(NonNull.class, null, mSlice);
|
||||
}
|
||||
|
||||
public Entry(int id, @NonNull Slice slice) {
|
||||
mId = id;
|
||||
public Entry(@NonNull String key, @NonNull String subkey, @NonNull Slice slice) {
|
||||
mKey = key;
|
||||
mSubkey = subkey;
|
||||
mSlice = slice;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the id of this entry that's unique within the context of the CredentialManager
|
||||
* Returns the identifier of this entry that's unique within the context of the CredentialManager
|
||||
* request.
|
||||
*/
|
||||
public int getEntryId() {
|
||||
return mId;
|
||||
@NonNull
|
||||
public String getKey() {
|
||||
return mKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the sub-identifier of this entry that's unique within the context of the {@code key}.
|
||||
*/
|
||||
@NonNull
|
||||
public String getSubkey() {
|
||||
return mSubkey;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -120,7 +134,8 @@ public class Entry implements Parcelable {
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeInt(mId);
|
||||
dest.writeString8(mKey);
|
||||
dest.writeString8(mSubkey);
|
||||
mSlice.writeToParcel(dest, flags);
|
||||
}
|
||||
|
||||
|
||||
@@ -54,18 +54,17 @@ public class UserSelectionDialogResult extends BaseDialogResult implements Parce
|
||||
private static final String EXTRA_USER_SELECTION_RESULT =
|
||||
"android.credentials.ui.extra.USER_SELECTION_RESULT";
|
||||
|
||||
@NonNull
|
||||
private final String mProviderId;
|
||||
|
||||
// TODO: consider switching to string or other types, depending on the service implementation.
|
||||
private final int mEntryId;
|
||||
@NonNull private final String mProviderId;
|
||||
@NonNull private final String mEntryKey;
|
||||
@NonNull private final String mEntrySubkey;
|
||||
|
||||
public UserSelectionDialogResult(
|
||||
@NonNull IBinder requestToken, @NonNull String providerId,
|
||||
int entryId) {
|
||||
@NonNull String entryKey, @NonNull String entrySubkey) {
|
||||
super(requestToken);
|
||||
mProviderId = providerId;
|
||||
mEntryId = entryId;
|
||||
mEntryKey = entryKey;
|
||||
mEntrySubkey = entrySubkey;
|
||||
}
|
||||
|
||||
/** Returns provider package name whose entry was selected by the user. */
|
||||
@@ -74,26 +73,38 @@ public class UserSelectionDialogResult extends BaseDialogResult implements Parce
|
||||
return mProviderId;
|
||||
}
|
||||
|
||||
/** Returns the id of the visual entry that the user selected. */
|
||||
public int getEntryId() {
|
||||
return mEntryId;
|
||||
/** Returns the key of the visual entry that the user selected. */
|
||||
@NonNull
|
||||
public String getEntryKey() {
|
||||
return mEntryKey;
|
||||
}
|
||||
|
||||
/** Returns the subkey of the visual entry that the user selected. */
|
||||
@NonNull
|
||||
public String getEntrySubkey() {
|
||||
return mEntrySubkey;
|
||||
}
|
||||
|
||||
protected UserSelectionDialogResult(@NonNull Parcel in) {
|
||||
super(in);
|
||||
String providerId = in.readString8();
|
||||
int entryId = in.readInt();
|
||||
String entryKey = in.readString8();
|
||||
String entrySubkey = in.readString8();
|
||||
|
||||
mProviderId = providerId;
|
||||
AnnotationValidations.validate(NonNull.class, null, mProviderId);
|
||||
mEntryId = entryId;
|
||||
mEntryKey = entryKey;
|
||||
AnnotationValidations.validate(NonNull.class, null, mEntryKey);
|
||||
mEntrySubkey = entrySubkey;
|
||||
AnnotationValidations.validate(NonNull.class, null, mEntrySubkey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
super.writeToParcel(dest, flags);
|
||||
dest.writeString8(mProviderId);
|
||||
dest.writeInt(mEntryId);
|
||||
dest.writeString8(mEntryKey);
|
||||
dest.writeString8(mEntrySubkey);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -71,11 +71,12 @@ class CredentialManagerRepo(
|
||||
resultReceiver?.send(BaseDialogResult.RESULT_CODE_DIALOG_CANCELED, resultData)
|
||||
}
|
||||
|
||||
fun onOptionSelected(providerPackageName: String, entryId: Int) {
|
||||
fun onOptionSelected(providerPackageName: String, entryKey: String, entrySubkey: String) {
|
||||
val userSelectionDialogResult = UserSelectionDialogResult(
|
||||
requestInfo.token,
|
||||
providerPackageName,
|
||||
entryId
|
||||
entryKey,
|
||||
entrySubkey
|
||||
)
|
||||
val resultData = Bundle()
|
||||
UserSelectionDialogResult.addToBundle(userSelectionDialogResult, resultData)
|
||||
@@ -137,16 +138,16 @@ class CredentialManagerRepo(
|
||||
Icon.createWithResource(context, R.drawable.ic_launcher_foreground))
|
||||
.setCredentialEntries(
|
||||
listOf<Entry>(
|
||||
newEntry(1, "elisa.beckett@gmail.com", "Elisa Backett",
|
||||
"20 passwords and 7 passkeys saved"),
|
||||
newEntry(2, "elisa.work@google.com", "Elisa Backett Work",
|
||||
"20 passwords and 7 passkeys saved"),
|
||||
newEntry("key1", "subkey-1", "elisa.beckett@gmail.com",
|
||||
"Elisa Backett", "20 passwords and 7 passkeys saved"),
|
||||
newEntry("key1", "subkey-2", "elisa.work@google.com",
|
||||
"Elisa Backett Work", "20 passwords and 7 passkeys saved"),
|
||||
)
|
||||
).setActionChips(
|
||||
listOf<Entry>(
|
||||
newEntry(3, "Go to Settings", "",
|
||||
newEntry("key2", "subkey-1", "Go to Settings", "",
|
||||
"20 passwords and 7 passkeys saved"),
|
||||
newEntry(4, "Switch Account", "",
|
||||
newEntry("key2", "subkey-2", "Switch Account", "",
|
||||
"20 passwords and 7 passkeys saved"),
|
||||
),
|
||||
).build(),
|
||||
@@ -156,21 +157,28 @@ class CredentialManagerRepo(
|
||||
Icon.createWithResource(context, R.drawable.ic_launcher_foreground))
|
||||
.setCredentialEntries(
|
||||
listOf<Entry>(
|
||||
newEntry(1, "elisa.beckett@dashlane.com", "Elisa Backett",
|
||||
"20 passwords and 7 passkeys saved"),
|
||||
newEntry(2, "elisa.work@dashlane.com", "Elisa Backett Work",
|
||||
"20 passwords and 7 passkeys saved"),
|
||||
newEntry("key1", "subkey-3", "elisa.beckett@dashlane.com",
|
||||
"Elisa Backett", "20 passwords and 7 passkeys saved"),
|
||||
newEntry("key1", "subkey-4", "elisa.work@dashlane.com",
|
||||
"Elisa Backett Work", "20 passwords and 7 passkeys saved"),
|
||||
)
|
||||
).setActionChips(
|
||||
listOf<Entry>(
|
||||
newEntry(3, "Manage Accounts", "Manage your accounts in the dashlane app",
|
||||
newEntry("key2", "subkey-3", "Manage Accounts",
|
||||
"Manage your accounts in the dashlane app",
|
||||
"20 passwords and 7 passkeys saved"),
|
||||
),
|
||||
).build(),
|
||||
)
|
||||
}
|
||||
|
||||
private fun newEntry(id: Int, title: String, subtitle: String, usageData: String): Entry {
|
||||
private fun newEntry(
|
||||
key: String,
|
||||
subkey: String,
|
||||
title: String,
|
||||
subtitle: String,
|
||||
usageData: String
|
||||
): Entry {
|
||||
val slice = Slice.Builder(
|
||||
Entry.CREDENTIAL_MANAGER_ENTRY_URI, SliceSpec(Entry.VERSION, 1)
|
||||
)
|
||||
@@ -183,7 +191,8 @@ class CredentialManagerRepo(
|
||||
.addText(usageData, Slice.SUBTYPE_MESSAGE, listOf(Entry.HINT_SUBTITLE))
|
||||
.build()
|
||||
return Entry(
|
||||
id,
|
||||
key,
|
||||
subkey,
|
||||
slice
|
||||
)
|
||||
}
|
||||
|
||||
@@ -59,7 +59,8 @@ class GetFlowUtils {
|
||||
?: context.getDrawable(R.drawable.ic_passkey)!!,
|
||||
title = credentialEntryUi.userName.toString(),
|
||||
subtitle = credentialEntryUi.displayName?.toString() ?: "Unknown display name",
|
||||
id = it.entryId,
|
||||
entryKey = it.key,
|
||||
entrySubkey = it.subkey,
|
||||
usageData = credentialEntryUi.usageData?.toString() ?: "Unknown usageData",
|
||||
)
|
||||
}
|
||||
@@ -99,7 +100,8 @@ class CreateFlowUtils {
|
||||
?: context.getDrawable(R.drawable.ic_passkey)!!,
|
||||
title = saveEntryUi.title.toString(),
|
||||
subtitle = saveEntryUi.subTitle?.toString() ?: "Unknown subtitle",
|
||||
id = it.entryId,
|
||||
entryKey = it.key,
|
||||
entrySubkey = it.subkey,
|
||||
usageData = saveEntryUi.usageData?.toString() ?: "Unknown usageData",
|
||||
)
|
||||
}
|
||||
|
||||
@@ -30,7 +30,8 @@ data class CreateOptionInfo(
|
||||
val icon: Drawable,
|
||||
val title: String,
|
||||
val subtitle: String,
|
||||
val id: Int,
|
||||
val entryKey: String,
|
||||
val entrySubkey: String,
|
||||
val usageData: String
|
||||
)
|
||||
|
||||
|
||||
@@ -63,32 +63,32 @@ fun CreatePasskeyScreen(
|
||||
val uiState = viewModel.uiState
|
||||
when (uiState.currentScreenState) {
|
||||
CreateScreenState.PASSKEY_INTRO -> ConfirmationCard(
|
||||
onConfirm = {viewModel.onConfirmIntro()},
|
||||
onCancel = {viewModel.onCancel()},
|
||||
onConfirm = viewModel::onConfirmIntro,
|
||||
onCancel = viewModel::onCancel,
|
||||
)
|
||||
CreateScreenState.PROVIDER_SELECTION -> ProviderSelectionCard(
|
||||
providerList = uiState.providers,
|
||||
onCancel = {viewModel.onCancel()},
|
||||
onProviderSelected = {viewModel.onProviderSelected(it)}
|
||||
onCancel = viewModel::onCancel,
|
||||
onProviderSelected = viewModel::onProviderSelected
|
||||
)
|
||||
CreateScreenState.CREATION_OPTION_SELECTION -> CreationSelectionCard(
|
||||
requestDisplayInfo = uiState.requestDisplayInfo,
|
||||
providerInfo = uiState.activeEntry?.activeProvider!!,
|
||||
createOptionInfo = uiState.activeEntry.activeCreateOptionInfo,
|
||||
onOptionSelected = {viewModel.onPrimaryCreateOptionInfoSelected()},
|
||||
onConfirm = {viewModel.onPrimaryCreateOptionInfoSelected()},
|
||||
onCancel = {viewModel.onCancel()},
|
||||
onOptionSelected = viewModel::onPrimaryCreateOptionInfoSelected,
|
||||
onConfirm = viewModel::onPrimaryCreateOptionInfoSelected,
|
||||
onCancel = viewModel::onCancel,
|
||||
multiProvider = uiState.providers.size > 1,
|
||||
onMoreOptionsSelected = {viewModel.onMoreOptionsSelected()}
|
||||
onMoreOptionsSelected = viewModel::onMoreOptionsSelected
|
||||
)
|
||||
CreateScreenState.MORE_OPTIONS_SELECTION -> MoreOptionsSelectionCard(
|
||||
providerList = uiState.providers,
|
||||
onBackButtonSelected = {viewModel.onBackButtonSelected()},
|
||||
onOptionSelected = {viewModel.onMoreOptionsRowSelected(it)}
|
||||
onBackButtonSelected = viewModel::onBackButtonSelected,
|
||||
onOptionSelected = viewModel::onMoreOptionsRowSelected
|
||||
)
|
||||
CreateScreenState.MORE_OPTIONS_ROW_INTRO -> MoreOptionsRowIntroCard(
|
||||
providerInfo = uiState.activeEntry?.activeProvider!!,
|
||||
onDefaultOrNotSelected = {viewModel.onDefaultOrNotSelected()}
|
||||
onDefaultOrNotSelected = viewModel::onDefaultOrNotSelected
|
||||
)
|
||||
}
|
||||
},
|
||||
@@ -491,40 +491,6 @@ fun CreationSelectionCard(
|
||||
}
|
||||
}
|
||||
|
||||
@ExperimentalMaterialApi
|
||||
@Composable
|
||||
fun CreateOptionRow(createOptionInfo: CreateOptionInfo, onOptionSelected: (Int) -> Unit) {
|
||||
Chip(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
onClick = {onOptionSelected(createOptionInfo.id)},
|
||||
leadingIcon = {
|
||||
Image(modifier = Modifier.size(24.dp, 24.dp).padding(start = 10.dp),
|
||||
bitmap = createOptionInfo.icon.toBitmap().asImageBitmap(),
|
||||
// painter = painterResource(R.drawable.ic_passkey),
|
||||
// TODO: add description.
|
||||
contentDescription = "")
|
||||
},
|
||||
colors = ChipDefaults.chipColors(
|
||||
backgroundColor = Grey100,
|
||||
leadingIconContentColor = Grey100
|
||||
),
|
||||
shape = Shapes.large
|
||||
) {
|
||||
Column() {
|
||||
Text(
|
||||
text = createOptionInfo.title,
|
||||
style = Typography.h6,
|
||||
modifier = Modifier.padding(top = 16.dp)
|
||||
)
|
||||
Text(
|
||||
text = createOptionInfo.subtitle,
|
||||
style = Typography.body2,
|
||||
modifier = Modifier.padding(bottom = 16.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ExperimentalMaterialApi
|
||||
@Composable
|
||||
fun PrimaryCreateOptionRow(
|
||||
|
||||
@@ -73,11 +73,15 @@ class CreatePasskeyViewModel(
|
||||
)
|
||||
}
|
||||
|
||||
fun onCreateOptionSelected(createOptionId: Int) {
|
||||
Log.d("Account Selector", "Option selected for creation: $createOptionId")
|
||||
fun onCreateOptionSelected(entryKey: String, entrySubkey: String) {
|
||||
Log.d(
|
||||
"Account Selector",
|
||||
"Option selected for creation: {key = $entryKey, subkey = $entrySubkey}"
|
||||
)
|
||||
CredentialManagerRepo.getInstance().onOptionSelected(
|
||||
uiState.activeEntry?.activeProvider!!.name,
|
||||
createOptionId
|
||||
entryKey,
|
||||
entrySubkey
|
||||
)
|
||||
dialogResult.value = DialogResult(
|
||||
ResultState.COMPLETE,
|
||||
@@ -122,13 +126,21 @@ class CreatePasskeyViewModel(
|
||||
}
|
||||
|
||||
fun onPrimaryCreateOptionInfoSelected() {
|
||||
var createOptionId = uiState.activeEntry?.activeCreateOptionInfo?.id
|
||||
Log.d("Account Selector", "Option selected for creation: $createOptionId")
|
||||
if (createOptionId != null) {
|
||||
var createOptionEntryKey = uiState.activeEntry?.activeCreateOptionInfo?.entryKey
|
||||
var createOptionEntrySubkey = uiState.activeEntry?.activeCreateOptionInfo?.entrySubkey
|
||||
Log.d(
|
||||
"Account Selector",
|
||||
"Option selected for creation: " +
|
||||
"{key = $createOptionEntryKey, subkey = $createOptionEntrySubkey}"
|
||||
)
|
||||
if (createOptionEntryKey != null && createOptionEntrySubkey != null) {
|
||||
CredentialManagerRepo.getInstance().onOptionSelected(
|
||||
uiState.activeEntry?.activeProvider!!.name,
|
||||
createOptionId
|
||||
createOptionEntryKey,
|
||||
createOptionEntrySubkey
|
||||
)
|
||||
} else {
|
||||
TODO("Gracefully handle illegal state.")
|
||||
}
|
||||
dialogResult.value = DialogResult(
|
||||
ResultState.COMPLETE,
|
||||
|
||||
@@ -68,10 +68,10 @@ fun GetCredentialScreen(
|
||||
GetScreenState.CREDENTIAL_SELECTION -> CredentialSelectionCard(
|
||||
requestDisplayInfo = uiState.requestDisplayInfo,
|
||||
providerInfo = uiState.selectedProvider!!,
|
||||
onCancel = {viewModel.onCancel()},
|
||||
onOptionSelected = {viewModel.onCredentailSelected(it)},
|
||||
onCancel = viewModel::onCancel,
|
||||
onOptionSelected = viewModel::onCredentailSelected,
|
||||
multiProvider = uiState.providers.size > 1,
|
||||
onMoreOptionSelected = {viewModel.onMoreOptionSelected()},
|
||||
onMoreOptionSelected = viewModel::onMoreOptionSelected,
|
||||
)
|
||||
}
|
||||
},
|
||||
@@ -90,7 +90,7 @@ fun GetCredentialScreen(
|
||||
fun CredentialSelectionCard(
|
||||
requestDisplayInfo: RequestDisplayInfo,
|
||||
providerInfo: ProviderInfo,
|
||||
onOptionSelected: (Int) -> Unit,
|
||||
onOptionSelected: (String, String) -> Unit,
|
||||
onCancel: () -> Unit,
|
||||
multiProvider: Boolean,
|
||||
onMoreOptionSelected: () -> Unit,
|
||||
@@ -165,11 +165,11 @@ fun CredentialSelectionCard(
|
||||
@Composable
|
||||
fun CredentialOptionRow(
|
||||
credentialOptionInfo: CredentialOptionInfo,
|
||||
onOptionSelected: (Int) -> Unit
|
||||
onOptionSelected: (String, String) -> Unit,
|
||||
) {
|
||||
Chip(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
onClick = {onOptionSelected(credentialOptionInfo.id)},
|
||||
onClick = {onOptionSelected(credentialOptionInfo.entryKey, credentialOptionInfo.entrySubkey)},
|
||||
leadingIcon = {
|
||||
Image(modifier = Modifier.size(24.dp, 24.dp).padding(start = 10.dp),
|
||||
bitmap = credentialOptionInfo.icon.toBitmap().asImageBitmap(),
|
||||
|
||||
@@ -49,11 +49,12 @@ class GetCredentialViewModel(
|
||||
return dialogResult
|
||||
}
|
||||
|
||||
fun onCredentailSelected(credentialId: Int) {
|
||||
Log.d("Account Selector", "credential selected: $credentialId")
|
||||
fun onCredentailSelected(entryKey: String, entrySubkey: String) {
|
||||
Log.d("Account Selector", "credential selected: {key=$entryKey,subkey=$entrySubkey}")
|
||||
CredentialManagerRepo.getInstance().onOptionSelected(
|
||||
uiState.selectedProvider!!.name,
|
||||
credentialId
|
||||
entryKey,
|
||||
entrySubkey
|
||||
)
|
||||
dialogResult.value = DialogResult(
|
||||
ResultState.COMPLETE,
|
||||
|
||||
@@ -30,7 +30,8 @@ data class CredentialOptionInfo(
|
||||
val icon: Drawable,
|
||||
val title: String,
|
||||
val subtitle: String,
|
||||
val id: Int,
|
||||
val entryKey: String,
|
||||
val entrySubkey: String,
|
||||
val usageData: String
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user