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

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

Merge "Add choose other password manager row in the more options screen"

parents 53ee7564 96d5bac2
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@
  <string name="passkeys">passkeys</string>
  <string name="passwords">passwords</string>
  <string name="sign_ins">sign-ins</string>
  <string name="other_password_manager">Other password manager</string>
  <string name="createOptionInfo_icon_description">CreateOptionInfo credentialType icon</string>
  <!-- Spoken content description of an element which will close the sheet when clicked. -->
  <string name="close_sheet">"Close sheet"</string>
+33 −14
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import android.credentials.ui.Constants
import android.credentials.ui.Entry
import android.credentials.ui.CreateCredentialProviderData
import android.credentials.ui.GetCredentialProviderData
import android.credentials.ui.DisabledProviderData
import android.credentials.ui.ProviderData
import android.credentials.ui.RequestInfo
import android.credentials.ui.BaseDialogResult
@@ -39,7 +40,7 @@ import android.os.ResultReceiver
import com.android.credentialmanager.createflow.ActiveEntry
import com.android.credentialmanager.createflow.CreatePasskeyUiState
import com.android.credentialmanager.createflow.CreateScreenState
import com.android.credentialmanager.createflow.ProviderInfo
import com.android.credentialmanager.createflow.EnabledProviderInfo
import com.android.credentialmanager.createflow.RequestDisplayInfo
import com.android.credentialmanager.getflow.GetCredentialUiState
import com.android.credentialmanager.getflow.GetScreenState
@@ -51,7 +52,8 @@ class CredentialManagerRepo(
  intent: Intent,
) {
  private val requestInfo: RequestInfo
  private val providerList: List<ProviderData>
  private val providerEnabledList: List<ProviderData>
  private val providerDisabledList: List<DisabledProviderData>
  // TODO: require non-null.
  val resultReceiver: ResultReceiver?

@@ -61,16 +63,16 @@ class CredentialManagerRepo(
      RequestInfo::class.java
    ) ?: testCreateRequestInfo()

    providerList = when (requestInfo.type) {
    providerEnabledList = when (requestInfo.type) {
      RequestInfo.TYPE_CREATE ->
        intent.extras?.getParcelableArrayList(
                ProviderData.EXTRA_ENABLED_PROVIDER_DATA_LIST,
                CreateCredentialProviderData::class.java
        ) ?: testCreateCredentialProviderList()
        ) ?: testCreateCredentialEnabledProviderList()
      RequestInfo.TYPE_GET ->
        intent.extras?.getParcelableArrayList(
          ProviderData.EXTRA_ENABLED_PROVIDER_DATA_LIST,
          GetCredentialProviderData::class.java
          DisabledProviderData::class.java
        ) ?: testGetCredentialProviderList()
      else -> {
        // TODO: fail gracefully
@@ -78,6 +80,12 @@ class CredentialManagerRepo(
      }
    }

    providerDisabledList =
      intent.extras?.getParcelableArrayList(
        ProviderData.EXTRA_DISABLED_PROVIDER_DATA_LIST,
        DisabledProviderData::class.java
      ) ?: testDisabledProviderList()

    resultReceiver = intent.getParcelableExtra(
      Constants.EXTRA_RESULT_RECEIVER,
      ResultReceiver::class.java
@@ -103,25 +111,28 @@ class CredentialManagerRepo(
  }

  fun getCredentialInitialUiState(): GetCredentialUiState {
    val providerList = GetFlowUtils.toProviderList(
    val providerEnabledList = GetFlowUtils.toProviderList(
    // TODO: handle runtime cast error
    providerList as List<GetCredentialProviderData>, context)
      providerEnabledList as List<GetCredentialProviderData>, context)
    // TODO: covert from real requestInfo
    val requestDisplayInfo = com.android.credentialmanager.getflow.RequestDisplayInfo("tribank")
    return GetCredentialUiState(
      providerList,
      providerEnabledList,
      GetScreenState.PRIMARY_SELECTION,
      requestDisplayInfo,
    )
  }

  fun createPasskeyInitialUiState(): CreatePasskeyUiState {
    val providerList = CreateFlowUtils.toProviderList(
    val providerEnabledList = CreateFlowUtils.toEnabledProviderList(
      // Handle runtime cast error
      providerList as List<CreateCredentialProviderData>, context)
      providerEnabledList as List<CreateCredentialProviderData>, context)
    val providerDisabledList = CreateFlowUtils.toDisabledProviderList(
      // Handle runtime cast error
      providerDisabledList as List<DisabledProviderData>, context)
    var hasDefault = false
    var defaultProvider: ProviderInfo = providerList.first()
    providerList.forEach{providerInfo -> providerInfo.createOptions =
    var defaultProvider: EnabledProviderInfo = providerEnabledList.first()
    providerEnabledList.forEach{providerInfo -> providerInfo.createOptions =
      providerInfo.createOptions.sortedWith(compareBy { it.lastUsedTimeMillis }).reversed()
      if (providerInfo.isDefault) {hasDefault = true; defaultProvider = providerInfo} }
    // TODO: covert from real requestInfo
@@ -131,7 +142,8 @@ class CredentialManagerRepo(
      TYPE_PUBLIC_KEY_CREDENTIAL,
      "tribank")
    return CreatePasskeyUiState(
      providers = providerList,
      enabledProviders = providerEnabledList,
      disabledProviders = providerDisabledList,
      if (hasDefault)
      {CreateScreenState.CREATION_OPTION_SELECTION} else {CreateScreenState.PASSKEY_INTRO},
      requestDisplayInfo,
@@ -157,7 +169,7 @@ class CredentialManagerRepo(
  }

  // TODO: below are prototype functionalities. To be removed for productionization.
  private fun testCreateCredentialProviderList(): List<CreateCredentialProviderData> {
  private fun testCreateCredentialEnabledProviderList(): List<CreateCredentialProviderData> {
    return listOf(
      CreateCredentialProviderData
        .Builder("com.google/com.google.CredentialManagerService")
@@ -185,6 +197,13 @@ class CredentialManagerRepo(
    )
  }

  private fun testDisabledProviderList(): List<DisabledProviderData> {
    return listOf(
      DisabledProviderData("LastPass"),
      DisabledProviderData("Xyzinstalledbutdisabled"),
    )
  }

  private fun testGetCredentialProviderList(): List<GetCredentialProviderData> {
    return listOf(
      GetCredentialProviderData.Builder("com.google/com.google.CredentialManagerService")
+18 −3
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.content.Context
import android.credentials.ui.Entry
import android.credentials.ui.GetCredentialProviderData
import android.credentials.ui.CreateCredentialProviderData
import android.credentials.ui.DisabledProviderData
import com.android.credentialmanager.createflow.CreateOptionInfo
import com.android.credentialmanager.getflow.ActionEntryInfo
import com.android.credentialmanager.getflow.AuthenticationEntryInfo
@@ -103,12 +104,12 @@ class GetFlowUtils {
class CreateFlowUtils {
  companion object {

    fun toProviderList(
    fun toEnabledProviderList(
      providerDataList: List<CreateCredentialProviderData>,
      context: Context,
    ): List<com.android.credentialmanager.createflow.ProviderInfo> {
    ): List<com.android.credentialmanager.createflow.EnabledProviderInfo> {
      return providerDataList.map {
        com.android.credentialmanager.createflow.ProviderInfo(
        com.android.credentialmanager.createflow.EnabledProviderInfo(
          // TODO: replace to extract from the service data structure when available
          icon = context.getDrawable(R.drawable.ic_passkey)!!,
          name = it.providerFlattenedComponentName,
@@ -119,6 +120,20 @@ class CreateFlowUtils {
      }
    }

    fun toDisabledProviderList(
      providerDataList: List<DisabledProviderData>,
      context: Context,
    ): List<com.android.credentialmanager.createflow.DisabledProviderInfo> {
      return providerDataList.map {
        com.android.credentialmanager.createflow.DisabledProviderInfo(
          // TODO: replace to extract from the service data structure when available
          icon = context.getDrawable(R.drawable.ic_passkey)!!,
          name = it.providerFlattenedComponentName,
          displayName = it.providerFlattenedComponentName,
        )
      }
    }

    private fun toCreationOptionInfoList(
      creationEntries: List<Entry>,
      context: Context,
+15 −3
Original line number Diff line number Diff line
@@ -18,13 +18,25 @@ package com.android.credentialmanager.createflow

import android.graphics.drawable.Drawable

data class ProviderInfo(
open class ProviderInfo(
  val icon: Drawable,
  val name: String,
  val displayName: String,
)

class EnabledProviderInfo(
  icon: Drawable,
  name: String,
  displayName: String,
  var createOptions: List<CreateOptionInfo>,
  val isDefault: Boolean,
)
) : ProviderInfo(icon, name, displayName)

class DisabledProviderInfo(
  icon: Drawable,
  name: String,
  displayName: String,
) : ProviderInfo(icon, name, displayName)

open class EntryInfo (
  val entryKey: String,
@@ -55,7 +67,7 @@ data class RequestDisplayInfo(
 * user selects a different entry on the more option page.
 */
data class ActiveEntry (
  val activeProvider: ProviderInfo,
  val activeProvider: EnabledProviderInfo,
  val activeEntryInfo: EntryInfo,
)

+58 −14
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import androidx.compose.material3.TextButton
import androidx.compose.material3.TopAppBar
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.filled.Add
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Alignment
@@ -59,7 +60,7 @@ fun CreatePasskeyScreen(
          onCancel = viewModel::onCancel,
        )
        CreateScreenState.PROVIDER_SELECTION -> ProviderSelectionCard(
          providerList = uiState.providers,
          enabledProviderList = uiState.enabledProviders,
          onCancel = viewModel::onCancel,
          onProviderSelected = viewModel::onProviderSelected
        )
@@ -70,14 +71,16 @@ fun CreatePasskeyScreen(
          onOptionSelected = viewModel::onPrimaryCreateOptionInfoSelected,
          onConfirm = viewModel::onPrimaryCreateOptionInfoSelected,
          onCancel = viewModel::onCancel,
          multiProvider = uiState.providers.size > 1,
          multiProvider = uiState.enabledProviders.size > 1,
          onMoreOptionsSelected = viewModel::onMoreOptionsSelected
        )
        CreateScreenState.MORE_OPTIONS_SELECTION -> MoreOptionsSelectionCard(
            requestDisplayInfo = uiState.requestDisplayInfo,
            providerList = uiState.providers,
            enabledProviderList = uiState.enabledProviders,
            disabledProviderList = uiState.disabledProviders,
            onBackButtonSelected = viewModel::onBackButtonSelected,
            onOptionSelected = viewModel::onMoreOptionsRowSelected
            onOptionSelected = viewModel::onMoreOptionsRowSelected,
            onDisabledPasswordManagerSelected = viewModel::onDisabledPasswordManagerSelected
          )
        CreateScreenState.MORE_OPTIONS_ROW_INTRO -> MoreOptionsRowIntroCard(
          providerInfo = uiState.activeEntry?.activeProvider!!,
@@ -153,7 +156,7 @@ fun ConfirmationCard(
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ProviderSelectionCard(
  providerList: List<ProviderInfo>,
  enabledProviderList: List<EnabledProviderInfo>,
  onProviderSelected: (String) -> Unit,
  onCancel: () -> Unit
) {
@@ -182,7 +185,7 @@ fun ProviderSelectionCard(
        LazyColumn(
          verticalArrangement = Arrangement.spacedBy(2.dp)
        ) {
          providerList.forEach {
          enabledProviderList.forEach {
            item {
              ProviderRow(providerInfo = it, onProviderSelected = onProviderSelected)
            }
@@ -212,9 +215,11 @@ fun ProviderSelectionCard(
@Composable
fun MoreOptionsSelectionCard(
  requestDisplayInfo: RequestDisplayInfo,
  providerList: List<ProviderInfo>,
  enabledProviderList: List<EnabledProviderInfo>,
  disabledProviderList: List<DisabledProviderInfo>,
  onBackButtonSelected: () -> Unit,
  onOptionSelected: (ActiveEntry) -> Unit
  onOptionSelected: (ActiveEntry) -> Unit,
  onDisabledPasswordManagerSelected: () -> Unit,
) {
  Card() {
    Column() {
@@ -250,18 +255,24 @@ fun MoreOptionsSelectionCard(
        LazyColumn(
          verticalArrangement = Arrangement.spacedBy(2.dp)
        ) {
          providerList.forEach { providerInfo ->
            providerInfo.createOptions.forEach { createOptionInfo ->
          enabledProviderList.forEach { enabledProviderInfo ->
            enabledProviderInfo.createOptions.forEach { createOptionInfo ->
              item {
                MoreOptionsInfoRow(
                  providerInfo = providerInfo,
                  providerInfo = enabledProviderInfo,
                  createOptionInfo = createOptionInfo,
                  onOptionSelected = {
                    onOptionSelected(ActiveEntry(providerInfo, createOptionInfo))
                    onOptionSelected(ActiveEntry(enabledProviderInfo, createOptionInfo))
                  })
              }
            }
          }
          item {
            MoreOptionsDisabledProvidersRow(
              disabledProviders = disabledProviderList,
              onDisabledPasswordManagerSelected = onDisabledPasswordManagerSelected,
            )
          }
        }
      }
      Divider(
@@ -276,7 +287,7 @@ fun MoreOptionsSelectionCard(
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MoreOptionsRowIntroCard(
  providerInfo: ProviderInfo,
  providerInfo: EnabledProviderInfo,
  onDefaultOrNotSelected: () -> Unit,
) {
  Card() {
@@ -483,7 +494,7 @@ fun PrimaryCreateOptionRow(
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MoreOptionsInfoRow(
  providerInfo: ProviderInfo,
  providerInfo: EnabledProviderInfo,
  createOptionInfo: CreateOptionInfo,
  onOptionSelected: () -> Unit
) {
@@ -547,3 +558,36 @@ fun MoreOptionsInfoRow(
        }
    )
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MoreOptionsDisabledProvidersRow(
  disabledProviders: List<ProviderInfo>,
  onDisabledPasswordManagerSelected: () -> Unit,
) {
  SuggestionChip(
    modifier = Modifier.fillMaxWidth(),
    onClick = onDisabledPasswordManagerSelected,
    icon = {
      Icon(
        Icons.Filled.Add,
        contentDescription = null
      )
    },
    shape = MaterialTheme.shapes.large,
    label = {
      Column() {
        Text(
          text = stringResource(R.string.other_password_manager),
          style = MaterialTheme.typography.titleLarge,
          modifier = Modifier.padding(top = 16.dp)
        )
        Text(
          text = disabledProviders.joinToString(separator = ", "){ it.displayName },
          style = MaterialTheme.typography.bodyMedium,
          modifier = Modifier.padding(bottom = 16.dp)
        )
      }
    }
  )
}
 No newline at end of file
Loading