Merge "Handle finishing up a dialog."
This commit is contained in:
@@ -41,7 +41,7 @@ public class ProviderData implements Parcelable {
|
||||
"android.credentials.ui.extra.PROVIDER_DATA_LIST";
|
||||
|
||||
@NonNull
|
||||
private final String mPackageName;
|
||||
private final String mProviderId;
|
||||
@NonNull
|
||||
private final List<Entry> mCredentialEntries;
|
||||
@NonNull
|
||||
@@ -50,11 +50,11 @@ public class ProviderData implements Parcelable {
|
||||
private final Entry mAuthenticationEntry;
|
||||
|
||||
public ProviderData(
|
||||
@NonNull String packageName,
|
||||
@NonNull String providerId,
|
||||
@NonNull List<Entry> credentialEntries,
|
||||
@NonNull List<Entry> actionChips,
|
||||
@Nullable Entry authenticationEntry) {
|
||||
mPackageName = packageName;
|
||||
mProviderId = providerId;
|
||||
mCredentialEntries = credentialEntries;
|
||||
mActionChips = actionChips;
|
||||
mAuthenticationEntry = authenticationEntry;
|
||||
@@ -62,8 +62,8 @@ public class ProviderData implements Parcelable {
|
||||
|
||||
/** Returns the provider package name. */
|
||||
@NonNull
|
||||
public String getPackageName() {
|
||||
return mPackageName;
|
||||
public String getProviderId() {
|
||||
return mProviderId;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@@ -82,9 +82,9 @@ public class ProviderData implements Parcelable {
|
||||
}
|
||||
|
||||
protected ProviderData(@NonNull Parcel in) {
|
||||
String packageName = in.readString8();
|
||||
mPackageName = packageName;
|
||||
AnnotationValidations.validate(NonNull.class, null, mPackageName);
|
||||
String providerId = in.readString8();
|
||||
mProviderId = providerId;
|
||||
AnnotationValidations.validate(NonNull.class, null, mProviderId);
|
||||
|
||||
List<Entry> credentialEntries = new ArrayList<>();
|
||||
in.readTypedList(credentialEntries, Entry.CREATOR);
|
||||
@@ -102,7 +102,7 @@ public class ProviderData implements Parcelable {
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeString8(mPackageName);
|
||||
dest.writeString8(mProviderId);
|
||||
dest.writeTypedList(mCredentialEntries);
|
||||
dest.writeTypedList(mActionChips);
|
||||
dest.writeTypedObject(mAuthenticationEntry, flags);
|
||||
|
||||
@@ -43,11 +43,16 @@ public class UserSelectionResult implements Parcelable {
|
||||
@NonNull
|
||||
private final IBinder mRequestToken;
|
||||
|
||||
@NonNull
|
||||
private final String mProviderId;
|
||||
|
||||
// TODO: consider switching to string or other types, depending on the service implementation.
|
||||
private final int mEntryId;
|
||||
|
||||
public UserSelectionResult(@NonNull IBinder requestToken, int entryId) {
|
||||
public UserSelectionResult(@NonNull IBinder requestToken, @NonNull String providerId,
|
||||
int entryId) {
|
||||
mRequestToken = requestToken;
|
||||
mProviderId = providerId;
|
||||
mEntryId = entryId;
|
||||
}
|
||||
|
||||
@@ -57,23 +62,33 @@ public class UserSelectionResult implements Parcelable {
|
||||
return mRequestToken;
|
||||
}
|
||||
|
||||
/** Returns provider package name whose entry was selected by the user. */
|
||||
@NonNull
|
||||
public String getProviderId() {
|
||||
return mProviderId;
|
||||
}
|
||||
|
||||
/** Returns the id of the visual entry that the user selected. */
|
||||
public int geEntryId() {
|
||||
public int getEntryId() {
|
||||
return mEntryId;
|
||||
}
|
||||
|
||||
protected UserSelectionResult(@NonNull Parcel in) {
|
||||
IBinder requestToken = in.readStrongBinder();
|
||||
String providerId = in.readString8();
|
||||
int entryId = in.readInt();
|
||||
|
||||
mRequestToken = requestToken;
|
||||
AnnotationValidations.validate(NonNull.class, null, mRequestToken);
|
||||
mProviderId = providerId;
|
||||
AnnotationValidations.validate(NonNull.class, null, mProviderId);
|
||||
mEntryId = entryId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeStrongBinder(mRequestToken);
|
||||
dest.writeString8(mProviderId);
|
||||
dest.writeInt(mEntryId);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.credentialmanager
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.slice.Slice
|
||||
import android.app.slice.SliceSpec
|
||||
import android.content.Context
|
||||
@@ -23,8 +24,11 @@ import android.content.Intent
|
||||
import android.credentials.ui.Entry
|
||||
import android.credentials.ui.ProviderData
|
||||
import android.credentials.ui.RequestInfo
|
||||
import android.credentials.ui.UserSelectionResult
|
||||
import android.graphics.drawable.Icon
|
||||
import android.os.Binder
|
||||
import android.os.Bundle
|
||||
import android.os.ResultReceiver
|
||||
import com.android.credentialmanager.createflow.CreatePasskeyUiState
|
||||
import com.android.credentialmanager.createflow.CreateScreenState
|
||||
import com.android.credentialmanager.getflow.GetCredentialUiState
|
||||
@@ -37,6 +41,8 @@ class CredentialManagerRepo(
|
||||
) {
|
||||
private val requestInfo: RequestInfo
|
||||
private val providerList: List<ProviderData>
|
||||
// TODO: require non-null.
|
||||
val resultReceiver: ResultReceiver?
|
||||
|
||||
init {
|
||||
requestInfo = intent.extras?.getParcelable(
|
||||
@@ -52,6 +58,29 @@ class CredentialManagerRepo(
|
||||
ProviderData.EXTRA_PROVIDER_DATA_LIST,
|
||||
ProviderData::class.java
|
||||
) ?: testProviderList()
|
||||
|
||||
resultReceiver = intent.getParcelableExtra(
|
||||
RequestInfo.EXTRA_RESULT_RECEIVER,
|
||||
ResultReceiver::class.java
|
||||
)
|
||||
}
|
||||
|
||||
fun onCancel() {
|
||||
resultReceiver?.send(Activity.RESULT_CANCELED, null)
|
||||
}
|
||||
|
||||
fun onOptionSelected(providerPackageName: String, entryId: Int) {
|
||||
val userSelectionResult = UserSelectionResult(
|
||||
requestInfo.token,
|
||||
providerPackageName,
|
||||
entryId
|
||||
)
|
||||
val resultData = Bundle()
|
||||
resultData.putParcelable(
|
||||
UserSelectionResult.EXTRA_USER_SELECTION_RESULT,
|
||||
userSelectionResult
|
||||
)
|
||||
resultReceiver?.send(Activity.RESULT_OK, resultData)
|
||||
}
|
||||
|
||||
fun getCredentialInitialUiState(): GetCredentialUiState {
|
||||
|
||||
@@ -23,9 +23,15 @@ import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.compose.material.ExperimentalMaterialApi
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.android.credentialmanager.common.DialogType
|
||||
import com.android.credentialmanager.common.DialogResult
|
||||
import com.android.credentialmanager.common.ResultState
|
||||
import com.android.credentialmanager.createflow.CreatePasskeyScreen
|
||||
import com.android.credentialmanager.createflow.CreatePasskeyViewModel
|
||||
import com.android.credentialmanager.getflow.GetCredentialScreen
|
||||
import com.android.credentialmanager.getflow.GetCredentialViewModel
|
||||
import com.android.credentialmanager.ui.theme.CredentialSelectorTheme
|
||||
|
||||
@ExperimentalMaterialApi
|
||||
@@ -57,10 +63,20 @@ class CredentialSelectorActivity : ComponentActivity() {
|
||||
val dialogType = DialogType.toDialogType(operationType)
|
||||
when (dialogType) {
|
||||
DialogType.CREATE_PASSKEY -> {
|
||||
CreatePasskeyScreen(cancelActivity = onCancel)
|
||||
val viewModel: CreatePasskeyViewModel = viewModel()
|
||||
viewModel.observeDialogResult().observe(
|
||||
this@CredentialSelectorActivity,
|
||||
onCancel
|
||||
)
|
||||
CreatePasskeyScreen(viewModel = viewModel)
|
||||
}
|
||||
DialogType.GET_CREDENTIALS -> {
|
||||
GetCredentialScreen(cancelActivity = onCancel)
|
||||
val viewModel: GetCredentialViewModel = viewModel()
|
||||
viewModel.observeDialogResult().observe(
|
||||
this@CredentialSelectorActivity,
|
||||
onCancel
|
||||
)
|
||||
GetCredentialScreen(viewModel = viewModel)
|
||||
}
|
||||
else -> {
|
||||
Log.w("AccountSelector", "Unknown type, not rendering any UI")
|
||||
@@ -69,7 +85,9 @@ class CredentialSelectorActivity : ComponentActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
private val onCancel = {
|
||||
this@CredentialSelectorActivity.finish()
|
||||
private val onCancel = Observer<DialogResult> {
|
||||
if (it.resultState == ResultState.COMPLETE || it.resultState == ResultState.CANCELED) {
|
||||
this@CredentialSelectorActivity.finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ class GetFlowUtils {
|
||||
ProviderInfo(
|
||||
// TODO: replace to extract from the service data structure when available
|
||||
icon = context.getDrawable(R.drawable.ic_passkey)!!,
|
||||
name = it.packageName,
|
||||
name = it.providerId,
|
||||
appDomainName = "tribank.us",
|
||||
credentialTypeIcon = context.getDrawable(R.drawable.ic_passkey)!!,
|
||||
credentialOptions = toCredentialOptionInfoList(it.credentialEntries, context)
|
||||
@@ -78,7 +78,7 @@ class CreateFlowUtils {
|
||||
com.android.credentialmanager.createflow.ProviderInfo(
|
||||
// TODO: replace to extract from the service data structure when available
|
||||
icon = context.getDrawable(R.drawable.ic_passkey)!!,
|
||||
name = it.packageName,
|
||||
name = it.providerId,
|
||||
appDomainName = "tribank.us",
|
||||
credentialTypeIcon = context.getDrawable(R.drawable.ic_passkey)!!,
|
||||
createOptions = toCreationOptionInfoList(it.credentialEntries, context),
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.common
|
||||
|
||||
enum class ResultState {
|
||||
COMPLETE,
|
||||
CANCELED,
|
||||
}
|
||||
|
||||
data class DialogResult(
|
||||
val resultState: ResultState,
|
||||
)
|
||||
@@ -38,7 +38,6 @@ import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.graphics.drawable.toBitmap
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.android.credentialmanager.R
|
||||
import com.android.credentialmanager.ui.theme.Grey100
|
||||
import com.android.credentialmanager.ui.theme.Shapes
|
||||
@@ -50,8 +49,7 @@ import com.android.credentialmanager.ui.theme.lightSurface1
|
||||
@ExperimentalMaterialApi
|
||||
@Composable
|
||||
fun CreatePasskeyScreen(
|
||||
viewModel: CreatePasskeyViewModel = viewModel(),
|
||||
cancelActivity: () -> Unit,
|
||||
viewModel: CreatePasskeyViewModel,
|
||||
) {
|
||||
val state = rememberModalBottomSheetState(
|
||||
initialValue = ModalBottomSheetValue.Expanded,
|
||||
@@ -64,17 +62,17 @@ fun CreatePasskeyScreen(
|
||||
when (uiState.currentScreenState) {
|
||||
CreateScreenState.PASSKEY_INTRO -> ConfirmationCard(
|
||||
onConfirm = {viewModel.onConfirmIntro()},
|
||||
onCancel = cancelActivity,
|
||||
onCancel = {viewModel.onCancel()},
|
||||
)
|
||||
CreateScreenState.PROVIDER_SELECTION -> ProviderSelectionCard(
|
||||
providerList = uiState.providers,
|
||||
onCancel = cancelActivity,
|
||||
onCancel = {viewModel.onCancel()},
|
||||
onProviderSelected = {viewModel.onProviderSelected(it)}
|
||||
)
|
||||
CreateScreenState.CREATION_OPTION_SELECTION -> CreationSelectionCard(
|
||||
providerInfo = uiState.selectedProvider!!,
|
||||
onOptionSelected = {viewModel.onCreateOptionSelected(it)},
|
||||
onCancel = cancelActivity,
|
||||
onCancel = {viewModel.onCancel()},
|
||||
multiProvider = uiState.providers.size > 1,
|
||||
onMoreOptionsSelected = {viewModel.onMoreOptionsSelected(it)}
|
||||
)
|
||||
@@ -93,7 +91,7 @@ fun CreatePasskeyScreen(
|
||||
) {}
|
||||
LaunchedEffect(state.currentValue) {
|
||||
if (state.currentValue == ModalBottomSheetValue.Hidden) {
|
||||
cancelActivity()
|
||||
viewModel.onCancel()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,8 +20,12 @@ import android.util.Log
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.android.credentialmanager.CredentialManagerRepo
|
||||
import com.android.credentialmanager.common.DialogResult
|
||||
import com.android.credentialmanager.common.ResultState
|
||||
|
||||
data class CreatePasskeyUiState(
|
||||
val providers: List<ProviderInfo>,
|
||||
@@ -36,6 +40,14 @@ class CreatePasskeyViewModel(
|
||||
var uiState by mutableStateOf(credManRepo.createPasskeyInitialUiState())
|
||||
private set
|
||||
|
||||
val dialogResult: MutableLiveData<DialogResult> by lazy {
|
||||
MutableLiveData<DialogResult>()
|
||||
}
|
||||
|
||||
fun observeDialogResult(): LiveData<DialogResult> {
|
||||
return dialogResult
|
||||
}
|
||||
|
||||
fun onConfirmIntro() {
|
||||
if (uiState.providers.size > 1) {
|
||||
uiState = uiState.copy(
|
||||
@@ -60,6 +72,13 @@ class CreatePasskeyViewModel(
|
||||
|
||||
fun onCreateOptionSelected(createOptionId: Int) {
|
||||
Log.d("Account Selector", "Option selected for creation: $createOptionId")
|
||||
CredentialManagerRepo.getInstance().onOptionSelected(
|
||||
uiState.selectedProvider!!.name,
|
||||
createOptionId
|
||||
)
|
||||
dialogResult.value = DialogResult(
|
||||
ResultState.COMPLETE,
|
||||
)
|
||||
}
|
||||
|
||||
fun getProviderInfoByName(providerName: String): ProviderInfo {
|
||||
@@ -88,4 +107,9 @@ class CreatePasskeyViewModel(
|
||||
selectedProvider = getProviderInfoByName(providerName)
|
||||
)
|
||||
}
|
||||
|
||||
fun onCancel() {
|
||||
CredentialManagerRepo.getInstance().onCancel()
|
||||
dialogResult.value = DialogResult(ResultState.CANCELED)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,6 @@ import androidx.compose.ui.graphics.asImageBitmap
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.graphics.drawable.toBitmap
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.android.credentialmanager.R
|
||||
import com.android.credentialmanager.createflow.CancelButton
|
||||
import com.android.credentialmanager.ui.theme.Grey100
|
||||
@@ -55,8 +54,7 @@ import com.android.credentialmanager.ui.theme.lightBackgroundColor
|
||||
@ExperimentalMaterialApi
|
||||
@Composable
|
||||
fun GetCredentialScreen(
|
||||
viewModel: GetCredentialViewModel = viewModel(),
|
||||
cancelActivity: () -> Unit,
|
||||
viewModel: GetCredentialViewModel,
|
||||
) {
|
||||
val state = rememberModalBottomSheetState(
|
||||
initialValue = ModalBottomSheetValue.Expanded,
|
||||
@@ -69,7 +67,7 @@ fun GetCredentialScreen(
|
||||
when (uiState.currentScreenState) {
|
||||
GetScreenState.CREDENTIAL_SELECTION -> CredentialSelectionCard(
|
||||
providerInfo = uiState.selectedProvider!!,
|
||||
onCancel = cancelActivity,
|
||||
onCancel = {viewModel.onCancel()},
|
||||
onOptionSelected = {viewModel.onCredentailSelected(it)},
|
||||
multiProvider = uiState.providers.size > 1,
|
||||
onMoreOptionSelected = {viewModel.onMoreOptionSelected()},
|
||||
@@ -81,7 +79,7 @@ fun GetCredentialScreen(
|
||||
) {}
|
||||
LaunchedEffect(state.currentValue) {
|
||||
if (state.currentValue == ModalBottomSheetValue.Hidden) {
|
||||
cancelActivity()
|
||||
viewModel.onCancel()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,8 +20,12 @@ import android.util.Log
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.android.credentialmanager.CredentialManagerRepo
|
||||
import com.android.credentialmanager.common.DialogResult
|
||||
import com.android.credentialmanager.common.ResultState
|
||||
|
||||
data class GetCredentialUiState(
|
||||
val providers: List<ProviderInfo>,
|
||||
@@ -36,11 +40,31 @@ class GetCredentialViewModel(
|
||||
var uiState by mutableStateOf(credManRepo.getCredentialInitialUiState())
|
||||
private set
|
||||
|
||||
val dialogResult: MutableLiveData<DialogResult> by lazy {
|
||||
MutableLiveData<DialogResult>()
|
||||
}
|
||||
|
||||
fun observeDialogResult(): LiveData<DialogResult> {
|
||||
return dialogResult
|
||||
}
|
||||
|
||||
fun onCredentailSelected(credentialId: Int) {
|
||||
Log.d("Account Selector", "credential selected: $credentialId")
|
||||
CredentialManagerRepo.getInstance().onOptionSelected(
|
||||
uiState.selectedProvider!!.name,
|
||||
credentialId
|
||||
)
|
||||
dialogResult.value = DialogResult(
|
||||
ResultState.COMPLETE,
|
||||
)
|
||||
}
|
||||
|
||||
fun onMoreOptionSelected() {
|
||||
Log.d("Account Selector", "More Option selected")
|
||||
}
|
||||
|
||||
fun onCancel() {
|
||||
CredentialManagerRepo.getInstance().onCancel()
|
||||
dialogResult.value = DialogResult(ResultState.CANCELED)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user