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

Commit 6621e3ef authored by Qinmei Du's avatar Qinmei Du
Browse files

Update UX according to the new design

Except getting the newest design of the dialog, also fix the following
know issue:

1. Weired padding in passkey intro screen
2. Make icons fall back to unknown sign-ins icon for credential entries
   in get flow
3. Icons only get tint color when it's type icons
4. Only show total credentials count for create other sign-in
5. Update the structure in view model to make repos not communicating
   with each other

screencast:
create flow(https://drive.google.com/file/d/1heq4LUTIC4Vg_-4FwZyzGRdCiK2RPXAV/view?usp=sharing&resourcekey=0-JAEDodT7zDKXfKeLJmEO6Q )
get flow(https://drive.google.com/file/d/12o197YBJgJjcAeIHFzvJ0z7C8iRWXX3M/view?usp=sharing&resourcekey=0-B-HOKUpLSe3lTsv0GHdYgQ )

Test: deployed locally

Bug: 261060321
Change-Id: I9dd3cac0e0e3db41e5e812331bc3662cf91b3322
parent 4b07f0a7
Loading
Loading
Loading
Loading
+0 −11
Original line number Diff line number Diff line
<vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt"
        android:viewportWidth="46"
        android:viewportHeight="46"
        android:width="46dp"
        android:height="46dp">
    <path
        android:pathData="M45.4247 22.9953C45.4247 35.0229 35.4133 44.7953 23.0359 44.7953C10.6585 44.7953 0.646973 35.0229 0.646973 22.9953C0.646973 10.9677 10.6585 1.19531 23.0359 1.19531C35.4133 1.19531 45.4247 10.9677 45.4247 22.9953Z"
        android:strokeColor="#202124"
        android:strokeAlpha="0.13"
        android:strokeWidth="1" />
</vector>
 No newline at end of file
+18 −17
Original line number Diff line number Diff line
@@ -9,6 +9,8 @@
  <string name="string_cancel">Cancel</string>
  <!-- Button label to confirm choosing the default dialog information and continue. [CHAR LIMIT=40] -->
  <string name="string_continue">Continue</string>
  <!-- Button label to create this credential in other available places. [CHAR LIMIT=40] -->
  <string name="string_more_options">More options</string>
  <!-- This appears as a text button where users can click to create this passkey in other available places. [CHAR LIMIT=80] -->
  <string name="string_create_in_another_place">Create in another place</string>
  <!-- This appears as a text button where users can click to create this password or other credential types in other available places. [CHAR LIMIT=80] -->
@@ -20,11 +22,11 @@
  <!-- This appears as the title of the modal bottom sheet introducing what is passkey to users. [CHAR LIMIT=200] -->
  <string name="passkey_creation_intro_title">Safer with passkeys</string>
  <!-- This appears as the description body of the modal bottom sheet introducing why passkey beneficial on the passwords side. [CHAR LIMIT=200] -->
  <string name="passkey_creation_intro_body_password">No need to create or remember complex passwords</string>
  <string name="passkey_creation_intro_body_password">With passkeys, you don’t need to create or remember complex passwords</string>
  <!-- This appears as the description body of the modal bottom sheet introducing why passkey beneficial on the safety side. [CHAR LIMIT=200] -->
  <string name="passkey_creation_intro_body_fingerprint">Use your fingerprint, face, or screen lock to create a unique passkey</string>
  <string name="passkey_creation_intro_body_fingerprint">Passkeys are encrypted digital keys you create using your fingerprint, face, or screen lock</string>
  <!-- This appears as the description body of the modal bottom sheet introducing why passkey beneficial on the using other devices side. [CHAR LIMIT=200] -->
  <string name="passkey_creation_intro_body_device">Passkeys are saved to a password manager, so you can sign in on other devices</string>
  <string name="passkey_creation_intro_body_device">They are saved to a password manager, so you can sign in on other devices</string>
  <!-- This appears as the title of the modal bottom sheet which provides all available providers for users to choose. [CHAR LIMIT=200] -->
  <string name="choose_provider_title">Choose where to <xliff:g id="createTypes" example="create your passkeys">%1$s</xliff:g></string>
  <!-- Create types which are inserted as a placeholder for string choose_provider_title. [CHAR LIMIT=200] -->
@@ -33,26 +35,23 @@
  <string name="save_your_sign_in_info">save your sign-in info</string>

  <!-- This appears as the description body of the modal bottom sheet which provides all available providers for users to choose. [CHAR LIMIT=200] -->
  <string name="choose_provider_body">Set a default password manager to save your passwords and passkeys and sign in faster next time.</string>
  <string name="choose_provider_body">Select a password manager to save your info and sign in faster next time.</string>
  <!-- This appears as the title of the modal bottom sheet for users to choose the create option inside a provider when the credential type is passkey. [CHAR LIMIT=200] -->
  <string name="choose_create_option_passkey_title">Create a passkey in <xliff:g id="providerInfoDisplayName" example="Google Password Manager">%1$s</xliff:g>?</string>
  <string name="choose_create_option_passkey_title">Create passkey for <xliff:g id="appName" example="Tribank">%1$s</xliff:g>?</string>
  <!-- This appears as the title of the modal bottom sheet for users to choose the create option inside a provider when the credential type is password. [CHAR LIMIT=200] -->
  <string name="choose_create_option_password_title">Save your password to <xliff:g id="providerInfoDisplayName" example="Google Password Manager">%1$s</xliff:g>?</string>
  <string name="choose_create_option_password_title">Save password for <xliff:g id="appName" example="Tribank">%1$s</xliff:g>?</string>
  <!-- This appears as the title of the modal bottom sheet for users to choose the create option inside a provider when the credential type is others. [CHAR LIMIT=200] -->
  <string name="choose_create_option_sign_in_title">Save your sign-in info to <xliff:g id="providerInfoDisplayName" example="Google Password Manager">%1$s</xliff:g>?</string>
  <string name="choose_create_option_sign_in_title">Save sign-in info for <xliff:g id="appName" example="Tribank">%1$s</xliff:g>?</string>
  <!-- This appears as the description body of the modal bottom sheet for users to choose the create option inside a provider. [CHAR LIMIT=200] -->
  <string name="choose_create_option_description">You can use your <xliff:g id="appDomainName" example="Tribank">%1$s</xliff:g> <xliff:g id="type" example="passkey">%2$s</xliff:g> on any device. It is saved to <xliff:g id="providerInfoDisplayName" example="Google Password Manager">%3$s</xliff:g> for <xliff:g id="createInfoDisplayName" example="elisa.beckett@gmail.com">%4$s</xliff:g></string>
  <!-- Types which are inserted as a placeholder for string choose_create_option_description. [CHAR LIMIT=200] -->
  <string name="choose_create_option_description">You can use your <xliff:g id="appDomainName" example="Tribank">%1$s</xliff:g> <xliff:g id="credentialTypes" example="passkey">%2$s</xliff:g> on any device. It is saved to <xliff:g id="providerInfoDisplayName" example="Google Password Manager">%3$s</xliff:g> for <xliff:g id="createInfoDisplayName" example="elisa.beckett@gmail.com">%4$s</xliff:g>.</string>
  <!-- Types which are inserted as a placeholder as credentialTypes for other strings. [CHAR LIMIT=200] -->
  <string name="passkey">passkey</string>
  <string name="password">password</string>
  <string name="sign_ins">sign-ins</string>
  <string name="sign_in_info">sign-in info</string>

  <!-- This appears as the title of the modal bottom sheet for users to choose other available places the created passkey can be created to. [CHAR LIMIT=200] -->
  <string name="create_passkey_in_title">Create passkey in</string>
  <!-- This appears as the title of the modal bottom sheet for users to choose other available places the created password can be saved to. [CHAR LIMIT=200] -->
  <string name="save_password_to_title">Save password to</string>
  <!-- This appears as the title of the modal bottom sheet for users to choose other available places the created other credential types can be saved to. [CHAR LIMIT=200] -->
  <string name="save_sign_in_to_title">Save sign-in to</string>
  <string name="save_credential_to_title">Save <xliff:g id="credentialTypes" example="passkey">%1$s</xliff:g> to</string>
  <!-- This appears as the title of the modal bottom sheet for users to choose to create a passkey on another device. [CHAR LIMIT=200] -->
  <string name="create_passkey_in_other_device_title">Create a passkey in another device?</string>
  <!-- This appears as the title of the modal bottom sheet for users to confirm whether they should use the selected provider as default or not. [CHAR LIMIT=200] -->
@@ -65,11 +64,13 @@
  <!-- Button label to set the selected provider on the modal bottom sheet not as default but just use once. [CHAR LIMIT=40] -->
  <string name="use_once">Use once</string>
  <!-- Appears as an option row subtitle to show how many passwords and passkeys are saved in this option when there are passwords and passkeys. [CHAR LIMIT=80] -->
  <string name="more_options_usage_passwords_passkeys"><xliff:g id="passwordsNumber" example="1">%1$s</xliff:g> passwords, <xliff:g id="passkeysNumber" example="2">%2$s</xliff:g> passkeys</string>
  <string name="more_options_usage_passwords_passkeys"><xliff:g id="passwordsNumber" example="1">%1$s</xliff:g> passwords <xliff:g id="passkeysNumber" example="2">%2$s</xliff:g> passkeys</string>
  <!-- Appears as an option row subtitle to show how many passwords and passkeys are saved in this option when there are only passwords. [CHAR LIMIT=80] -->
  <string name="more_options_usage_passwords"><xliff:g id="passwordsNumber" example="3">%1$s</xliff:g> passwords</string>
  <!-- Appears as an option row subtitle to show how many passwords and passkeys are saved in this option when there are only passkeys. [CHAR LIMIT=80] -->
  <string name="more_options_usage_passkeys"><xliff:g id="passkeysNumber" example="4">%1$s</xliff:g> passkeys</string>
  <!-- Appears as an option row subtitle to show how many total credentials are saved in this option when the request type is other sign-ins. [CHAR LIMIT=80] -->
  <string name="more_options_usage_credentials"><xliff:g id="totalCredentialsNumber" example="5">%1$s</xliff:g> credentials</string>
  <!-- Appears before a request display name when the credential type is passkey . [CHAR LIMIT=80] -->
  <string name="passkey_before_subtitle">Passkey</string>
  <!-- Appears as an option row title that users can choose to use another device for this creation. [CHAR LIMIT=80] -->
@@ -92,8 +93,8 @@
  <string name="get_dialog_title_choose_sign_in_for">Choose a saved sign-in for <xliff:g id="app_name" example="YouTube">%1$s</xliff:g></string>
  <!-- Appears as an option row for viewing all the available sign-in options. [CHAR LIMIT=80] -->
  <string name="get_dialog_use_saved_passkey_for">Sign in another way</string>
  <!-- Button label to close the dialog when the user does not want to use any sign-in. [CHAR LIMIT=40] -->
  <string name="get_dialog_button_label_no_thanks">No thanks</string>
  <!-- Appears as a text button in the snackbar for users to click to view all options. [CHAR LIMIT=80] -->
  <string name="snackbar_action">View options</string>
  <!-- Button label to continue with the selected sign-in. [CHAR LIMIT=40] -->
  <string name="get_dialog_button_label_continue">Continue</string>
  <!-- Separator for sign-in type and username in a sign-in entry. -->
+47 −42
Original line number Diff line number Diff line
@@ -36,13 +36,14 @@ import android.credentials.ui.RequestInfo
import android.credentials.ui.BaseDialogResult
import android.credentials.ui.ProviderPendingIntentResponse
import android.credentials.ui.UserSelectionDialogResult
import android.graphics.drawable.Icon
import android.os.Binder
import android.os.Bundle
import android.os.ResultReceiver
import android.service.credentials.CredentialProviderService
import android.util.ArraySet
import com.android.credentialmanager.createflow.CreateCredentialUiState
import com.android.credentialmanager.createflow.RequestDisplayInfo
import com.android.credentialmanager.createflow.EnabledProviderInfo
import com.android.credentialmanager.createflow.DisabledProviderInfo
import com.android.credentialmanager.getflow.GetCredentialUiState
import com.android.credentialmanager.jetpack.developer.CreatePasswordRequest.Companion.toBundle
import com.android.credentialmanager.jetpack.developer.CreatePublicKeyCredentialRequest
@@ -67,7 +68,7 @@ class CredentialManagerRepo(
    requestInfo = intent.extras?.getParcelable(
      RequestInfo.EXTRA_REQUEST_INFO,
      RequestInfo::class.java
    ) ?: testGetRequestInfo()
    ) ?: testCreatePasskeyRequestInfo()

    providerEnabledList = when (requestInfo.type) {
      RequestInfo.TYPE_CREATE ->
@@ -134,19 +135,24 @@ class CredentialManagerRepo(
    )
  }

  fun createCredentialInitialUiState(): CreateCredentialUiState {
    val requestDisplayInfo = CreateFlowUtils.toRequestDisplayInfo(requestInfo, context)
  fun getCreateProviderEnableListInitialUiState(): List<EnabledProviderInfo> {
    val providerEnabledList = CreateFlowUtils.toEnabledProviderList(
      // Handle runtime cast error
      providerEnabledList as List<CreateCredentialProviderData>, requestDisplayInfo, context)
    val providerDisabledList = CreateFlowUtils.toDisabledProviderList(
      // Handle runtime cast error
      providerDisabledList, context)
      providerEnabledList as List<CreateCredentialProviderData>, context)
    providerEnabledList.forEach{providerInfo -> providerInfo.createOptions =
      providerInfo.createOptions.sortedWith(compareBy { it.lastUsedTimeMillis }).reversed()
    }
    return CreateFlowUtils.toCreateCredentialUiState(
      providerEnabledList, providerDisabledList, requestDisplayInfo, false)
    return providerEnabledList
  }

  fun getCreateProviderDisableListInitialUiState(): List<DisabledProviderInfo>? {
    return CreateFlowUtils.toDisabledProviderList(
      // Handle runtime cast error
      providerDisabledList, context)
  }

  fun getCreateRequestDisplayInfoInitialUiState(): RequestDisplayInfo {
    return CreateFlowUtils.toRequestDisplayInfo(requestInfo, context)
  }

  companion object {
@@ -312,8 +318,7 @@ class CredentialManagerRepo(

        val credentialEntry = CredentialEntry(credentialType, credentialTypeDisplayName, userName,
                userDisplayName, pendingIntent, lastUsedTimeMillis
                ?: 0L, Icon.createWithResource(context, R.drawable.ic_passkey),
                false)
                ?: 0L, null, false)

        return Entry(
                key,
@@ -351,7 +356,7 @@ class CredentialManagerRepo(

        val createEntry = CreateEntry(
                providerDisplayName, pendingIntent,
                Icon.createWithResource(context, R.drawable.ic_profile), lastUsedTimeMillis,
                null, lastUsedTimeMillis,
                listOf(
                        CredentialCountInformation.createPasswordCountInformation(passwordCount),
                        CredentialCountInformation.createPublicKeyCountInformation(passkeyCount),
+20 −17
Original line number Diff line number Diff line
@@ -123,8 +123,7 @@ class GetFlowUtils {
          userName = credentialEntry.username.toString(),
          displayName = credentialEntry.displayName?.toString(),
          // TODO: proper fallback
          icon = credentialEntry.icon?.loadDrawable(context)
                  ?: context.getDrawable(R.drawable.ic_other_sign_in)!!,
          icon = credentialEntry.icon?.loadDrawable(context),
          lastUsedTimeMillis = credentialEntry.lastUsedTimeMillis,
        )
      }
@@ -196,9 +195,8 @@ class CreateFlowUtils {

    fun toEnabledProviderList(
      providerDataList: List<CreateCredentialProviderData>,
      requestDisplayInfo: RequestDisplayInfo,
      context: Context,
    ): List<com.android.credentialmanager.createflow.EnabledProviderInfo> {
    ): List<EnabledProviderInfo> {
      // TODO: get from the actual service info
      val packageManager = context.packageManager

@@ -219,7 +217,7 @@ class CreateFlowUtils {
          name = it.providerFlattenedComponentName,
          displayName = pkgInfo.applicationInfo.loadLabel(packageManager).toString(),
          createOptions = toCreationOptionInfoList(
            it.providerFlattenedComponentName, it.saveEntries, requestDisplayInfo, context),
            it.providerFlattenedComponentName, it.saveEntries, context),
          remoteEntry = toRemoteInfo(it.providerFlattenedComponentName, it.remoteEntry),
        )
      }
@@ -228,14 +226,14 @@ class CreateFlowUtils {
    fun toDisabledProviderList(
      providerDataList: List<DisabledProviderData>?,
      context: Context,
    ): List<com.android.credentialmanager.createflow.DisabledProviderInfo>? {
    ): List<DisabledProviderInfo>? {
      // TODO: get from the actual service info
      val packageManager = context.packageManager
      return providerDataList?.map {
        val pkgInfo = packageManager
          .getPackageInfo(it.providerFlattenedComponentName,
            PackageManager.PackageInfoFlags.of(0))
        com.android.credentialmanager.createflow.DisabledProviderInfo(
        DisabledProviderInfo(
          icon = pkgInfo.applicationInfo.loadIcon(packageManager)!!,
          name = it.providerFlattenedComponentName,
          displayName = pkgInfo.applicationInfo.loadLabel(packageManager).toString(),
@@ -295,14 +293,15 @@ class CreateFlowUtils {
    fun toCreateCredentialUiState(
      enabledProviders: List<EnabledProviderInfo>,
      disabledProviders: List<DisabledProviderInfo>?,
      defaultProviderId: String?,
      requestDisplayInfo: RequestDisplayInfo,
      isOnPasskeyIntroStateAlready: Boolean,
      isPasskeyFirstUse: Boolean,
    ): CreateCredentialUiState {
      var createOptionSize = 0
      var lastSeenProviderWithNonEmptyCreateOptions: EnabledProviderInfo? = null
      var remoteEntry: RemoteInfo? = null
      var defaultProvider: EnabledProviderInfo? = null
      val defaultProviderId = UserConfigRepo.getInstance().getDefaultProviderId()
      enabledProviders.forEach {
          enabledProvider ->
        if (defaultProviderId != null) {
@@ -322,13 +321,18 @@ class CreateFlowUtils {
        enabledProviders = enabledProviders,
        disabledProviders = disabledProviders,
        toCreateScreenState(
          createOptionSize, isOnPasskeyIntroStateAlready,
          requestDisplayInfo, defaultProvider, remoteEntry),
          /*createOptionSize=*/createOptionSize,
          /*isOnPasskeyIntroStateAlready=*/isOnPasskeyIntroStateAlready,
          /*requestDisplayInfo=*/requestDisplayInfo,
          /*defaultProvider=*/defaultProvider, /*remoteEntry=*/remoteEntry,
          /*isPasskeyFirstUse=*/isPasskeyFirstUse),
        requestDisplayInfo,
        isOnPasskeyIntroStateAlready,
        defaultProvider != null,
        toActiveEntry(
          /*defaultProvider=*/defaultProvider, createOptionSize,
          lastSeenProviderWithNonEmptyCreateOptions, remoteEntry),
          /*defaultProvider=*/defaultProvider,
          /*createOptionSize=*/createOptionSize,
          /*lastSeenProviderWithNonEmptyCreateOptions=*/lastSeenProviderWithNonEmptyCreateOptions,
          /*remoteEntry=*/remoteEntry),
      )
    }

@@ -338,9 +342,10 @@ class CreateFlowUtils {
      requestDisplayInfo: RequestDisplayInfo,
      defaultProvider: EnabledProviderInfo?,
      remoteEntry: RemoteInfo?,
      isPasskeyFirstUse: Boolean,
    ): CreateScreenState {
      return if (
        UserConfigRepo.getInstance().getIsFirstUse() && requestDisplayInfo
        isPasskeyFirstUse && requestDisplayInfo
          .type == TYPE_PUBLIC_KEY_CREDENTIAL && !isOnPasskeyIntroStateAlready) {
        CreateScreenState.PASSKEY_INTRO
      } else if (
@@ -382,7 +387,6 @@ class CreateFlowUtils {
    private fun toCreationOptionInfoList(
      providerId: String,
      creationEntries: List<Entry>,
      requestDisplayInfo: RequestDisplayInfo,
      context: Context,
    ): List<CreateOptionInfo> {
      return creationEntries.map {
@@ -397,8 +401,7 @@ class CreateFlowUtils {
          pendingIntent = it.pendingIntent,
          fillInIntent = it.frameworkExtrasIntent,
          userProviderDisplayName = createEntry.accountName.toString(),
          profileIcon = createEntry.icon?.loadDrawable(context)
                  ?: requestDisplayInfo.typeIcon,
          profileIcon = createEntry.icon?.loadDrawable(context),
          passwordCount = CredentialCountInformation.getPasswordCount(
                  createEntry.credentialCountInformationList) ?: 0,
          passkeyCount = CredentialCountInformation.getPasskeyCount(
+2 −2
Original line number Diff line number Diff line
@@ -32,7 +32,7 @@ class UserConfigRepo(context: Context) {
        }
    }

    fun setIsFirstUse(
    fun setIsPasskeyFirstUse(
        isFirstUse: Boolean
    ) {
        sharedPreferences.edit().apply {
@@ -45,7 +45,7 @@ class UserConfigRepo(context: Context) {
        return sharedPreferences.getString(DEFAULT_PROVIDER, null)
    }

    fun getIsFirstUse(): Boolean {
    fun getIsPasskeyFirstUse(): Boolean {
        return sharedPreferences.getBoolean(IS_PASSKEY_FIRST_USE, true)
    }

Loading