Merge "Remove pending intent from framework provider APIs"

This commit is contained in:
TreeHugger Robot
2023-01-08 06:39:39 +00:00
committed by Android (Google) Code Review
11 changed files with 230 additions and 284 deletions

View File

@@ -39769,9 +39769,8 @@ package android.service.controls.templates {
package android.service.credentials {
public class Action implements android.os.Parcelable {
ctor public Action(@NonNull android.app.slice.Slice, @NonNull android.app.PendingIntent);
ctor public Action(@NonNull android.app.slice.Slice);
method public int describeContents();
method @NonNull public android.app.PendingIntent getPendingIntent();
method @NonNull public android.app.slice.Slice getSlice();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.service.credentials.Action> CREATOR;
@@ -39866,21 +39865,18 @@ package android.service.credentials {
}
public class CreateEntry implements android.os.Parcelable {
ctor public CreateEntry(@NonNull android.app.slice.Slice, @NonNull android.app.PendingIntent);
ctor public CreateEntry(@NonNull android.app.slice.Slice);
method public int describeContents();
method @NonNull public android.app.PendingIntent getPendingIntent();
method @NonNull public android.app.slice.Slice getSlice();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.service.credentials.CreateEntry> CREATOR;
}
public class CredentialEntry implements android.os.Parcelable {
ctor public CredentialEntry(@NonNull String, @NonNull android.app.slice.Slice, @NonNull android.app.PendingIntent, boolean);
ctor public CredentialEntry(@NonNull String, @NonNull android.app.slice.Slice);
method public int describeContents();
method @NonNull public android.app.PendingIntent getPendingIntent();
method @NonNull public android.app.slice.Slice getSlice();
method @NonNull public String getType();
method public boolean isAutoSelectAllowed();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.service.credentials.CredentialEntry> CREATOR;
}

View File

@@ -997,7 +997,8 @@ package android.credentials.ui {
public final class Entry implements android.os.Parcelable {
ctor public Entry(@NonNull String, @NonNull String, @NonNull android.app.slice.Slice);
ctor public Entry(@NonNull String, @NonNull String, @NonNull android.app.slice.Slice, @NonNull android.app.PendingIntent, @Nullable android.content.Intent);
ctor public Entry(@NonNull String, @NonNull String, @NonNull android.app.slice.Slice, @NonNull android.app.PendingIntent, @NonNull android.content.Intent);
ctor public Entry(@NonNull String, @NonNull String, @NonNull android.app.slice.Slice, @NonNull android.content.Intent);
method public int describeContents();
method @Nullable public android.content.Intent getFrameworkExtrasIntent();
method @NonNull public String getKey();

View File

@@ -89,12 +89,21 @@ public final class Entry implements Parcelable {
* when clicked.
*/
public Entry(@NonNull String key, @NonNull String subkey, @NonNull Slice slice,
@NonNull PendingIntent pendingIntent, @Nullable Intent intent) {
@NonNull PendingIntent pendingIntent, @NonNull Intent intent) {
this(key, subkey, slice);
mPendingIntent = pendingIntent;
mFrameworkExtrasIntent = intent;
}
/** Constructor to be used for an entry that requires a pending intent to be invoked
* when clicked.
*/
public Entry(@NonNull String key, @NonNull String subkey, @NonNull Slice slice,
@NonNull Intent intent) {
this(key, subkey, slice);
mFrameworkExtrasIntent = intent;
}
/**
* Returns the identifier of this entry that's unique within the context of the CredentialManager
* request.

View File

@@ -29,6 +29,9 @@ import java.util.Objects;
* An action defined by the provider that intents into the provider's app for specific
* user actions.
*
* <p>If user selects this action entry, the corresponding {@link PendingIntent} set on the
* {@code slice} as a {@link androidx.slice.core.SliceAction} will get invoked.
*
* <p>Any class that derives this class must only add extra field values to the {@code slice}
* object passed into the constructor. Any other field will not be parceled through. If the
* derived class has custom parceling implementation, this class will not be able to unpack
@@ -37,9 +40,8 @@ import java.util.Objects;
@SuppressLint("ParcelNotFinal")
public class Action implements Parcelable {
/** Slice object containing display content to be displayed with this action on the UI. */
private final @NonNull Slice mSlice;
/** The pending intent to be invoked when the user selects this action. */
private final @NonNull PendingIntent mPendingIntent;
@NonNull
private final Slice mSlice;
/**
* Constructs an action to be displayed on the UI.
@@ -52,21 +54,18 @@ public class Action implements Parcelable {
* {@link BeginCreateCredentialResponse} and {@link BeginGetCredentialResponse}.
*
* @param slice the display content to be displayed on the UI, along with this action
* @param pendingIntent the intent to be invoked when the user selects this action
*/
public Action(@NonNull Slice slice, @NonNull PendingIntent pendingIntent) {
public Action(@NonNull Slice slice) {
Objects.requireNonNull(slice, "slice must not be null");
Objects.requireNonNull(pendingIntent, "pendingIntent must not be null");
mSlice = slice;
mPendingIntent = pendingIntent;
}
private Action(@NonNull Parcel in) {
mSlice = in.readTypedObject(Slice.CREATOR);
mPendingIntent = in.readTypedObject(PendingIntent.CREATOR);
}
public static final @NonNull Creator<Action> CREATOR = new Creator<Action>() {
@NonNull
public static final Creator<Action> CREATOR = new Creator<Action>() {
@Override
public Action createFromParcel(@NonNull Parcel in) {
return new Action(in);
@@ -86,20 +85,13 @@ public class Action implements Parcelable {
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeTypedObject(mSlice, flags);
dest.writeTypedObject(mPendingIntent, flags);
}
/**
* Returns a {@code Slice} object containing the display content to be displayed on the UI.
*/
public @NonNull Slice getSlice() {
@NonNull
public Slice getSlice() {
return mSlice;
}
/**
* Returns the {@link PendingIntent} to be invoked when the action is selected.
*/
public @NonNull PendingIntent getPendingIntent() {
return mPendingIntent;
}
}

View File

@@ -27,6 +27,13 @@ import android.os.Parcelable;
* An entry to be shown on the UI. This entry represents where the credential to be created will
* be stored. Examples include user's account, family group etc.
*
* <p>If user selects this entry, the corresponding {@link PendingIntent} set on the
* {@code slice} as a {@link androidx.slice.core.SliceAction} will get invoked.
* Once the resulting activity fulfills the required user engagement,
* the {@link android.app.Activity} result should be set to {@link android.app.Activity#RESULT_OK},
* and the {@link CredentialProviderService#EXTRA_CREATE_CREDENTIAL_RESPONSE} must be set with a
* {@link android.credentials.CreateCredentialResponse} object.
*
* <p>Any class that derives this class must only add extra field values to the {@code slice}
* object passed into the constructor. Any other field will not be parceled through. If the
* derived class has custom parceling implementation, this class will not be able to unpack
@@ -35,14 +42,13 @@ import android.os.Parcelable;
@SuppressLint("ParcelNotFinal")
public class CreateEntry implements Parcelable {
private final @NonNull Slice mSlice;
private final @NonNull PendingIntent mPendingIntent;
private CreateEntry(@NonNull Parcel in) {
mSlice = in.readTypedObject(Slice.CREATOR);
mPendingIntent = in.readTypedObject(PendingIntent.CREATOR);
}
public static final @NonNull Creator<CreateEntry> CREATOR = new Creator<CreateEntry>() {
@NonNull
public static final Creator<CreateEntry> CREATOR = new Creator<CreateEntry>() {
@Override
public CreateEntry createFromParcel(@NonNull Parcel in) {
return new CreateEntry(in);
@@ -62,33 +68,23 @@ public class CreateEntry implements Parcelable {
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeTypedObject(mSlice, flags);
dest.writeTypedObject(mPendingIntent, flags);
}
/**
* Constructs a CreateEntry to be displayed on the UI.
*
* @param slice the display content to be displayed on the UI, along with this entry
* @param pendingIntent the intent to be invoked when the user selects this entry
*/
public CreateEntry(
@NonNull Slice slice,
@NonNull PendingIntent pendingIntent) {
@NonNull Slice slice) {
this.mSlice = slice;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mSlice);
this.mPendingIntent = pendingIntent;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mPendingIntent);
}
/** Returns the content to be displayed with this create entry on the UI. */
public @NonNull Slice getSlice() {
@NonNull
public Slice getSlice() {
return mSlice;
}
/** Returns the pendingIntent to be invoked when this create entry on the UI is selectcd. */
public @NonNull PendingIntent getPendingIntent() {
return mPendingIntent;
}
}

View File

@@ -24,17 +24,14 @@ import android.credentials.GetCredentialResponse;
import android.os.Parcel;
import android.os.Parcelable;
import com.android.internal.util.Preconditions;
import java.util.Objects;
/**
* A credential entry that is to be displayed on the account selector that is presented to the
* user.
*
* <p>If user selects this entry, the corresponding {@code pendingIntent} will be invoked to
* launch activities that require some user engagement before getting the credential
* corresponding to this entry, e.g. authentication, confirmation etc.
* <p>If user selects this entry, the corresponding {@link PendingIntent},
* set on the {@code slice} as a {@link androidx.slice.core.SliceAction} will be
* invoked to launch activities that require some user engagement before getting
* the credential corresponding to this entry, e.g. authentication, confirmation etc.
*
* Once the activity fulfills the required user engagement, the {@link android.app.Activity}
* result should be set to {@link android.app.Activity#RESULT_OK}, and the
@@ -55,51 +52,29 @@ public class CredentialEntry implements Parcelable {
* on the UI. */
private final @NonNull Slice mSlice;
/** The pending intent to be invoked when this credential entry is selected. */
private final @NonNull PendingIntent mPendingIntent;
/** A flag denoting whether auto-select is enabled for this entry. */
private final boolean mAutoSelectAllowed;
/**
* Constructs an instance of the credential entry to be displayed on the UI
* @param type the type of credential underlying this credential entry
* @param slice the content to be displayed with this entry on the UI
* @param pendingIntent the pendingIntent to be invoked when this entry is selected by the user
* @param autoSelectAllowed whether this entry should be auto selected if it is the only one
* on the selector
*
* @throws NullPointerException If {@code slice}, or {@code pendingIntent} is null.
* @throws IllegalArgumentException If {@code type} is null or empty, or if
* {@code pendingIntent} is null.
*/
public CredentialEntry(@NonNull String type, @NonNull Slice slice,
@NonNull PendingIntent pendingIntent, boolean autoSelectAllowed) {
mType = Preconditions.checkStringNotEmpty(type, "type must not be null");
mSlice = Objects.requireNonNull(slice, "slice must not be null");
mPendingIntent = Objects.requireNonNull(pendingIntent, "pendingintent must not be null");
mAutoSelectAllowed = autoSelectAllowed;
public CredentialEntry(@NonNull String type, @NonNull Slice slice) {
mType = type;
mSlice = slice;
}
private CredentialEntry(@NonNull Parcel in) {
mType = in.readString8();
mSlice = in.readTypedObject(Slice.CREATOR);
mPendingIntent = in.readTypedObject(PendingIntent.CREATOR);
mAutoSelectAllowed = in.readBoolean();
}
public static final @NonNull Creator<CredentialEntry> CREATOR =
@NonNull
public static final Creator<CredentialEntry> CREATOR =
new Creator<CredentialEntry>() {
@Override
public CredentialEntry createFromParcel(@NonNull Parcel in) {
return new CredentialEntry(in);
}
@Override
public CredentialEntry createFromParcel(@NonNull Parcel in) {
return new CredentialEntry(in);
}
@Override
public CredentialEntry[] newArray(int size) {
return new CredentialEntry[size];
}
};
@Override
public CredentialEntry[] newArray(int size) {
return new CredentialEntry[size];
}
};
@Override
public int describeContents() {
@@ -110,35 +85,21 @@ public class CredentialEntry implements Parcelable {
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeString8(mType);
dest.writeTypedObject(mSlice, flags);
dest.writeTypedObject(mPendingIntent, flags);
dest.writeBoolean(mAutoSelectAllowed);
}
/**
* Returns the specific credential type of the entry.
*/
public @NonNull String getType() {
@NonNull
public String getType() {
return mType;
}
/**
* Returns the {@link Slice} object containing UI display content to be shown for this entry.
*/
public @NonNull Slice getSlice() {
@NonNull
public Slice getSlice() {
return mSlice;
}
/**
* Returns the pending intent to be invoked if the user selects this entry.
*/
public @NonNull PendingIntent getPendingIntent() {
return mPendingIntent;
}
/**
* Returns whether this entry can be auto selected if it is the only option for the user.
*/
public boolean isAutoSelectAllowed() {
return mAutoSelectAllowed;
}
}

View File

@@ -325,7 +325,6 @@ class CredentialManagerRepo(
key,
subkey,
CredentialEntry.toSlice(credentialEntry),
pendingIntent,
null
)
}
@@ -366,8 +365,7 @@ class CredentialManagerRepo(
key,
subkey,
CreateEntry.toSlice(createEntry),
pendingIntent,
fillInIntent,
fillInIntent
)
}

View File

@@ -53,8 +53,8 @@ class GetFlowUtils {
companion object {
fun toProviderList(
providerDataList: List<GetCredentialProviderData>,
context: Context,
providerDataList: List<GetCredentialProviderData>,
context: Context,
): List<ProviderInfo> {
val packageManager = context.packageManager
return providerDataList.map {
@@ -67,45 +67,45 @@ class GetFlowUtils {
}
val pkgInfo = packageManager
.getPackageInfo(packageName!!,
PackageManager.PackageInfoFlags.of(0))
.getPackageInfo(packageName!!,
PackageManager.PackageInfoFlags.of(0))
val providerDisplayName = pkgInfo.applicationInfo.loadLabel(packageManager).toString()
// TODO: get the provider icon from the service
// and decide what to do when failed to load a provider icon
val providerIcon = pkgInfo.applicationInfo.loadIcon(packageManager)!!
ProviderInfo(
id = 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,
providerDisplayName,
providerIcon,
it.authenticationEntry),
remoteEntry = getRemoteEntry(it.providerFlattenedComponentName, it.remoteEntry),
actionEntryList = getActionEntryList(
it.providerFlattenedComponentName, it.actionChips, providerIcon),
id = 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,
providerDisplayName,
providerIcon,
it.authenticationEntry),
remoteEntry = getRemoteEntry(it.providerFlattenedComponentName, it.remoteEntry),
actionEntryList = getActionEntryList(
it.providerFlattenedComponentName, it.actionChips, providerIcon),
)
}
}
fun toRequestDisplayInfo(
requestInfo: RequestInfo,
requestInfo: RequestInfo,
): com.android.credentialmanager.getflow.RequestDisplayInfo {
return com.android.credentialmanager.getflow.RequestDisplayInfo(
appDomainName = requestInfo.appPackageName
appDomainName = requestInfo.appPackageName
)
}
/* From service data structure to UI credential entry list representation. */
private fun getCredentialOptionInfoList(
providerId: String,
credentialEntries: List<Entry>,
context: Context,
providerId: String,
credentialEntries: List<Entry>,
context: Context,
): List<CredentialEntryInfo> {
return credentialEntries.map {
// TODO: handle NPE gracefully
@@ -113,27 +113,27 @@ class GetFlowUtils {
// Consider directly move the UI object into the class.
return@map CredentialEntryInfo(
providerId = providerId,
entryKey = it.key,
entrySubkey = it.subkey,
pendingIntent = it.pendingIntent,
fillInIntent = it.frameworkExtrasIntent,
credentialType = credentialEntry.type.toString(),
credentialTypeDisplayName = credentialEntry.typeDisplayName.toString(),
userName = credentialEntry.username.toString(),
displayName = credentialEntry.displayName?.toString(),
// TODO: proper fallback
icon = credentialEntry.icon?.loadDrawable(context),
lastUsedTimeMillis = credentialEntry.lastUsedTimeMillis,
providerId = providerId,
entryKey = it.key,
entrySubkey = it.subkey,
pendingIntent = credentialEntry.pendingIntent,
fillInIntent = it.frameworkExtrasIntent,
credentialType = credentialEntry.type.toString(),
credentialTypeDisplayName = credentialEntry.typeDisplayName.toString(),
userName = credentialEntry.username.toString(),
displayName = credentialEntry.displayName?.toString(),
// TODO: proper fallback
icon = credentialEntry.icon?.loadDrawable(context),
lastUsedTimeMillis = credentialEntry.lastUsedTimeMillis,
)
}
}
private fun getAuthenticationEntry(
providerId: String,
providerDisplayName: String,
providerIcon: Drawable,
authEntry: Entry?,
providerId: String,
providerDisplayName: String,
providerIcon: Drawable,
authEntry: Entry?,
): AuthenticationEntryInfo? {
// TODO: should also call fromSlice after getting the official jetpack code.
@@ -141,13 +141,13 @@ class GetFlowUtils {
return null
}
return AuthenticationEntryInfo(
providerId = providerId,
entryKey = authEntry.key,
entrySubkey = authEntry.subkey,
pendingIntent = authEntry.pendingIntent,
fillInIntent = authEntry.frameworkExtrasIntent,
title = providerDisplayName,
icon = providerIcon,
providerId = providerId,
entryKey = authEntry.key,
entrySubkey = authEntry.subkey,
pendingIntent = authEntry.pendingIntent,
fillInIntent = authEntry.frameworkExtrasIntent,
title = providerDisplayName,
icon = providerIcon,
)
}
@@ -157,33 +157,33 @@ class GetFlowUtils {
return null
}
return RemoteEntryInfo(
providerId = providerId,
entryKey = remoteEntry.key,
entrySubkey = remoteEntry.subkey,
pendingIntent = remoteEntry.pendingIntent,
fillInIntent = remoteEntry.frameworkExtrasIntent,
providerId = providerId,
entryKey = remoteEntry.key,
entrySubkey = remoteEntry.subkey,
pendingIntent = remoteEntry.pendingIntent,
fillInIntent = remoteEntry.frameworkExtrasIntent,
)
}
private fun getActionEntryList(
providerId: String,
actionEntries: List<Entry>,
providerIcon: Drawable,
providerId: String,
actionEntries: List<Entry>,
providerIcon: Drawable,
): List<ActionEntryInfo> {
return actionEntries.map {
// TODO: handle NPE gracefully
val actionEntryUi = Action.fromSlice(it.slice)!!
return@map ActionEntryInfo(
providerId = providerId,
entryKey = it.key,
entrySubkey = it.subkey,
pendingIntent = it.pendingIntent,
fillInIntent = it.frameworkExtrasIntent,
title = actionEntryUi.title.toString(),
// TODO: gracefully fail
icon = providerIcon,
subTitle = actionEntryUi.subTitle?.toString(),
providerId = providerId,
entryKey = it.key,
entrySubkey = it.subkey,
pendingIntent = actionEntryUi.pendingIntent,
fillInIntent = it.frameworkExtrasIntent,
title = actionEntryUi.title.toString(),
// TODO: gracefully fail
icon = providerIcon,
subTitle = actionEntryUi.subTitle?.toString(),
)
}
}
@@ -194,8 +194,8 @@ class CreateFlowUtils {
companion object {
fun toEnabledProviderList(
providerDataList: List<CreateCredentialProviderData>,
context: Context,
providerDataList: List<CreateCredentialProviderData>,
context: Context,
): List<EnabledProviderInfo> {
// TODO: get from the actual service info
val packageManager = context.packageManager
@@ -209,23 +209,23 @@ class CreateFlowUtils {
}
val pkgInfo = packageManager
.getPackageInfo(packageName!!,
PackageManager.PackageInfoFlags.of(0))
.getPackageInfo(packageName!!,
PackageManager.PackageInfoFlags.of(0))
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(),
createOptions = toCreationOptionInfoList(
it.providerFlattenedComponentName, it.saveEntries, context),
remoteEntry = toRemoteInfo(it.providerFlattenedComponentName, it.remoteEntry),
// 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(),
createOptions = toCreationOptionInfoList(
it.providerFlattenedComponentName, it.saveEntries, context),
remoteEntry = toRemoteInfo(it.providerFlattenedComponentName, it.remoteEntry),
)
}
}
fun toDisabledProviderList(
providerDataList: List<DisabledProviderData>?,
context: Context,
providerDataList: List<DisabledProviderData>?,
context: Context,
): List<DisabledProviderInfo>? {
// TODO: get from the actual service info
val packageManager = context.packageManager
@@ -240,31 +240,31 @@ class CreateFlowUtils {
.getPackageInfo(packageName,
PackageManager.PackageInfoFlags.of(0))
DisabledProviderInfo(
icon = pkgInfo.applicationInfo.loadIcon(packageManager)!!,
name = it.providerFlattenedComponentName,
displayName = pkgInfo.applicationInfo.loadLabel(packageManager).toString(),
icon = pkgInfo.applicationInfo.loadIcon(packageManager)!!,
name = it.providerFlattenedComponentName,
displayName = pkgInfo.applicationInfo.loadLabel(packageManager).toString(),
)
}
}
fun toRequestDisplayInfo(
requestInfo: RequestInfo,
context: Context,
requestInfo: RequestInfo,
context: Context,
): RequestDisplayInfo {
val createCredentialRequest = requestInfo.createCredentialRequest
val createCredentialRequestJetpack = createCredentialRequest?.let {
CreateCredentialRequest.createFrom(
it
it
)
}
when (createCredentialRequestJetpack) {
is CreatePasswordRequest -> {
return RequestDisplayInfo(
createCredentialRequestJetpack.id,
createCredentialRequestJetpack.password,
createCredentialRequestJetpack.type,
requestInfo.appPackageName,
context.getDrawable(R.drawable.ic_password)!!
createCredentialRequestJetpack.id,
createCredentialRequestJetpack.password,
createCredentialRequestJetpack.type,
requestInfo.appPackageName,
context.getDrawable(R.drawable.ic_password)!!
)
}
is CreatePublicKeyCredentialRequest -> {
@@ -278,31 +278,31 @@ class CreateFlowUtils {
displayName = user.getString("displayName")
}
return RequestDisplayInfo(
name,
displayName,
createCredentialRequestJetpack.type,
requestInfo.appPackageName,
context.getDrawable(R.drawable.ic_passkey)!!)
name,
displayName,
createCredentialRequestJetpack.type,
requestInfo.appPackageName,
context.getDrawable(R.drawable.ic_passkey)!!)
}
// TODO: correctly parsing for other sign-ins
else -> {
return RequestDisplayInfo(
"beckett-bakert@gmail.com",
"Elisa Beckett",
"other-sign-ins",
requestInfo.appPackageName,
context.getDrawable(R.drawable.ic_other_sign_in)!!)
"beckett-bakert@gmail.com",
"Elisa Beckett",
"other-sign-ins",
requestInfo.appPackageName,
context.getDrawable(R.drawable.ic_other_sign_in)!!)
}
}
}
fun toCreateCredentialUiState(
enabledProviders: List<EnabledProviderInfo>,
disabledProviders: List<DisabledProviderInfo>?,
defaultProviderId: String?,
requestDisplayInfo: RequestDisplayInfo,
isOnPasskeyIntroStateAlready: Boolean,
isPasskeyFirstUse: Boolean,
enabledProviders: List<EnabledProviderInfo>,
disabledProviders: List<DisabledProviderInfo>?,
defaultProviderId: String?,
requestDisplayInfo: RequestDisplayInfo,
isOnPasskeyIntroStateAlready: Boolean,
isPasskeyFirstUse: Boolean,
): CreateCredentialUiState {
var lastSeenProviderWithNonEmptyCreateOptions: EnabledProviderInfo? = null
var remoteEntry: RemoteInfo? = null
@@ -310,7 +310,7 @@ class CreateFlowUtils {
var createOptionsPairs:
MutableList<Pair<CreateOptionInfo, EnabledProviderInfo>> = mutableListOf()
enabledProviders.forEach {
enabledProvider ->
enabledProvider ->
if (defaultProviderId != null) {
if (enabledProvider.id == defaultProviderId) {
defaultProvider = enabledProvider
@@ -327,10 +327,10 @@ class CreateFlowUtils {
}
}
return CreateCredentialUiState(
enabledProviders = enabledProviders,
disabledProviders = disabledProviders,
toCreateScreenState(
/*createOptionSize=*/createOptionsPairs.size,
enabledProviders = enabledProviders,
disabledProviders = disabledProviders,
toCreateScreenState(
/*createOptionSize=*/createOptionsPairs.size,
/*isOnPasskeyIntroStateAlready=*/isOnPasskeyIntroStateAlready,
/*requestDisplayInfo=*/requestDisplayInfo,
/*defaultProvider=*/defaultProvider, /*remoteEntry=*/remoteEntry,
@@ -341,31 +341,32 @@ class CreateFlowUtils {
toActiveEntry(
/*defaultProvider=*/defaultProvider,
/*createOptionSize=*/createOptionsPairs.size,
/*lastSeenProviderWithNonEmptyCreateOptions=*/lastSeenProviderWithNonEmptyCreateOptions,
/*remoteEntry=*/remoteEntry),
/*lastSeenProviderWithNonEmptyCreateOptions=*/
lastSeenProviderWithNonEmptyCreateOptions,
/*remoteEntry=*/remoteEntry),
)
}
private fun toCreateScreenState(
createOptionSize: Int,
isOnPasskeyIntroStateAlready: Boolean,
requestDisplayInfo: RequestDisplayInfo,
defaultProvider: EnabledProviderInfo?,
remoteEntry: RemoteInfo?,
isPasskeyFirstUse: Boolean,
createOptionSize: Int,
isOnPasskeyIntroStateAlready: Boolean,
requestDisplayInfo: RequestDisplayInfo,
defaultProvider: EnabledProviderInfo?,
remoteEntry: RemoteInfo?,
isPasskeyFirstUse: Boolean,
): CreateScreenState {
return if (
isPasskeyFirstUse && requestDisplayInfo
.type == TYPE_PUBLIC_KEY_CREDENTIAL && !isOnPasskeyIntroStateAlready) {
isPasskeyFirstUse && requestDisplayInfo
.type == TYPE_PUBLIC_KEY_CREDENTIAL && !isOnPasskeyIntroStateAlready) {
CreateScreenState.PASSKEY_INTRO
} else if (
(defaultProvider == null || defaultProvider.createOptions.isEmpty()
) && createOptionSize > 1) {
(defaultProvider == null || defaultProvider.createOptions.isEmpty()
) && createOptionSize > 1) {
CreateScreenState.PROVIDER_SELECTION
} else if (
((defaultProvider == null || defaultProvider.createOptions.isEmpty()
) && createOptionSize == 1) || (
defaultProvider != null && defaultProvider.createOptions.isNotEmpty())) {
((defaultProvider == null || defaultProvider.createOptions.isEmpty()
) && createOptionSize == 1) || (
defaultProvider != null && defaultProvider.createOptions.isNotEmpty())) {
CreateScreenState.CREATION_OPTION_SELECTION
} else if (createOptionSize == 0 && remoteEntry != null) {
CreateScreenState.EXTERNAL_ONLY_SELECTION
@@ -376,65 +377,66 @@ class CreateFlowUtils {
}
private fun toActiveEntry(
defaultProvider: EnabledProviderInfo?,
createOptionSize: Int,
lastSeenProviderWithNonEmptyCreateOptions: EnabledProviderInfo?,
remoteEntry: RemoteInfo?,
defaultProvider: EnabledProviderInfo?,
createOptionSize: Int,
lastSeenProviderWithNonEmptyCreateOptions: EnabledProviderInfo?,
remoteEntry: RemoteInfo?,
): ActiveEntry? {
return if (
defaultProvider != null && defaultProvider.createOptions.isEmpty() && remoteEntry != null) {
defaultProvider != null && defaultProvider.createOptions.isEmpty() &&
remoteEntry != null) {
ActiveEntry(defaultProvider, remoteEntry)
} else if (
defaultProvider != null && defaultProvider.createOptions.isNotEmpty()
defaultProvider != null && defaultProvider.createOptions.isNotEmpty()
) {
ActiveEntry(defaultProvider, defaultProvider.createOptions.first())
} else if (createOptionSize == 1) {
ActiveEntry(lastSeenProviderWithNonEmptyCreateOptions!!,
lastSeenProviderWithNonEmptyCreateOptions.createOptions.first())
lastSeenProviderWithNonEmptyCreateOptions.createOptions.first())
} else null
}
private fun toCreationOptionInfoList(
providerId: String,
creationEntries: List<Entry>,
context: Context,
providerId: String,
creationEntries: List<Entry>,
context: Context,
): List<CreateOptionInfo> {
return creationEntries.map {
// TODO: handle NPE gracefully
val createEntry = CreateEntry.fromSlice(it.slice)!!
return@map CreateOptionInfo(
// TODO: remove fallbacks
providerId = providerId,
entryKey = it.key,
entrySubkey = it.subkey,
pendingIntent = it.pendingIntent,
fillInIntent = it.frameworkExtrasIntent,
userProviderDisplayName = createEntry.accountName.toString(),
profileIcon = createEntry.icon?.loadDrawable(context),
passwordCount = CredentialCountInformation.getPasswordCount(
createEntry.credentialCountInformationList) ?: 0,
passkeyCount = CredentialCountInformation.getPasskeyCount(
createEntry.credentialCountInformationList) ?: 0,
totalCredentialCount = CredentialCountInformation.getTotalCount(
createEntry.credentialCountInformationList) ?: 0,
lastUsedTimeMillis = createEntry.lastUsedTimeMillis ?: 0,
// TODO: remove fallbacks
providerId = providerId,
entryKey = it.key,
entrySubkey = it.subkey,
pendingIntent = createEntry.pendingIntent,
fillInIntent = it.frameworkExtrasIntent,
userProviderDisplayName = createEntry.accountName.toString(),
profileIcon = createEntry.icon?.loadDrawable(context),
passwordCount = CredentialCountInformation.getPasswordCount(
createEntry.credentialCountInformationList) ?: 0,
passkeyCount = CredentialCountInformation.getPasskeyCount(
createEntry.credentialCountInformationList) ?: 0,
totalCredentialCount = CredentialCountInformation.getTotalCount(
createEntry.credentialCountInformationList) ?: 0,
lastUsedTimeMillis = createEntry.lastUsedTimeMillis ?: 0,
)
}
}
private fun toRemoteInfo(
providerId: String,
remoteEntry: Entry?,
providerId: String,
remoteEntry: Entry?,
): RemoteInfo? {
// TODO: should also call fromSlice after getting the official jetpack code.
return if (remoteEntry != null) {
RemoteInfo(
providerId = providerId,
entryKey = remoteEntry.key,
entrySubkey = remoteEntry.subkey,
pendingIntent = remoteEntry.pendingIntent,
fillInIntent = remoteEntry.frameworkExtrasIntent,
providerId = providerId,
entryKey = remoteEntry.key,
entrySubkey = remoteEntry.subkey,
pendingIntent = remoteEntry.pendingIntent,
fillInIntent = remoteEntry.frameworkExtrasIntent,
)
} else null
}

View File

@@ -72,7 +72,7 @@ public final class GetRequestSession extends RequestSession<GetCredentialRequest
try {
mClientCallback.onPendingIntent(mCredentialManagerUi.createPendingIntent(
RequestInfo.newGetRequestInfo(
mRequestId, null, ""),
mRequestId, mClientRequest, mClientAppInfo.getPackageName()),
providerDataList));
} catch (RemoteException e) {
Log.i(TAG, "Issue with invoking pending intent: " + e.getMessage());

View File

@@ -19,7 +19,6 @@ package com.android.server.credentials;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.credentials.CreateCredentialException;
@@ -211,14 +210,13 @@ public final class ProviderCreateSession extends ProviderSession<
mUiSaveEntries.put(entryId, createEntry);
Log.i(TAG, "in prepareUiProviderData creating ui entry with id " + entryId);
uiSaveEntries.add(new Entry(SAVE_ENTRY_KEY, entryId, createEntry.getSlice(),
createEntry.getPendingIntent(), setUpFillInIntent(
createEntry.getPendingIntent())));
setUpFillInIntent()));
}
return uiSaveEntries;
}
private Intent setUpFillInIntent(PendingIntent pendingIntent) {
Intent intent = pendingIntent.getIntent();
private Intent setUpFillInIntent() {
Intent intent = new Intent();
intent.putExtra(CredentialProviderService.EXTRA_CREATE_CREDENTIAL_REQUEST,
mCompleteRequest);
return intent;

View File

@@ -19,7 +19,6 @@ package com.android.server.credentials;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.credentials.GetCredentialException;
@@ -288,8 +287,8 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
private Entry prepareUiAuthenticationAction(@NonNull Action authenticationAction) {
String entryId = generateEntryId();
Entry authEntry = new Entry(
AUTHENTICATION_ACTION_ENTRY_KEY, entryId, authenticationAction.getSlice(),
authenticationAction.getPendingIntent(), /*fillInIntent=*/null);
AUTHENTICATION_ACTION_ENTRY_KEY, entryId,
authenticationAction.getSlice());
mUiAuthenticationAction = new Pair<>(entryId, authenticationAction);
return authEntry;
}
@@ -304,20 +303,15 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
String entryId = generateEntryId();
mUiCredentialEntries.put(entryId, credentialEntry);
Log.i(TAG, "in prepareUiProviderData creating ui entry with id " + entryId);
if (credentialEntry.getPendingIntent() != null) {
credentialUiEntries.add(new Entry(CREDENTIAL_ENTRY_KEY, entryId,
credentialEntry.getSlice(), credentialEntry.getPendingIntent(),
setUpFillInIntent(credentialEntry.getPendingIntent(),
credentialEntry.getType())));
} else {
Log.i(TAG, "No pending intent. Should not happen.");
}
credentialUiEntries.add(new Entry(CREDENTIAL_ENTRY_KEY, entryId,
credentialEntry.getSlice(),
/*fillInIntent=*/setUpFillInIntent(credentialEntry.getType())));
}
return credentialUiEntries;
}
private Intent setUpFillInIntent(PendingIntent pendingIntent, String type) {
Intent intent = pendingIntent.getIntent();
private Intent setUpFillInIntent(String type) {
Intent intent = new Intent();
for (GetCredentialOption option : mCompleteRequest.getGetCredentialOptions()) {
if (option.getType().equals(type)) {
intent.putExtra(
@@ -336,8 +330,7 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
String entryId = UUID.randomUUID().toString();
mUiActionsEntries.put(entryId, action);
// TODO : Remove conversion of string to int after change in Entry class
actionEntries.add(new Entry(ACTION_ENTRY_KEY, entryId, action.getSlice(),
action.getPendingIntent(), /*fillInIntent=*/null));
actionEntries.add(new Entry(ACTION_ENTRY_KEY, entryId, action.getSlice()));
}
return actionEntries;
}
@@ -388,7 +381,7 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
private void onAuthenticationEntrySelected(
@Nullable ProviderPendingIntentResponse providerPendingIntentResponse) {
//TODO: Other provider intent statuses
//TODO: Other provider intent statuses
// Check if pending intent has an error
GetCredentialException exception = maybeGetPendingIntentException(
providerPendingIntentResponse);