diff options
| author | 2022-11-22 19:05:39 +0000 | |
|---|---|---|
| committer | 2022-11-22 19:05:39 +0000 | |
| commit | 90cef8f47366e74bd3888835b21000e3f13e86ab (patch) | |
| tree | af66ba74ebd601ded73849f15243cd30879cf6cf | |
| parent | b14d49eaf9fd5448cf77e3c1bc408d3f3624fe10 (diff) | |
| parent | 20c29c93df2c08577af0c9986f4b9404e519f452 (diff) | |
Merge "Add the only one createOption but has remoteEntry screen for create passkey"
6 files changed, 118 insertions, 81 deletions
| diff --git a/packages/CredentialManager/res/values/strings.xml b/packages/CredentialManager/res/values/strings.xml index 114de89ce82a..887a369093dd 100644 --- a/packages/CredentialManager/res/values/strings.xml +++ b/packages/CredentialManager/res/values/strings.xml @@ -6,6 +6,7 @@    <string name="string_more_options">More options</string>    <string name="string_create_in_another_place">Create in another place</string>    <string name="string_save_to_another_place">Save to another place</string> +  <string name="string_use_another_device">Use another device</string>    <string name="string_no_thanks">No thanks</string>    <string name="passkey_creation_intro_title">A simple way to sign in safely</string>    <string name="passkey_creation_intro_body">Use your fingerprint, face or screen lock to sign in with a unique passkey that can’t be forgotten or stolen. Learn more</string> diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt index a6e64cefedcb..232d681fd209 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt @@ -149,8 +149,8 @@ class CredentialManagerRepo(        if (providerInfo.isDefault) {hasDefault = true; defaultProvider = providerInfo} }      // TODO: covert from real requestInfo for create passkey      var requestDisplayInfo = RequestDisplayInfo( -      "Elisa Beckett",        "beckett-bakert@gmail.com", +      "Elisa Beckett",        TYPE_PUBLIC_KEY_CREDENTIAL,        "tribank")      val createCredentialRequest = requestInfo.createCredentialRequest @@ -165,8 +165,12 @@ class CredentialManagerRepo(      return CreateCredentialUiState(        enabledProviders = providerEnabledList,        disabledProviders = providerDisabledList, -      if (hasDefault) -      {CreateScreenState.CREATION_OPTION_SELECTION} else {CreateScreenState.PASSKEY_INTRO}, +      // TODO: Add the screen when defaultProvider has no createOption but +      //  there's remoteInfo under other providers +      if (!hasDefault || defaultProvider.createOptions.isEmpty()) { +        if (requestDisplayInfo.type == TYPE_PUBLIC_KEY_CREDENTIAL) +        {CreateScreenState.PASSKEY_INTRO} else {CreateScreenState.PROVIDER_SELECTION} +      } else {CreateScreenState.CREATION_OPTION_SELECTION},        requestDisplayInfo,        if (hasDefault) {          ActiveEntry(defaultProvider, defaultProvider.createOptions.first()) @@ -439,7 +443,7 @@ class CredentialManagerRepo(      return RequestInfo.newCreateRequestInfo(        Binder(),        CreateCredentialRequest( -        TYPE_PASSWORD_CREDENTIAL, +        TYPE_PUBLIC_KEY_CREDENTIAL,          data        ),        /*isFirstUsage=*/false, diff --git a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt index 830bc7a11bda..1c74743ab481 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt @@ -193,9 +193,10 @@ class CreateFlowUtils {            icon = pkgInfo.applicationInfo.loadIcon(packageManager)!!,            name = it.providerFlattenedComponentName,            displayName = pkgInfo.applicationInfo.loadLabel(packageManager).toString(), -          createOptions = toCreationOptionInfoList(it.saveEntries, context), +          createOptions = toCreationOptionInfoList( +            it.providerFlattenedComponentName, it.saveEntries, context),            isDefault = it.isDefaultProvider, -          remoteEntry = toRemoteInfo(it.remoteEntry), +          remoteEntry = toRemoteInfo(it.providerFlattenedComponentName, it.remoteEntry),          )        }      } @@ -219,6 +220,7 @@ class CreateFlowUtils {      }      private fun toCreationOptionInfoList( +      providerId: String,        creationEntries: List<Entry>,        context: Context,      ): List<CreateOptionInfo> { @@ -227,6 +229,7 @@ class CreateFlowUtils {          return@map CreateOptionInfo(            // TODO: remove fallbacks +          providerId = providerId,            entryKey = it.key,            entrySubkey = it.subkey,            pendingIntent = it.pendingIntent, @@ -245,11 +248,13 @@ class CreateFlowUtils {      }      private fun toRemoteInfo( +      providerId: String,        remoteEntry: Entry?,      ): RemoteInfo? {        // TODO: should also call fromSlice after getting the official jetpack code.        return if (remoteEntry != null) {          RemoteInfo( +          providerId = providerId,            entryKey = remoteEntry.key,            entrySubkey = remoteEntry.subkey,            pendingIntent = remoteEntry.pendingIntent, diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt index 3a277a638e93..7574feed2132 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt @@ -55,8 +55,11 @@ fun CreateCredentialScreen(    viewModel: CreateCredentialViewModel,    providerActivityLauncher: ManagedActivityResultLauncher<IntentSenderRequest, ActivityResult>  ) { -  val primaryEntryCallback: () -> Unit = { -    viewModel.onPrimaryCreateOptionInfoSelected(providerActivityLauncher) +  val selectEntryCallback: (EntryInfo) -> Unit = { +    viewModel.onEntrySelected(it, providerActivityLauncher) +  } +  val confirmEntryCallback: () -> Unit = { +    viewModel.onConfirmCreationSelected(providerActivityLauncher)    }    val state = rememberModalBottomSheetState(      initialValue = ModalBottomSheetValue.Expanded, @@ -78,23 +81,23 @@ fun CreateCredentialScreen(          )          CreateScreenState.CREATION_OPTION_SELECTION -> CreationSelectionCard(            requestDisplayInfo = uiState.requestDisplayInfo, +          enabledProviderList = uiState.enabledProviders,            providerInfo = uiState.activeEntry?.activeProvider!!,            createOptionInfo = uiState.activeEntry.activeEntryInfo as CreateOptionInfo, -          onOptionSelected = primaryEntryCallback, -          onConfirm = primaryEntryCallback, +          onOptionSelected = selectEntryCallback, +          onConfirm = confirmEntryCallback,            onCancel = viewModel::onCancel, -          multiProvider = uiState.enabledProviders.size > 1, -          onMoreOptionsSelected = viewModel::onMoreOptionsSelected +          onMoreOptionsSelected = viewModel::onMoreOptionsSelected,          )          CreateScreenState.MORE_OPTIONS_SELECTION -> MoreOptionsSelectionCard( -            requestDisplayInfo = uiState.requestDisplayInfo, -            enabledProviderList = uiState.enabledProviders, -            disabledProviderList = uiState.disabledProviders, -            onBackButtonSelected = viewModel::onBackButtonSelected, -            onOptionSelected = viewModel::onMoreOptionsRowSelected, -            onDisabledPasswordManagerSelected = viewModel::onDisabledPasswordManagerSelected, -            onRemoteEntrySelected = viewModel::onRemoteEntrySelected -          ) +          requestDisplayInfo = uiState.requestDisplayInfo, +          enabledProviderList = uiState.enabledProviders, +          disabledProviderList = uiState.disabledProviders, +          onBackButtonSelected = viewModel::onBackButtonSelected, +          onOptionSelected = viewModel::onMoreOptionsRowSelected, +          onDisabledPasswordManagerSelected = viewModel::onDisabledPasswordManagerSelected, +          onRemoteEntrySelected = selectEntryCallback, +        )          CreateScreenState.MORE_OPTIONS_ROW_INTRO -> MoreOptionsRowIntroCard(            providerInfo = uiState.activeEntry?.activeProvider!!,            onDefaultOrNotSelected = viewModel::onDefaultOrNotSelected @@ -234,7 +237,7 @@ fun MoreOptionsSelectionCard(    onBackButtonSelected: () -> Unit,    onOptionSelected: (ActiveEntry) -> Unit,    onDisabledPasswordManagerSelected: () -> Unit, -  onRemoteEntrySelected: () -> Unit, +  onRemoteEntrySelected: (EntryInfo) -> Unit,  ) {    Card() {      Column() { @@ -292,17 +295,15 @@ fun MoreOptionsSelectionCard(                )              }            } -          var hasRemoteInfo = false +          // TODO: handle the error situation that if multiple remoteInfos exists            enabledProviderList.forEach {              if (it.remoteEntry != null) { -              hasRemoteInfo = true -            } -          } -          if (hasRemoteInfo) { -            item { -              RemoteEntryRow( -                onRemoteEntrySelected = onRemoteEntrySelected, -              ) +              item { +                RemoteEntryRow( +                  remoteInfo = it.remoteEntry!!, +                  onRemoteEntrySelected = onRemoteEntrySelected, +                ) +              }              }            }          } @@ -388,12 +389,12 @@ fun ProviderRow(providerInfo: ProviderInfo, onProviderSelected: (String) -> Unit  @Composable  fun CreationSelectionCard(    requestDisplayInfo: RequestDisplayInfo, -  providerInfo: ProviderInfo, +  enabledProviderList: List<EnabledProviderInfo>, +  providerInfo: EnabledProviderInfo,    createOptionInfo: CreateOptionInfo, -  onOptionSelected: () -> Unit, +  onOptionSelected: (EntryInfo) -> Unit,    onConfirm: () -> Unit,    onCancel: () -> Unit, -  multiProvider: Boolean,    onMoreOptionsSelected: () -> Unit,  ) {    Card() { @@ -442,19 +443,16 @@ fun CreationSelectionCard(            .padding(horizontal = 24.dp)            .align(alignment = Alignment.CenterHorizontally),        ) { -        LazyColumn( -          verticalArrangement = Arrangement.spacedBy(2.dp) -        ) { -            item { -              PrimaryCreateOptionRow( -                requestDisplayInfo = requestDisplayInfo, -                createOptionInfo = createOptionInfo, -                onOptionSelected = onOptionSelected -              ) -            } -        } +        PrimaryCreateOptionRow( +          requestDisplayInfo = requestDisplayInfo, +          createOptionInfo = createOptionInfo, +          onOptionSelected = onOptionSelected +        )        } -      if (multiProvider) { +      var createOptionsSize = 0 +      enabledProviderList.forEach{ +        enabledProvider -> createOptionsSize += enabledProvider.createOptions.size} +      if (createOptionsSize > 1) {          TextButton(            onClick = onMoreOptionsSelected,            modifier = Modifier @@ -469,6 +467,26 @@ fun CreationSelectionCard(              textAlign = TextAlign.Center,            )          } +      } else if ( +        requestDisplayInfo.type == TYPE_PUBLIC_KEY_CREDENTIAL +      ) { +        // TODO: handle the error situation that if multiple remoteInfos exists +        enabledProviderList.forEach { enabledProvider -> +          if (enabledProvider.remoteEntry != null) { +            TextButton( +              onClick = { +                onOptionSelected(enabledProvider.remoteEntry!!) }, +              modifier = Modifier +                .padding(horizontal = 24.dp) +                .align(alignment = Alignment.CenterHorizontally) +            ) { +              Text( +                text = stringResource(R.string.string_use_another_device), +                textAlign = TextAlign.Center, +              ) +            } +          } +        }        }        Divider(          thickness = 24.dp, @@ -501,10 +519,10 @@ fun CreationSelectionCard(  fun PrimaryCreateOptionRow(    requestDisplayInfo: RequestDisplayInfo,    createOptionInfo: CreateOptionInfo, -  onOptionSelected: () -> Unit +  onOptionSelected: (EntryInfo) -> Unit  ) {    Entry( -    onClick = onOptionSelected, +    onClick = {onOptionSelected(createOptionInfo)},      icon = {        Image(modifier = Modifier.size(32.dp).padding(start = 10.dp),          bitmap = createOptionInfo.credentialTypeIcon.toBitmap().asImageBitmap(), @@ -527,7 +545,7 @@ fun PrimaryCreateOptionRow(            )          } else {            Text( -            text = requestDisplayInfo.subtitle, +            text = requestDisplayInfo.title,              style = MaterialTheme.typography.titleLarge,              modifier = Modifier.padding(top = 16.dp, bottom = 16.dp)            ) @@ -640,10 +658,11 @@ fun MoreOptionsDisabledProvidersRow(  @OptIn(ExperimentalMaterial3Api::class)  @Composable  fun RemoteEntryRow( -  onRemoteEntrySelected: () -> Unit, +  remoteInfo: RemoteInfo, +  onRemoteEntrySelected: (RemoteInfo) -> Unit,  ) {    Entry( -    onClick = onRemoteEntrySelected, +    onClick = {onRemoteEntrySelected(remoteInfo)},      icon = {        Icon(          painter = painterResource(R.drawable.ic_other_devices), diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialViewModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialViewModel.kt index 093c88f1c020..a90f4da3cae6 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialViewModel.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialViewModel.kt @@ -37,6 +37,7 @@ data class CreateCredentialUiState(    val currentScreenState: CreateScreenState,    val requestDisplayInfo: RequestDisplayInfo,    val activeEntry: ActiveEntry? = null, +  val selectedEntry: EntryInfo? = null,  )  class CreateCredentialViewModel( @@ -109,10 +110,6 @@ class CreateCredentialViewModel(      // TODO: Complete this function    } -  fun onRemoteEntrySelected() { -    // TODO: Complete this function -  } -    fun onCancel() {      CredentialManagerRepo.getInstance().onCancel()      dialogResult.value = DialogResult(ResultState.CANCELED) @@ -125,46 +122,54 @@ class CreateCredentialViewModel(      // TODO: implement the if choose as default or not logic later    } -  fun onPrimaryCreateOptionInfoSelected( +  fun onEntrySelected( +    selectedEntry: EntryInfo, +    launcher: ManagedActivityResultLauncher<IntentSenderRequest, ActivityResult> +  ) { +    val providerId = selectedEntry.providerId +    val entryKey = selectedEntry.entryKey +    val entrySubkey = selectedEntry.entrySubkey +    Log.d( +      "Account Selector", "Option selected for entry: " + +              " {provider=$providerId, key=$entryKey, subkey=$entrySubkey") +    if (selectedEntry.pendingIntent != null) { +      uiState = uiState.copy(selectedEntry = selectedEntry) +      val intentSenderRequest = IntentSenderRequest.Builder(selectedEntry.pendingIntent) +        .setFillInIntent(selectedEntry.fillInIntent).build() +      launcher.launch(intentSenderRequest) +    } else { +      CredentialManagerRepo.getInstance().onOptionSelected( +        providerId, +        entryKey, +        entrySubkey +      ) +      dialogResult.value = DialogResult( +        ResultState.COMPLETE, +      ) +    } +  } + +  fun onConfirmCreationSelected(      launcher: ManagedActivityResultLauncher<IntentSenderRequest, ActivityResult>    ) {      val selectedEntry = uiState.activeEntry?.activeEntryInfo      if (selectedEntry != null) { -      val entryKey = selectedEntry.entryKey -      val entrySubkey = selectedEntry.entrySubkey -      Log.d( -        "Account Selector", -        "Option selected for creation: " + -                "{key = $entryKey, subkey = $entrySubkey}" -      ) -      if (selectedEntry.pendingIntent != null) { -        val intentSenderRequest = IntentSenderRequest.Builder(selectedEntry.pendingIntent) -          .setFillInIntent(selectedEntry.fillInIntent).build() -        launcher.launch(intentSenderRequest) -      } else { -        CredentialManagerRepo.getInstance().onOptionSelected( -          uiState.activeEntry?.activeProvider!!.name, -          entryKey, -          entrySubkey -        ) -        dialogResult.value = DialogResult( -          ResultState.COMPLETE, -        ) -      } +      onEntrySelected(selectedEntry, launcher)      } else { +      Log.w("Account Selector", +        "Illegal state: confirm is pressed but activeEntry isn't set.")        dialogResult.value = DialogResult(          ResultState.COMPLETE,        ) -      TODO("Gracefully handle illegal state.")      }    }    fun onProviderActivityResult(providerActivityResult: ProviderActivityResult) { -    val entry = uiState.activeEntry?.activeEntryInfo +    val entry = uiState.selectedEntry      val resultCode = providerActivityResult.resultCode      val resultData = providerActivityResult.data -    val providerId = uiState.activeEntry?.activeProvider!!.name      if (entry != null) { +      val providerId = entry.providerId        Log.d("Account Selector", "Got provider activity result: {provider=" +                "$providerId, key=${entry.entryKey}, subkey=${entry.entrySubkey}, " +                "resultCode=$resultCode, resultData=$resultData}" diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt index 753dc3c63bc7..e27db43768a0 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt @@ -42,6 +42,7 @@ class DisabledProviderInfo(  ) : ProviderInfo(icon, name, displayName)  open class EntryInfo ( +  val providerId: String,    val entryKey: String,    val entrySubkey: String,    val pendingIntent: PendingIntent?, @@ -49,6 +50,7 @@ open class EntryInfo (  )  class CreateOptionInfo( +  providerId: String,    entryKey: String,    entrySubkey: String,    pendingIntent: PendingIntent?, @@ -60,14 +62,15 @@ class CreateOptionInfo(    val passkeyCount: Int?,    val totalCredentialCount: Int?,    val lastUsedTimeMillis: Long?, -) : EntryInfo(entryKey, entrySubkey, pendingIntent, fillInIntent) +) : EntryInfo(providerId, entryKey, entrySubkey, pendingIntent, fillInIntent)  class RemoteInfo( +  providerId: String,    entryKey: String,    entrySubkey: String,    pendingIntent: PendingIntent?,    fillInIntent: Intent?, -) : EntryInfo(entryKey, entrySubkey, pendingIntent, fillInIntent) +) : EntryInfo(providerId, entryKey, entrySubkey, pendingIntent, fillInIntent)  data class RequestDisplayInfo(    val title: String, |