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

Commit 0c1fb3ca authored by Helen Qin's avatar Helen Qin Committed by Android (Google) Code Review
Browse files

Merge "Support locked entries and action chips for the get flow."

parents 31039711 4d1312b2
Loading
Loading
Loading
Loading
+30 −0
Original line number Diff line number Diff line
<!--
  ~ Copyright (C) 2022 The Android Open Source Project
  ~
  ~ Licensed under the Apache License, Version 2.0 (the "License");
  ~ you may not use this file except in compliance with the License.
  ~ You may obtain a copy of the License at
  ~
  ~      http://www.apache.org/licenses/LICENSE-2.0
  ~
  ~ Unless required by applicable law or agreed to in writing, software
  ~ distributed under the License is distributed on an "AS IS" BASIS,
  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  ~ See the License for the specific language governing permissions and
  ~ limitations under the License.
  -->

<!--TODO: Testing only icon. Remove later. -->

<vector xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        tools:ignore="VectorPath"
        android:width="24dp"
        android:height="24dp"
        android:viewportWidth="24"
        android:viewportHeight="24"
        android:tint="?attr/colorControlNormal">
    <path
        android:fillColor="#808080"
        android:pathData="M9.025,14.275Q8.5,14.275 8.125,13.9Q7.75,13.525 7.75,13Q7.75,12.475 8.125,12.1Q8.5,11.725 9.025,11.725Q9.575,11.725 9.938,12.1Q10.3,12.475 10.3,13Q10.3,13.525 9.938,13.9Q9.575,14.275 9.025,14.275ZM14.975,14.275Q14.425,14.275 14.062,13.9Q13.7,13.525 13.7,13Q13.7,12.475 14.062,12.1Q14.425,11.725 14.975,11.725Q15.5,11.725 15.875,12.1Q16.25,12.475 16.25,13Q16.25,13.525 15.875,13.9Q15.5,14.275 14.975,14.275ZM12,19.925Q15.325,19.925 17.625,17.625Q19.925,15.325 19.925,12Q19.925,11.4 19.85,10.85Q19.775,10.3 19.575,9.775Q19.05,9.9 18.538,9.962Q18.025,10.025 17.45,10.025Q15.2,10.025 13.188,9.062Q11.175,8.1 9.775,6.375Q8.975,8.3 7.5,9.712Q6.025,11.125 4.075,11.85Q4.075,11.9 4.075,11.925Q4.075,11.95 4.075,12Q4.075,15.325 6.375,17.625Q8.675,19.925 12,19.925ZM12,22.2Q9.9,22.2 8.038,21.4Q6.175,20.6 4.788,19.225Q3.4,17.85 2.6,15.988Q1.8,14.125 1.8,12Q1.8,9.875 2.6,8.012Q3.4,6.15 4.788,4.775Q6.175,3.4 8.038,2.6Q9.9,1.8 12,1.8Q14.125,1.8 15.988,2.6Q17.85,3.4 19.225,4.775Q20.6,6.15 21.4,8.012Q22.2,9.875 22.2,12Q22.2,14.125 21.4,15.988Q20.6,17.85 19.225,19.225Q17.85,20.6 15.988,21.4Q14.125,22.2 12,22.2Z"/>
</vector>
 No newline at end of file
+30 −0
Original line number Diff line number Diff line
<!--
  ~ Copyright (C) 2022 The Android Open Source Project
  ~
  ~ Licensed under the Apache License, Version 2.0 (the "License");
  ~ you may not use this file except in compliance with the License.
  ~ You may obtain a copy of the License at
  ~
  ~      http://www.apache.org/licenses/LICENSE-2.0
  ~
  ~ Unless required by applicable law or agreed to in writing, software
  ~ distributed under the License is distributed on an "AS IS" BASIS,
  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  ~ See the License for the specific language governing permissions and
  ~ limitations under the License.
  -->

<!--TODO: Testing only icon. Remove later. -->

