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

Commit 594e4c3b authored by Helen Qin's avatar Helen Qin
Browse files

Add remote entry for get flow.

Screenshot: https://screenshot.googleplex.com/B6bf2UiuJaDinzs

Bug: 253157237
Test: Local Deployment
Change-Id: I341642a162a5c007de9d3a2f9fbfab119b1f1e1d
parent ae64ee70
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -62,4 +62,8 @@
  <string name="locked_credential_entry_label_subtext">Tap to unlock</string>
  <!-- Column heading for displaying action chips for managing sign-ins from each credential provider. [CHAR LIMIT=80] -->
  <string name="get_dialog_heading_manage_sign_ins">Manage sign-ins</string>
  <!-- Column heading for displaying option to use sign-ins saved on a different device. [CHAR LIMIT=80] -->
  <string name="get_dialog_heading_from_another_device">From another device</string>
  <!-- Headline text for an option to use sign-ins saved on a different device. [CHAR LIMIT=120] -->
  <string name="get_dialog_option_headline_use_a_different_device">Use a different device</string>
</resources>
 No newline at end of file
+3 −1
Original line number Diff line number Diff line
@@ -194,7 +194,7 @@ class CredentialManagerRepo(
          )
        )
        .setRemoteEntry(
          newRemoteEntry("key1", "subkey-1")
          newRemoteEntry("key2", "subkey-1")
        )
        .setIsDefaultProvider(true)
        .build(),
@@ -252,6 +252,8 @@ class CredentialManagerRepo(
              "Open Google Password Manager", "beckett-family@gmail.com"
            ),
          )
        ).setRemoteEntry(
          newRemoteEntry("key4", "subkey-1")
        ).build(),
      GetCredentialProviderData.Builder("com.dashlane")
        .setCredentialEntries(
+18 −4
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import com.android.credentialmanager.getflow.ActionEntryInfo
import com.android.credentialmanager.getflow.AuthenticationEntryInfo
import com.android.credentialmanager.getflow.CredentialEntryInfo
import com.android.credentialmanager.getflow.ProviderInfo
import com.android.credentialmanager.getflow.RemoteEntryInfo
import com.android.credentialmanager.jetpack.provider.ActionUi
import com.android.credentialmanager.jetpack.provider.CredentialEntryUi
import com.android.credentialmanager.jetpack.provider.SaveEntryUi
@@ -63,6 +64,7 @@ class GetFlowUtils {
            providerDisplayName,
            providerIcon,
            it.authenticationEntry),
          remoteEntry = getRemoteEntry(it.providerFlattenedComponentName, it.remoteEntry),
          actionEntryList = getActionEntryList(
            it.providerFlattenedComponentName, it.actionChips, context),
        )
@@ -116,6 +118,18 @@ class GetFlowUtils {
      )
    }

    private fun getRemoteEntry(providerId: String, remoteEntry: Entry?): RemoteEntryInfo? {
      // TODO: should also call fromSlice after getting the official jetpack code.
      if (remoteEntry == null) {
        return null
      }
      return RemoteEntryInfo(
        providerId = providerId,
        entryKey = remoteEntry.key,
        entrySubkey = remoteEntry.subkey,
      )
    }

    private fun getActionEntryList(
      providerId: String,
      actionEntries: List<Entry>,
+55 −4
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
@@ -220,16 +221,25 @@ fun AllSignInOptionCard(
            )
          }
          // Locked password manager
          item {
          if (!authenticationEntryList.isEmpty()) {
            item {
              LockedCredentials(
                authenticationEntryList = authenticationEntryList,
                onEntrySelected = onEntrySelected,
              )
            }
          }
          // TODO: Remote action
          // Manage sign-ins
          // From another device
          val remoteEntry = providerDisplayInfo.remoteEntry
          if (remoteEntry != null) {
            item {
              RemoteEntryCard(
                remoteEntry = remoteEntry,
                onEntrySelected = onEntrySelected,
              )
            }
          }
          // Manage sign-ins (action chips)
          item {
            ActionChips(providerInfoList = providerInfoList, onEntrySelected = onEntrySelected)
          }
@@ -270,6 +280,47 @@ fun ActionChips(
  }
}

@Composable
fun RemoteEntryCard(
  remoteEntry: RemoteEntryInfo,
  onEntrySelected: (EntryInfo) -> Unit,
) {
  Text(
    text = stringResource(R.string.get_dialog_heading_from_another_device),
    style = MaterialTheme.typography.labelLarge,
    modifier = Modifier.padding(vertical = 8.dp)
  )
  Card(
    modifier = Modifier.fillMaxWidth().wrapContentHeight(),
    shape = MaterialTheme.shapes.medium,
  ) {
    Column(
      modifier = Modifier.fillMaxWidth().wrapContentHeight(),
      verticalArrangement = Arrangement.spacedBy(2.dp),
    ) {
      Entry(
        onClick = {onEntrySelected(remoteEntry)},
        icon = {
          Icon(
            painter = painterResource(R.drawable.ic_other_devices),
            contentDescription = null,
            tint = Color.Unspecified,
            modifier = Modifier.padding(start = 18.dp)
          )
        },
        label = {
          Text(
            text = stringResource(R.string.get_dialog_option_headline_use_a_different_device),
            style = MaterialTheme.typography.titleLarge,
            modifier = Modifier.padding(start = 16.dp, top = 18.dp, bottom = 18.dp)
              .align(alignment = Alignment.CenterHorizontally)
          )
        }
      )
    }
  }
}

@Composable
fun LockedCredentials(
  authenticationEntryList: List<AuthenticationEntryInfo>,
+9 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import com.android.credentialmanager.CredentialManagerRepo
import com.android.credentialmanager.common.DialogResult
import com.android.credentialmanager.common.ResultState
import com.android.credentialmanager.jetpack.developer.PublicKeyCredential
import com.android.internal.util.Preconditions

data class GetCredentialUiState(
  val providerInfoList: List<ProviderInfo>,
@@ -86,10 +87,14 @@ private fun toProviderDisplayInfo(

  val userNameToCredentialEntryMap = mutableMapOf<String, MutableList<CredentialEntryInfo>>()
  val authenticationEntryList = mutableListOf<AuthenticationEntryInfo>()
  val remoteEntryList = mutableListOf<RemoteEntryInfo>()
  providerInfoList.forEach { providerInfo ->
    if (providerInfo.authenticationEntry != null) {
      authenticationEntryList.add(providerInfo.authenticationEntry)
    }
    if (providerInfo.remoteEntry != null) {
      remoteEntryList.add(providerInfo.remoteEntry)
    }

    providerInfo.credentialEntryList.forEach {
      userNameToCredentialEntryMap.compute(
@@ -105,6 +110,9 @@ private fun toProviderDisplayInfo(
      }
    }
  }
  // There can only be at most one remote entry
  // TODO: fail elegantly
  Preconditions.checkState(remoteEntryList.size <= 1)

  // Compose sortedUserNameToCredentialEntryList
  val comparator = CredentialEntryInfoComparator()
@@ -122,6 +130,7 @@ private fun toProviderDisplayInfo(
  return ProviderDisplayInfo(
    sortedUserNameToCredentialEntryList = sortedUserNameToCredentialEntryList,
    authenticationEntryList = authenticationEntryList,
    remoteEntry = remoteEntryList.getOrNull(0),
  )
}

Loading