Merge "Remove pending intent from framework provider APIs"
This commit is contained in:
committed by
Android (Google) Code Review
commit
2610a620a5
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user