diff options
11 files changed, 513 insertions, 227 deletions
diff --git a/core/java/android/credentials/ui/CreateCredentialProviderData.java b/core/java/android/credentials/ui/CreateCredentialProviderData.java new file mode 100644 index 000000000000..9cc9c7289f9b --- /dev/null +++ b/core/java/android/credentials/ui/CreateCredentialProviderData.java @@ -0,0 +1,164 @@ +/* + * Copyright 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. + */ + +package android.credentials.ui; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.util.AnnotationValidations; + +import java.util.ArrayList; +import java.util.List; + +/** + * Per-provider metadata and entries for the create-credential flow. + * + * @hide + */ +public class CreateCredentialProviderData extends ProviderData implements Parcelable { + @NonNull + private final List<Entry> mSaveEntries; + @NonNull + private final List<Entry> mActionChips; + private final boolean mIsDefaultProvider; + @Nullable + private final Entry mRemoteEntry; + + public CreateCredentialProviderData( + @NonNull String providerFlattenedComponentName, @NonNull List<Entry> saveEntries, + @NonNull List<Entry> actionChips, boolean isDefaultProvider, + @Nullable Entry remoteEntry) { + super(providerFlattenedComponentName); + mSaveEntries = saveEntries; + mActionChips = actionChips; + mIsDefaultProvider = isDefaultProvider; + mRemoteEntry = remoteEntry; + } + + @NonNull + public List<Entry> getSaveEntries() { + return mSaveEntries; + } + + @NonNull + public List<Entry> getActionChips() { + return mActionChips; + } + + public boolean isDefaultProvider() { + return mIsDefaultProvider; + } + + @Nullable + public Entry getRemoteEntry() { + return mRemoteEntry; + } + + protected CreateCredentialProviderData(@NonNull Parcel in) { + super(in); + + List<Entry> credentialEntries = new ArrayList<>(); + in.readTypedList(credentialEntries, Entry.CREATOR); + mSaveEntries = credentialEntries; + AnnotationValidations.validate(NonNull.class, null, mSaveEntries); + + List<Entry> actionChips = new ArrayList<>(); + in.readTypedList(actionChips, Entry.CREATOR); + mActionChips = actionChips; + AnnotationValidations.validate(NonNull.class, null, mActionChips); + + mIsDefaultProvider = in.readBoolean(); + + Entry remoteEntry = in.readTypedObject(Entry.CREATOR); + mRemoteEntry = remoteEntry; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeTypedList(mSaveEntries); + dest.writeTypedList(mActionChips); + dest.writeBoolean(isDefaultProvider()); + dest.writeTypedObject(mRemoteEntry, flags); + } + + @Override + public int describeContents() { + return 0; + } + + public static final @NonNull Creator<CreateCredentialProviderData> CREATOR = + new Creator<CreateCredentialProviderData>() { + @Override + public CreateCredentialProviderData createFromParcel(@NonNull Parcel in) { + return new CreateCredentialProviderData(in); + } + + @Override + public CreateCredentialProviderData[] newArray(int size) { + return new CreateCredentialProviderData[size]; + } + }; + + /** + * Builder for {@link CreateCredentialProviderData}. + * + * @hide + */ + public static class Builder { + private @NonNull String mProviderFlattenedComponentName; + private @NonNull List<Entry> mSaveEntries = new ArrayList<>(); + private @NonNull List<Entry> mActionChips = new ArrayList<>(); + private boolean mIsDefaultProvider = false; + private @Nullable Entry mRemoteEntry = null; + + /** Constructor with required properties. */ + public Builder(@NonNull String providerFlattenedComponentName) { + mProviderFlattenedComponentName = providerFlattenedComponentName; + } + + /** Sets the list of save credential entries to be displayed to the user. */ + @NonNull + public Builder setSaveEntries(@NonNull List<Entry> credentialEntries) { + mSaveEntries = credentialEntries; + return this; + } + + /** Sets the list of action chips to be displayed to the user. */ + @NonNull + public Builder setActionChips(@NonNull List<Entry> actionChips) { + mActionChips = actionChips; + return this; + } + + /** Sets whether this provider is the user's selected default provider. */ + @NonNull + public Builder setIsDefaultProvider(boolean isDefaultProvider) { + mIsDefaultProvider = isDefaultProvider; + return this; + } + + /** Builds a {@link CreateCredentialProviderData}. */ + @NonNull + public CreateCredentialProviderData build() { + return new CreateCredentialProviderData(mProviderFlattenedComponentName, + mSaveEntries, mActionChips, mIsDefaultProvider, mRemoteEntry); + } + } +} diff --git a/core/java/android/credentials/ui/DisabledProviderData.java b/core/java/android/credentials/ui/DisabledProviderData.java new file mode 100644 index 000000000000..73c8dbe427a7 --- /dev/null +++ b/core/java/android/credentials/ui/DisabledProviderData.java @@ -0,0 +1,60 @@ +/* + * Copyright 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. + */ + +package android.credentials.ui; + +import android.annotation.NonNull; +import android.os.Parcel; +import android.os.Parcelable; + +/** + * Metadata of a disabled provider. + * + * @hide + */ +public class DisabledProviderData extends ProviderData implements Parcelable { + + public DisabledProviderData( + @NonNull String providerFlattenedComponentName) { + super(providerFlattenedComponentName); + } + + protected DisabledProviderData(@NonNull Parcel in) { + super(in); + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + super.writeToParcel(dest, flags); + } + + @Override + public int describeContents() { + return 0; + } + + public static final @NonNull Creator<DisabledProviderData> CREATOR = new Creator<>() { + @Override + public DisabledProviderData createFromParcel(@NonNull Parcel in) { + return new DisabledProviderData(in); + } + + @Override + public DisabledProviderData[] newArray(int size) { + return new DisabledProviderData[size]; + } + }; +} diff --git a/core/java/android/credentials/ui/GetCredentialProviderData.java b/core/java/android/credentials/ui/GetCredentialProviderData.java new file mode 100644 index 000000000000..834f9825208f --- /dev/null +++ b/core/java/android/credentials/ui/GetCredentialProviderData.java @@ -0,0 +1,174 @@ +/* + * Copyright 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. + */ + +package android.credentials.ui; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.util.AnnotationValidations; + +import java.util.ArrayList; +import java.util.List; + +/** + * Per-provider metadata and entries for the get-credential flow. + * + * @hide + */ +public class GetCredentialProviderData extends ProviderData implements Parcelable { + @NonNull + private final List<Entry> mCredentialEntries; + @NonNull + private final List<Entry> mActionChips; + @Nullable + private final Entry mAuthenticationEntry; + @Nullable + private final Entry mRemoteEntry; + + public GetCredentialProviderData( + @NonNull String providerFlattenedComponentName, @NonNull List<Entry> credentialEntries, + @NonNull List<Entry> actionChips, @Nullable Entry authenticationEntry, + @Nullable Entry remoteEntry) { + super(providerFlattenedComponentName); + mCredentialEntries = credentialEntries; + mActionChips = actionChips; + mAuthenticationEntry = authenticationEntry; + mRemoteEntry = remoteEntry; + } + + @NonNull + public List<Entry> getCredentialEntries() { + return mCredentialEntries; + } + + @NonNull + public List<Entry> getActionChips() { + return mActionChips; + } + + @Nullable + public Entry getAuthenticationEntry() { + return mAuthenticationEntry; + } + + @Nullable + public Entry getRemoteEntry() { + return mRemoteEntry; + } + + protected GetCredentialProviderData(@NonNull Parcel in) { + super(in); + + List<Entry> credentialEntries = new ArrayList<>(); + in.readTypedList(credentialEntries, Entry.CREATOR); + mCredentialEntries = credentialEntries; + AnnotationValidations.validate(NonNull.class, null, mCredentialEntries); + + List<Entry> actionChips = new ArrayList<>(); + in.readTypedList(actionChips, Entry.CREATOR); + mActionChips = actionChips; + AnnotationValidations.validate(NonNull.class, null, mActionChips); + + Entry authenticationEntry = in.readTypedObject(Entry.CREATOR); + mAuthenticationEntry = authenticationEntry; + + Entry remoteEntry = in.readTypedObject(Entry.CREATOR); + mRemoteEntry = remoteEntry; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeTypedList(mCredentialEntries); + dest.writeTypedList(mActionChips); + dest.writeTypedObject(mAuthenticationEntry, flags); + dest.writeTypedObject(mRemoteEntry, flags); + } + + @Override + public int describeContents() { + return 0; + } + + public static final @NonNull Creator<GetCredentialProviderData> CREATOR = + new Creator<GetCredentialProviderData>() { + @Override + public GetCredentialProviderData createFromParcel(@NonNull Parcel in) { + return new GetCredentialProviderData(in); + } + + @Override + public GetCredentialProviderData[] newArray(int size) { + return new GetCredentialProviderData[size]; + } + }; + + /** + * Builder for {@link GetCredentialProviderData}. + * + * @hide + */ + public static class Builder { + private @NonNull String mProviderFlattenedComponentName; + private @NonNull List<Entry> mCredentialEntries = new ArrayList<>(); + private @NonNull List<Entry> mActionChips = new ArrayList<>(); + private @Nullable Entry mAuthenticationEntry = null; + private @Nullable Entry mRemoteEntry = null; + + /** Constructor with required properties. */ + public Builder(@NonNull String providerFlattenedComponentName) { + mProviderFlattenedComponentName = providerFlattenedComponentName; + } + + /** Sets the list of save / get credential entries to be displayed to the user. */ + @NonNull + public Builder setCredentialEntries(@NonNull List<Entry> credentialEntries) { + mCredentialEntries = credentialEntries; + return this; + } + + /** Sets the list of action chips to be displayed to the user. */ + @NonNull + public Builder setActionChips(@NonNull List<Entry> actionChips) { + mActionChips = actionChips; + return this; + } + + /** Sets the authentication entry to be displayed to the user. */ + @NonNull + public Builder setAuthenticationEntry(@Nullable Entry authenticationEntry) { + mAuthenticationEntry = authenticationEntry; + return this; + } + + /** Sets the remote entry to be displayed to the user. */ + @NonNull + public Builder setRemoteEntry(@Nullable Entry remoteEntry) { + mRemoteEntry = remoteEntry; + return this; + } + + /** Builds a {@link GetCredentialProviderData}. */ + @NonNull + public GetCredentialProviderData build() { + return new GetCredentialProviderData(mProviderFlattenedComponentName, + mCredentialEntries, mActionChips, mAuthenticationEntry, mRemoteEntry); + } + } +} diff --git a/core/java/android/credentials/ui/IntentFactory.java b/core/java/android/credentials/ui/IntentFactory.java index 1b70ea4ebd71..475169670eb1 100644 --- a/core/java/android/credentials/ui/IntentFactory.java +++ b/core/java/android/credentials/ui/IntentFactory.java @@ -30,15 +30,20 @@ import java.util.ArrayList; */ public class IntentFactory { /** Generate a new launch intent to the . */ - public static Intent newIntent(RequestInfo requestInfo, - ArrayList<ProviderData> providerDataList, ResultReceiver resultReceiver) { + public static Intent newIntent( + RequestInfo requestInfo, + ArrayList<ProviderData> enabledProviderDataList, + ArrayList<DisabledProviderData> disabledProviderDataList, + ResultReceiver resultReceiver) { Intent intent = new Intent(); // TODO: define these as proper config strings. String activityName = "com.android.credentialmanager/.CredentialSelectorActivity"; intent.setComponent(ComponentName.unflattenFromString(activityName)); intent.putParcelableArrayListExtra( - ProviderData.EXTRA_PROVIDER_DATA_LIST, providerDataList); + ProviderData.EXTRA_ENABLED_PROVIDER_DATA_LIST, enabledProviderDataList); + intent.putParcelableArrayListExtra( + ProviderData.EXTRA_DISABLED_PROVIDER_DATA_LIST, disabledProviderDataList); intent.putExtra(RequestInfo.EXTRA_REQUEST_INFO, requestInfo); intent.putExtra(Constants.EXTRA_RESULT_RECEIVER, toIpcFriendlyResultReceiver(resultReceiver)); diff --git a/core/java/android/credentials/ui/ProviderData.java b/core/java/android/credentials/ui/ProviderData.java index 3728469d723d..eeaeb46e7896 100644 --- a/core/java/android/credentials/ui/ProviderData.java +++ b/core/java/android/credentials/ui/ProviderData.java @@ -16,232 +16,62 @@ package android.credentials.ui; -import android.annotation.CurrentTimeMillisLong; import android.annotation.NonNull; -import android.annotation.Nullable; -import android.graphics.drawable.Icon; import android.os.Parcel; import android.os.Parcelable; import com.android.internal.util.AnnotationValidations; -import java.util.ArrayList; -import java.util.List; - /** - * Holds metadata and credential entries for a single provider. + * Super class for data structures that hold metadata and credential entries for a single provider. * * @hide */ -public class ProviderData implements Parcelable { +public abstract class ProviderData implements Parcelable { /** - * The intent extra key for the list of {@code ProviderData} when launching the UX - * activities. + * The intent extra key for the list of {@code ProviderData} from active providers when + * launching the UX activities. + */ + public static final String EXTRA_ENABLED_PROVIDER_DATA_LIST = + "android.credentials.ui.extra.ENABLED_PROVIDER_DATA_LIST"; + /** + * The intent extra key for the list of {@code ProviderData} from disabled providers when + * launching the UX activities. */ - public static final String EXTRA_PROVIDER_DATA_LIST = - "android.credentials.ui.extra.PROVIDER_DATA_LIST"; + public static final String EXTRA_DISABLED_PROVIDER_DATA_LIST = + "android.credentials.ui.extra.DISABLED_PROVIDER_DATA_LIST"; @NonNull private final String mProviderFlattenedComponentName; - @NonNull - private final String mProviderDisplayName; - @Nullable - private final Icon mIcon; - @NonNull - private final List<Entry> mCredentialEntries; - @NonNull - private final List<Entry> mActionChips; - @Nullable - private final Entry mAuthenticationEntry; - - private final @CurrentTimeMillisLong long mLastUsedTimeMillis; public ProviderData( - @NonNull String providerFlattenedComponentName, @NonNull String providerDisplayName, - @Nullable Icon icon, @NonNull List<Entry> credentialEntries, - @NonNull List<Entry> actionChips, @Nullable Entry authenticationEntry, - @CurrentTimeMillisLong long lastUsedTimeMillis) { + @NonNull String providerFlattenedComponentName) { mProviderFlattenedComponentName = providerFlattenedComponentName; - mProviderDisplayName = providerDisplayName; - mIcon = icon; - mCredentialEntries = credentialEntries; - mActionChips = actionChips; - mAuthenticationEntry = authenticationEntry; - mLastUsedTimeMillis = lastUsedTimeMillis; } - /** Returns the unique provider id. */ + /** + * Returns provider component name. + * It also serves as the unique identifier for this provider. + */ @NonNull public String getProviderFlattenedComponentName() { return mProviderFlattenedComponentName; } - @NonNull - public String getProviderDisplayName() { - return mProviderDisplayName; - } - - @Nullable - public Icon getIcon() { - return mIcon; - } - - @NonNull - public List<Entry> getCredentialEntries() { - return mCredentialEntries; - } - - @NonNull - public List<Entry> getActionChips() { - return mActionChips; - } - - @Nullable - public Entry getAuthenticationEntry() { - return mAuthenticationEntry; - } - - /** Returns the time when the provider was last used. */ - public @CurrentTimeMillisLong long getLastUsedTimeMillis() { - return mLastUsedTimeMillis; - } - protected ProviderData(@NonNull Parcel in) { String providerFlattenedComponentName = in.readString8(); mProviderFlattenedComponentName = providerFlattenedComponentName; AnnotationValidations.validate(NonNull.class, null, mProviderFlattenedComponentName); - - String providerDisplayName = in.readString8(); - mProviderDisplayName = providerDisplayName; - AnnotationValidations.validate(NonNull.class, null, mProviderDisplayName); - - Icon icon = in.readTypedObject(Icon.CREATOR); - mIcon = icon; - - List<Entry> credentialEntries = new ArrayList<>(); - in.readTypedList(credentialEntries, Entry.CREATOR); - mCredentialEntries = credentialEntries; - AnnotationValidations.validate(NonNull.class, null, mCredentialEntries); - - List<Entry> actionChips = new ArrayList<>(); - in.readTypedList(actionChips, Entry.CREATOR); - mActionChips = actionChips; - AnnotationValidations.validate(NonNull.class, null, mActionChips); - - Entry authenticationEntry = in.readTypedObject(Entry.CREATOR); - mAuthenticationEntry = authenticationEntry; - - long lastUsedTimeMillis = in.readLong(); - mLastUsedTimeMillis = lastUsedTimeMillis; } @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeString8(mProviderFlattenedComponentName); - dest.writeString8(mProviderDisplayName); - dest.writeTypedObject(mIcon, flags); - dest.writeTypedList(mCredentialEntries); - dest.writeTypedList(mActionChips); - dest.writeTypedObject(mAuthenticationEntry, flags); - dest.writeLong(mLastUsedTimeMillis); } @Override public int describeContents() { return 0; } - - public static final @NonNull Creator<ProviderData> CREATOR = new Creator<ProviderData>() { - @Override - public ProviderData createFromParcel(@NonNull Parcel in) { - return new ProviderData(in); - } - - @Override - public ProviderData[] newArray(int size) { - return new ProviderData[size]; - } - }; - - /** - * Builder for {@link ProviderData}. - * - * @hide - */ - public static class Builder { - private @NonNull String mProviderFlattenedComponentName; - private @NonNull String mProviderDisplayName; - private @Nullable Icon mIcon; - private @NonNull List<Entry> mCredentialEntries = new ArrayList<>(); - private @NonNull List<Entry> mActionChips = new ArrayList<>(); - private @Nullable Entry mAuthenticationEntry = null; - private @CurrentTimeMillisLong long mLastUsedTimeMillis = 0L; - - /** Constructor with required properties. */ - public Builder(@NonNull String providerFlattenedComponentName, - @NonNull String providerDisplayName, - @Nullable Icon icon) { - mProviderFlattenedComponentName = providerFlattenedComponentName; - mProviderDisplayName = providerDisplayName; - mIcon = icon; - } - - /** Sets the unique provider id. */ - @NonNull - public Builder setProviderFlattenedComponentName(@NonNull String providerFlattenedComponentName) { - mProviderFlattenedComponentName = providerFlattenedComponentName; - return this; - } - - /** Sets the provider display name to be displayed to the user. */ - @NonNull - public Builder setProviderDisplayName(@NonNull String providerDisplayName) { - mProviderDisplayName = providerDisplayName; - return this; - } - - /** Sets the provider icon to be displayed to the user. */ - @NonNull - public Builder setIcon(@NonNull Icon icon) { - mIcon = icon; - return this; - } - - /** Sets the list of save / get credential entries to be displayed to the user. */ - @NonNull - public Builder setCredentialEntries(@NonNull List<Entry> credentialEntries) { - mCredentialEntries = credentialEntries; - return this; - } - - /** Sets the list of action chips to be displayed to the user. */ - @NonNull - public Builder setActionChips(@NonNull List<Entry> actionChips) { - mActionChips = actionChips; - return this; - } - - /** Sets the authentication entry to be displayed to the user. */ - @NonNull - public Builder setAuthenticationEntry(@Nullable Entry authenticationEntry) { - mAuthenticationEntry = authenticationEntry; - return this; - } - - /** Sets the time when the provider was last used. */ - @NonNull - public Builder setLastUsedTimeMillis(@CurrentTimeMillisLong long lastUsedTimeMillis) { - mLastUsedTimeMillis = lastUsedTimeMillis; - return this; - } - - /** Builds a {@link ProviderData}. */ - @NonNull - public ProviderData build() { - return new ProviderData(mProviderFlattenedComponentName, mProviderDisplayName, - mIcon, mCredentialEntries, - mActionChips, mAuthenticationEntry, mLastUsedTimeMillis); - } - } } diff --git a/core/java/android/credentials/ui/RequestInfo.java b/core/java/android/credentials/ui/RequestInfo.java index 619b08ec9ca7..59d511838edc 100644 --- a/core/java/android/credentials/ui/RequestInfo.java +++ b/core/java/android/credentials/ui/RequestInfo.java @@ -69,6 +69,7 @@ public class RequestInfo implements Parcelable { private final boolean mIsFirstUsage; + // TODO: change to package name @NonNull private final String mAppDisplayName; diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt index 0988cba2f424..01348e47932c 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt @@ -23,6 +23,8 @@ import android.content.Intent import android.credentials.CreateCredentialRequest import android.credentials.ui.Constants import android.credentials.ui.Entry +import android.credentials.ui.CreateCredentialProviderData +import android.credentials.ui.GetCredentialProviderData import android.credentials.ui.ProviderData import android.credentials.ui.RequestInfo import android.credentials.ui.BaseDialogResult @@ -54,10 +56,22 @@ class CredentialManagerRepo( RequestInfo::class.java ) ?: testRequestInfo() - providerList = intent.extras?.getParcelableArrayList( - ProviderData.EXTRA_PROVIDER_DATA_LIST, - ProviderData::class.java - ) ?: testProviderList() + providerList = when (requestInfo.type) { + RequestInfo.TYPE_CREATE -> + intent.extras?.getParcelableArrayList( + ProviderData.EXTRA_ENABLED_PROVIDER_DATA_LIST, + CreateCredentialProviderData::class.java + ) ?: testCreateCredentialProviderList() + RequestInfo.TYPE_GET -> + intent.extras?.getParcelableArrayList( + ProviderData.EXTRA_ENABLED_PROVIDER_DATA_LIST, + GetCredentialProviderData::class.java + ) ?: testGetCredentialProviderList() + else -> { + // TODO: fail gracefully + throw IllegalStateException("Unrecognized request type: ${requestInfo.type}") + } + } resultReceiver = intent.getParcelableExtra( Constants.EXTRA_RESULT_RECEIVER, @@ -84,7 +98,9 @@ class CredentialManagerRepo( } fun getCredentialInitialUiState(): GetCredentialUiState { - val providerList = GetFlowUtils.toProviderList(providerList, context) + val providerList = GetFlowUtils.toProviderList( + // TODO: handle runtime cast error + providerList as List<GetCredentialProviderData>, context) // TODO: covert from real requestInfo val requestDisplayInfo = com.android.credentialmanager.getflow.RequestDisplayInfo( "Elisa Beckett", @@ -100,7 +116,9 @@ class CredentialManagerRepo( } fun createPasskeyInitialUiState(): CreatePasskeyUiState { - val providerList = CreateFlowUtils.toProviderList(providerList, context) + val providerList = CreateFlowUtils.toProviderList( + // Handle runtime cast error + providerList as List<CreateCredentialProviderData>, context) // TODO: covert from real requestInfo val requestDisplayInfo = RequestDisplayInfo( "Elisa Beckett", @@ -130,31 +148,64 @@ class CredentialManagerRepo( } // TODO: below are prototype functionalities. To be removed for productionization. - private fun testProviderList(): List<ProviderData> { + private fun testCreateCredentialProviderList(): List<CreateCredentialProviderData> { return listOf( - ProviderData.Builder( - "com.google", - "Google Password Manager", - Icon.createWithResource(context, R.drawable.ic_launcher_foreground)) - .setCredentialEntries( + CreateCredentialProviderData.Builder("com.google/com.google.CredentialManagerService") + .setSaveEntries( listOf<Entry>( newEntry("key1", "subkey-1", "elisa.beckett@gmail.com", "Elisa Backett", "20 passwords and 7 passkeys saved"), newEntry("key1", "subkey-2", "elisa.work@google.com", "Elisa Backett Work", "20 passwords and 7 passkeys saved"), ) - ).setActionChips( + ) + .setActionChips( listOf<Entry>( newEntry("key2", "subkey-1", "Go to Settings", "", "20 passwords and 7 passkeys saved"), newEntry("key2", "subkey-2", "Switch Account", "", "20 passwords and 7 passkeys saved"), ), + ) + .setIsDefaultProvider(true) + .build(), + CreateCredentialProviderData.Builder("com.dashlane/com.dashlane.CredentialManagerService") + .setSaveEntries( + listOf<Entry>( + newEntry("key1", "subkey-3", "elisa.beckett@dashlane.com", + "Elisa Backett", "20 passwords and 7 passkeys saved"), + newEntry("key1", "subkey-4", "elisa.work@dashlane.com", + "Elisa Backett Work", "20 passwords and 7 passkeys saved"), + ) + ).setActionChips( + listOf<Entry>( + newEntry("key2", "subkey-3", "Manage Accounts", + "Manage your accounts in the dashlane app", + "20 passwords and 7 passkeys saved"), + ), ).build(), - ProviderData.Builder( - "com.dashlane", - "Dashlane", - Icon.createWithResource(context, R.drawable.ic_launcher_foreground)) + ) + } + + private fun testGetCredentialProviderList(): List<GetCredentialProviderData> { + return listOf( + GetCredentialProviderData.Builder("com.google/com.google.CredentialManagerService") + .setCredentialEntries( + listOf<Entry>( + newEntry("key1", "subkey-1", "elisa.beckett@gmail.com", + "Elisa Backett", "20 passwords and 7 passkeys saved"), + newEntry("key1", "subkey-2", "elisa.work@google.com", + "Elisa Backett Work", "20 passwords and 7 passkeys saved"), + ) + ).setActionChips( + listOf<Entry>( + newEntry("key2", "subkey-1", "Go to Settings", "", + "20 passwords and 7 passkeys saved"), + newEntry("key2", "subkey-2", "Switch Account", "", + "20 passwords and 7 passkeys saved"), + ), + ).build(), + GetCredentialProviderData.Builder("com.dashlane/com.dashlane.CredentialManagerService") .setCredentialEntries( listOf<Entry>( newEntry("key1", "subkey-3", "elisa.beckett@dashlane.com", @@ -166,7 +217,7 @@ class CredentialManagerRepo( listOf<Entry>( newEntry("key2", "subkey-3", "Manage Accounts", "Manage your accounts in the dashlane app", - "20 passwords and 7 passkeys saved"), + "20 passwords and 7 passkeys saved"), ), ).build(), ) diff --git a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt index 2ba8748c16b7..bf0dba23cb64 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt @@ -18,7 +18,8 @@ package com.android.credentialmanager import android.content.Context import android.credentials.ui.Entry -import android.credentials.ui.ProviderData +import android.credentials.ui.GetCredentialProviderData +import android.credentials.ui.CreateCredentialProviderData import com.android.credentialmanager.createflow.CreateOptionInfo import com.android.credentialmanager.getflow.CredentialOptionInfo import com.android.credentialmanager.getflow.ProviderInfo @@ -28,7 +29,7 @@ class GetFlowUtils { companion object { fun toProviderList( - providerDataList: List<ProviderData>, + providerDataList: List<GetCredentialProviderData>, context: Context, ): List<ProviderInfo> { return providerDataList.map { @@ -36,9 +37,10 @@ class GetFlowUtils { // TODO: replace to extract from the service data structure when available icon = context.getDrawable(R.drawable.ic_passkey)!!, name = it.providerFlattenedComponentName, - displayName = it.providerDisplayName, + // TODO: get the service display name and icon from the component name. + displayName = it.providerFlattenedComponentName, credentialTypeIcon = context.getDrawable(R.drawable.ic_passkey)!!, - credentialOptions = toCredentialOptionInfoList(it.credentialEntries, context) + credentialOptions = toCredentialOptionInfoList(it.credentialEntries, context), ) } } @@ -72,7 +74,7 @@ class CreateFlowUtils { companion object { fun toProviderList( - providerDataList: List<ProviderData>, + providerDataList: List<CreateCredentialProviderData>, context: Context, ): List<com.android.credentialmanager.createflow.ProviderInfo> { return providerDataList.map { @@ -80,9 +82,11 @@ class CreateFlowUtils { // TODO: replace to extract from the service data structure when available icon = context.getDrawable(R.drawable.ic_passkey)!!, name = it.providerFlattenedComponentName, - displayName = it.providerDisplayName, + // TODO: get the service display name and icon from the component name. + displayName = it.providerFlattenedComponentName, credentialTypeIcon = context.getDrawable(R.drawable.ic_passkey)!!, - createOptions = toCreationOptionInfoList(it.credentialEntries, context), + createOptions = toCreationOptionInfoList(it.saveEntries, context), + isDefault = it.isDefaultProvider, ) } } diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt index cb2bf10f2aef..db0f337e9a2b 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt @@ -24,6 +24,7 @@ data class ProviderInfo( val displayName: String, val credentialTypeIcon: Drawable, val createOptions: List<CreateOptionInfo>, + val isDefault: Boolean, ) data class CreateOptionInfo( diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java b/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java index 5f25e3df8a9a..dcf094f99aae 100644 --- a/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java +++ b/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java @@ -83,8 +83,9 @@ public class CredentialManagerUi { */ public void show(RequestInfo requestInfo, ArrayList<ProviderData> providerDataList) { Log.i(TAG, "In show"); - Intent intent = IntentFactory.newIntent(requestInfo, providerDataList, - mResultReceiver); + Intent intent = IntentFactory.newIntent( + requestInfo, providerDataList, + new ArrayList<>(), mResultReceiver); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); mContext.startActivity(intent); } diff --git a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java index 24610df7ad79..ff2107a95d25 100644 --- a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java +++ b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java @@ -20,7 +20,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.app.slice.Slice; import android.credentials.ui.Entry; -import android.credentials.ui.ProviderData; +import android.credentials.ui.GetCredentialProviderData; import android.service.credentials.Action; import android.service.credentials.CredentialEntry; import android.service.credentials.CredentialProviderInfo; @@ -117,7 +117,7 @@ public final class ProviderGetSession extends ProviderSession<GetCredentialsResp } @Override - protected final ProviderData prepareUiData() throws IllegalArgumentException { + protected GetCredentialProviderData prepareUiData() throws IllegalArgumentException { Log.i(TAG, "In prepareUiData"); if (!ProviderSession.isCompletionStatus(getStatus())) { Log.i(TAG, "In prepareUiData not complete"); @@ -147,7 +147,7 @@ public final class ProviderGetSession extends ProviderSession<GetCredentialsResp * To be called by {@link ProviderGetSession} when the UI is to be invoked. */ @Nullable - private ProviderData prepareUiProviderDataWithCredentials(@NonNull + private GetCredentialProviderData prepareUiProviderDataWithCredentials(@NonNull CredentialsDisplayContent content) { Log.i(TAG, "in prepareUiProviderData"); List<Entry> credentialEntries = new ArrayList<>(); @@ -173,15 +173,10 @@ public final class ProviderGetSession extends ProviderSession<GetCredentialsResp action.getSlice())); } - // TODO : Set the correct last used time - return new ProviderData.Builder(mComponentName.flattenToString(), - mProviderInfo.getServiceLabel() == null ? "" : - mProviderInfo.getServiceLabel().toString(), - /*icon=*/null) + return new GetCredentialProviderData.Builder(mComponentName.flattenToString()) .setCredentialEntries(credentialEntries) .setActionChips(actionChips) .setAuthenticationEntry(authenticationEntry) - .setLastUsedTimeMillis(0) .build(); } @@ -189,7 +184,7 @@ public final class ProviderGetSession extends ProviderSession<GetCredentialsResp * To be called by {@link ProviderGetSession} when the UI is to be invoked. */ @Nullable - private ProviderData prepareUiProviderDataWithAuthentication(@NonNull + private GetCredentialProviderData prepareUiProviderDataWithAuthentication(@NonNull Action authenticationEntry) { // TODO : Implement authentication flow return null; |