<vector xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        tools:ignore="VectorPath"
        android:width="24dp"
        android:height="24dp"
        android:viewportWidth="24"
        android:viewportHeight="24"
        android:tint="?attr/colorControlNormal">
    <path
        android:fillColor="#808080"
        android:pathData="M16.1,21.2 L15.775,19.675Q15.5,19.55 15.25,19.425Q15,19.3 14.75,19.1L13.275,19.575L12.2,17.75L13.375,16.725Q13.325,16.4 13.325,16.112Q13.325,15.825 13.375,15.5L12.2,14.475L13.275,12.65L14.75,13.1Q15,12.925 15.25,12.787Q15.5,12.65 15.775,12.55L16.1,11.025H18.25L18.55,12.55Q18.825,12.65 19.075,12.8Q19.325,12.95 19.575,13.15L21.05,12.65L22.125,14.525L20.95,15.55Q21.025,15.825 21.013,16.137Q21,16.45 20.95,16.725L22.125,17.75L21.05,19.575L19.575,19.1Q19.325,19.3 19.075,19.425Q18.825,19.55 18.55,19.675L18.25,21.2ZM1.8,20.3V17.3Q1.8,16.375 2.275,15.613Q2.75,14.85 3.5,14.475Q4.775,13.825 6.425,13.362Q8.075,12.9 10,12.9Q10.2,12.9 10.4,12.9Q10.6,12.9 10.775,12.95Q9.925,14.85 10.062,16.738Q10.2,18.625 11.4,20.3ZM17.175,18.075Q17.975,18.075 18.55,17.487Q19.125,16.9 19.125,16.1Q19.125,15.3 18.55,14.725Q17.975,14.15 17.175,14.15Q16.375,14.15 15.788,14.725Q15.2,15.3 15.2,16.1Q15.2,16.9 15.788,17.487Q16.375,18.075 17.175,18.075ZM10,11.9Q8.25,11.9 7.025,10.662Q5.8,9.425 5.8,7.7Q5.8,5.95 7.025,4.725Q8.25,3.5 10,3.5Q11.75,3.5 12.975,4.725Q14.2,5.95 14.2,7.7Q14.2,9.425 12.975,10.662Q11.75,11.9 10,11.9Z"/>
</vector>
 No newline at end of file
+7 −1
Original line number Diff line number Diff line
@@ -54,6 +54,12 @@
  <string name="get_dialog_sign_in_type_username_separator" translatable="false">" - "</string>
  <!-- Modal bottom sheet title for displaying all the available sign-in options. [CHAR LIMIT=80] -->
  <string name="get_dialog_title_sign_in_options">Sign-in options</string>
  <!-- Column heading for displaying sign-ins for a specific username. [CHAR LIMIT=20] -->
  <!-- Column heading for displaying sign-ins for a specific username. [CHAR LIMIT=80] -->
  <string name="get_dialog_heading_for_username">For <xliff:g id="username" example="becket@gmail.com">%1$s</xliff:g></string>
  <!-- Column heading for displaying locked (that is, the user needs to first authenticate via pin, fingerprint, faceId, etc.) sign-ins. [CHAR LIMIT=80] -->
  <string name="get_dialog_heading_locked_password_managers">Locked password managers</string>
  <!-- Explanatory sub/body text for an option entry to use a locked (that is, the user needs to first authenticate via pin, fingerprint, faceId, etc.) sign-in. [CHAR LIMIT=120] -->
  <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>
</resources>
 No newline at end of file
