Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 90cef8f4 authored by Qinmei Du's avatar Qinmei Du Committed by Android (Google) Code Review
Browse files

Merge "Add the only one createOption but has remoteEntry screen for create passkey"

parents b14d49ea 20c29c93
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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>
+8 −4
Original line number Diff line number Diff line
@@ -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,
+7 −2
Original line number Diff line number Diff line
@@ -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,
+63 −44
Original line number Diff line number Diff line
@@ -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,13 +81,13 @@ 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,
@@ -93,7 +96,7 @@ fun CreateCredentialScreen(
          onBackButtonSelected = viewModel::onBackButtonSelected,
          onOptionSelected = viewModel::onMoreOptionsRowSelected,
          onDisabledPasswordManagerSelected = viewModel::onDisabledPasswordManagerSelected,
            onRemoteEntrySelected = viewModel::onRemoteEntrySelected
          onRemoteEntrySelected = selectEntryCallback,
        )
        CreateScreenState.MORE_OPTIONS_ROW_INTRO -> MoreOptionsRowIntroCard(
          providerInfo = uiState.activeEntry?.activeProvider!!,
@@ -234,7 +237,7 @@ fun MoreOptionsSelectionCard(
  onBackButtonSelected: () -> Unit,
  onOptionSelected: (ActiveEntry) -> Unit,
  onDisabledPasswordManagerSelected: () -> Unit,
  onRemoteEntrySelected: () -> Unit,
  onRemoteEntrySelected: (EntryInfo) -> Unit,
) {
  Card() {
    Column() {
@@ -292,21 +295,19 @@ 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(
                  remoteInfo = it.remoteEntry!!,
                  onRemoteEntrySelected = onRemoteEntrySelected,
                )
              }
            }
          }
        }
      }
      Divider(
        thickness = 18.dp,
        color = Color.Transparent,
@@ -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
        )
      }
        }
      }
      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),
+34 −29
Original line number Diff line number Diff line
@@ -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,25 +122,24 @@ class CreateCredentialViewModel(
    // TODO: implement the if choose as default or not logic later
  }

  fun onPrimaryCreateOptionInfoSelected(
  fun onEntrySelected(
    selectedEntry: EntryInfo,
    launcher: ManagedActivityResultLauncher<IntentSenderRequest, ActivityResult>
  ) {
    val selectedEntry = uiState.activeEntry?.activeEntryInfo
    if (selectedEntry != null) {
    val providerId = selectedEntry.providerId
    val entryKey = selectedEntry.entryKey
    val entrySubkey = selectedEntry.entrySubkey
    Log.d(
        "Account Selector",
        "Option selected for creation: " +
                "{key = $entryKey, subkey = $entrySubkey}"
      )
      "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(
          uiState.activeEntry?.activeProvider!!.name,
        providerId,
        entryKey,
        entrySubkey
      )
@@ -151,20 +147,29 @@ class CreateCredentialViewModel(
        ResultState.COMPLETE,
      )
    }
  }

  fun onConfirmCreationSelected(
    launcher: ManagedActivityResultLauncher<IntentSenderRequest, ActivityResult>
  ) {
    val selectedEntry = uiState.activeEntry?.activeEntryInfo
    if (selectedEntry != null) {
      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}"
Loading