+65 −2
Original line number Diff line number Diff line
@@ -209,7 +209,7 @@ class CredentialManagerRepo(

  private fun testGetCredentialProviderList(): List<GetCredentialProviderData> {
    return listOf(
      GetCredentialProviderData.Builder("com.google/com.google.CredentialManagerService")
      GetCredentialProviderData.Builder("io.enpass.app")
        .setCredentialEntries(
          listOf<Entry>(
            newGetEntry(
@@ -225,8 +225,23 @@ class CredentialManagerRepo(
              "elisa.family@outlook.com", null, 100L
            ),
          )
        ).setAuthenticationEntry(
          newAuthenticationEntry("key2", "subkey-1", TYPE_PASSWORD_CREDENTIAL)
        ).setActionChips(
          listOf(
            newActionEntry(
              "key3", "subkey-1", TYPE_PASSWORD_CREDENTIAL,
              Icon.createWithResource(context, R.drawable.ic_manage_accounts),
              "Open Google Password Manager", "elisa.beckett@gmail.com"
            ),
            newActionEntry(
              "key3", "subkey-2", TYPE_PASSWORD_CREDENTIAL,
              Icon.createWithResource(context, R.drawable.ic_manage_accounts),
              "Open Google Password Manager", "beckett-family@gmail.com"
            ),
          )
        ).build(),
      GetCredentialProviderData.Builder("com.dashlane/com.dashlane.CredentialManagerService")
      GetCredentialProviderData.Builder("com.dashlane")
        .setCredentialEntries(
          listOf<Entry>(
            newGetEntry(
@@ -238,10 +253,58 @@ class CredentialManagerRepo(
              "elisa.family@outlook.com", null, 100L
            ),
          )
        ).setAuthenticationEntry(
          newAuthenticationEntry("key2", "subkey-1", TYPE_PASSWORD_CREDENTIAL)
        ).setActionChips(
          listOf(
            newActionEntry(
              "key3", "subkey-1", TYPE_PASSWORD_CREDENTIAL,
              Icon.createWithResource(context, R.drawable.ic_face),
              "Open Enpass"
            ),
          )
        ).build(),
    )
  }

  private fun newActionEntry(
    key: String,
    subkey: String,
    credentialType: String,
    icon: Icon,
    text: String,
    subtext: String? = null,
  ): Entry {
    val slice = Slice.Builder(
      Entry.CREDENTIAL_MANAGER_ENTRY_URI, SliceSpec(credentialType, 1)
    ).addText(
      text, null, listOf(Entry.HINT_ACTION_TITLE)
    ).addIcon(icon, null, listOf(Entry.HINT_ACTION_ICON))
    if (subtext != null) {
      slice.addText(subtext, null, listOf(Entry.HINT_ACTION_SUBTEXT))
    }
    return Entry(
      key,
      subkey,
      slice.build()
    )
  }

  private fun newAuthenticationEntry(
    key: String,
    subkey: String,
    credentialType: String,
  ): Entry {
    val slice = Slice.Builder(
      Entry.CREDENTIAL_MANAGER_ENTRY_URI, SliceSpec(credentialType, 1)
    )
    return Entry(
      key,
      subkey,
      slice.build()
    )
  }

  private fun newGetEntry(
    key: String,
    subkey: String,
+47 −10
Original line number Diff line number Diff line
@@ -22,12 +22,14 @@ import android.credentials.ui.Entry
import android.credentials.ui.GetCredentialProviderData
import android.credentials.ui.CreateCredentialProviderData
import android.credentials.ui.DisabledProviderData
import android.graphics.drawable.Drawable
import com.android.credentialmanager.createflow.CreateOptionInfo
import com.android.credentialmanager.createflow.RemoteInfo
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.jetpack.provider.ActionUi
import com.android.credentialmanager.jetpack.provider.CredentialEntryUi
import com.android.credentialmanager.jetpack.provider.SaveEntryUi

@@ -39,17 +41,27 @@ class GetFlowUtils {
      providerDataList: List<GetCredentialProviderData>,
      context: Context,
    ): List<ProviderInfo> {
      val packageManager = context.packageManager
      return providerDataList.map {
        // TODO: get from the actual service info
        val pkgInfo = packageManager
          .getPackageInfo(it.providerFlattenedComponentName,
            PackageManager.PackageInfoFlags.of(0))
        val providerDisplayName = pkgInfo.applicationInfo.loadLabel(packageManager).toString()
        // TODO: decide what to do when failed to load a provider icon
        val providerIcon = pkgInfo.applicationInfo.loadIcon(packageManager)!!
        ProviderInfo(
          id = it.providerFlattenedComponentName,
          // TODO: replace to extract from the service data structure when available
          icon = context.getDrawable(R.drawable.ic_passkey)!!,
          // TODO: get the service display name and icon from the component name.
          displayName = it.providerFlattenedComponentName,
          // TODO: decide what to do when failed to load a provider icon
          icon = providerIcon,
          displayName = providerDisplayName,
          credentialEntryList = getCredentialOptionInfoList(
            it.providerFlattenedComponentName, it.credentialEntries, context),
          authenticationEntry = getAuthenticationEntry(
            it.providerFlattenedComponentName, it.authenticationEntry, context),
              it.providerFlattenedComponentName,
              providerDisplayName,
              providerIcon,
              it.authenticationEntry),
          actionEntryList = getActionEntryList(
            it.providerFlattenedComponentName, it.actionChips, context),
        )
@@ -85,20 +97,42 @@ class GetFlowUtils {

    private fun getAuthenticationEntry(
      providerId: String,
      providerDisplayName: String,
      providerIcon: Drawable,
      authEntry: Entry?,
      context: Context,
    ): AuthenticationEntryInfo? {
      // TODO: implement
      // TODO: should also call fromSlice after getting the official jetpack code.

      if (authEntry == null) {
        return null
      }
      return AuthenticationEntryInfo(
        providerId = providerId,
        entryKey = authEntry.key,
        entrySubkey = authEntry.subkey,
        title = providerDisplayName,
        icon = providerIcon,
      )
    }

    private fun getActionEntryList(
      providerId: String,
      actionEntries: List<Entry>,
      context: Context,
    ): List<ActionEntryInfo> {
      // TODO: implement
      return emptyList()
      return actionEntries.map {
        val actionEntryUi = ActionUi.fromSlice(it.slice)

        return@map ActionEntryInfo(
          providerId = providerId,
          entryKey = it.key,
          entrySubkey = it.subkey,
          title = actionEntryUi.text.toString(),
          // TODO: gracefully fail
          icon = actionEntryUi.icon.loadDrawable(context)!!,
          subTitle = actionEntryUi.subtext?.toString(),
        )
      }
    }
  }
}
@@ -110,12 +144,14 @@ class CreateFlowUtils {
      providerDataList: List<CreateCredentialProviderData>,
      context: Context,
    ): List<com.android.credentialmanager.createflow.EnabledProviderInfo> {
      // 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.EnabledProviderInfo(
          // TODO: decide what to do when failed to load a provider icon
          icon = pkgInfo.applicationInfo.loadIcon(packageManager)!!,
          name = it.providerFlattenedComponentName,
          displayName = pkgInfo.applicationInfo.loadLabel(packageManager).toString(),
@@ -130,6 +166,7 @@ class CreateFlowUtils {
      providerDataList: List<DisabledProviderData>,
      context: Context,
    ): List<com.android.credentialmanager.createflow.DisabledProviderInfo> {
      // TODO: get from the actual service info
      val packageManager = context.packageManager
      return providerDataList.map {
        val pkgInfo = packageManager
Loading