/* * 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.selection; import static android.credentials.flags.Flags.FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED; import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.StringDef; import android.annotation.SystemApi; import android.annotation.TestApi; import android.credentials.CreateCredentialRequest; import android.credentials.GetCredentialRequest; import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; import com.android.internal.util.AnnotationValidations; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.List; /** * Contains information about the request that initiated this UX flow. * * @hide */ @SystemApi @FlaggedApi(FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED) public final class RequestInfo implements Parcelable { /** * The intent extra key for the {@code RequestInfo} object when launching the UX * activities. * * @hide */ @NonNull public static final String EXTRA_REQUEST_INFO = "android.credentials.selection.extra.REQUEST_INFO"; /** * Type value for any request that does not require UI. */ @NonNull public static final String TYPE_UNDEFINED = "android.credentials.selection.TYPE_UNDEFINED"; /** * Type value for a getCredential request. */ @NonNull public static final String TYPE_GET = "android.credentials.selection.TYPE_GET"; /** * Type value for a getCredential request that utilizes the credential registry. * * @hide */ @NonNull public static final String TYPE_GET_VIA_REGISTRY = "android.credentials.selection.TYPE_GET_VIA_REGISTRY"; /** * Type value for a createCredential request. */ @NonNull public static final String TYPE_CREATE = "android.credentials.selection.TYPE_CREATE"; /** @hide */ @Retention(RetentionPolicy.SOURCE) @StringDef(value = {TYPE_GET, TYPE_CREATE, TYPE_UNDEFINED}) public @interface RequestType { } @NonNull private final IBinder mToken; @Nullable private final CreateCredentialRequest mCreateCredentialRequest; @NonNull private final List mDefaultProviderIds; @NonNull private final List mRegistryProviderIds; @Nullable private final GetCredentialRequest mGetCredentialRequest; @NonNull @RequestType private final String mType; @NonNull private final String mPackageName; private final boolean mHasPermissionToOverrideDefault; private final boolean mIsShowAllOptionsRequested; /** * Creates new {@code RequestInfo} for a create-credential flow. * * @hide */ @TestApi @FlaggedApi(FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED) @NonNull public static RequestInfo newCreateRequestInfo( @NonNull IBinder token, @NonNull CreateCredentialRequest createCredentialRequest, @NonNull String appPackageName, boolean hasPermissionToOverrideDefault, @NonNull List defaultProviderIds, boolean isShowAllOptionsRequested) { return new RequestInfo( token, TYPE_CREATE, appPackageName, createCredentialRequest, null, hasPermissionToOverrideDefault, defaultProviderIds, isShowAllOptionsRequested); } /** * Creates new {@code RequestInfo} for a get-credential flow. * * @hide */ @TestApi @FlaggedApi(FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED) @NonNull public static RequestInfo newGetRequestInfo( @NonNull IBinder token, @NonNull GetCredentialRequest getCredentialRequest, @NonNull String appPackageName, boolean hasPermissionToOverrideDefault, boolean isShowAllOptionsRequested) { return new RequestInfo( token, TYPE_GET, appPackageName, null, getCredentialRequest, hasPermissionToOverrideDefault, /*defaultProviderIds=*/ new ArrayList<>(), isShowAllOptionsRequested); } /** Returns whether the calling package has the permission. */ public boolean hasPermissionToOverrideDefault() { return mHasPermissionToOverrideDefault; } /** * Returns the request token matching the user request. * * @hide */ @NonNull public IBinder getToken() { return mToken; } /** Returns the request type. */ @NonNull @RequestType public String getType() { return mType; } /** Returns the display name of the app that made this request. */ @NonNull public String getPackageName() { return mPackageName; } /** * Returns the non-null CreateCredentialRequest when the type of the request is {@link * #TYPE_CREATE}, or null otherwise. */ @Nullable public CreateCredentialRequest getCreateCredentialRequest() { return mCreateCredentialRequest; } /** Returns the request token matching the app request that should be cancelled. */ @NonNull public RequestToken getRequestToken() { return new RequestToken(mToken); } /** * Returns default provider identifiers (component or package name) configured from the user * settings. * * Will only be possibly non-empty for the create use case. Not meaningful for the sign-in use * case. */ @NonNull public List getDefaultProviderIds() { return mDefaultProviderIds; } /** * Returns provider identifiers (component or package name) that have been validated to provide * registry entries. */ @NonNull public List getRegistryProviderIds() { return mRegistryProviderIds; } /** * Returns the non-null GetCredentialRequest when the type of the request is {@link * #TYPE_GET}, or null otherwise. */ @Nullable public GetCredentialRequest getGetCredentialRequest() { return mGetCredentialRequest; } /** * Returns true if all options should be immediately displayed in the UI, and false otherwise. * * Normally this bit is set to false, upon which the selection UI should first display a * condensed view of popular, deduplicated options that is determined based on signals like * last-used timestamps, credential type priorities, and preferred providers configured from the * user settings {@link #getDefaultProviderIds()}; at the same time, the UI should offer an * option (button) that navigates the user to viewing all options from this condensed view. * * In some special occasions, e.g. when a request is initiated from the autofill drop-down * suggestion, this bit will be set to true to indicate that the selection UI should immediately * render the all option UI. This means that the request initiator has collected a user signal * to confirm that the user wants to view all the available options at once. */ public boolean isShowAllOptionsRequested() { return mIsShowAllOptionsRequested; } private RequestInfo(@NonNull IBinder token, @NonNull @RequestType String type, @NonNull String appPackageName, @Nullable CreateCredentialRequest createCredentialRequest, @Nullable GetCredentialRequest getCredentialRequest, boolean hasPermissionToOverrideDefault, @NonNull List defaultProviderIds, boolean isShowAllOptionsRequested) { mToken = token; mType = type; mPackageName = appPackageName; mCreateCredentialRequest = createCredentialRequest; mGetCredentialRequest = getCredentialRequest; mHasPermissionToOverrideDefault = hasPermissionToOverrideDefault; mDefaultProviderIds = defaultProviderIds == null ? new ArrayList<>() : defaultProviderIds; mRegistryProviderIds = new ArrayList<>(); mIsShowAllOptionsRequested = isShowAllOptionsRequested; } private RequestInfo(@NonNull Parcel in) { IBinder token = in.readStrongBinder(); String type = in.readString8(); String appPackageName = in.readString8(); CreateCredentialRequest createCredentialRequest = in.readTypedObject(CreateCredentialRequest.CREATOR); GetCredentialRequest getCredentialRequest = in.readTypedObject(GetCredentialRequest.CREATOR); mToken = token; AnnotationValidations.validate(NonNull.class, null, mToken); mType = type; AnnotationValidations.validate(NonNull.class, null, mType); mPackageName = appPackageName; AnnotationValidations.validate(NonNull.class, null, mPackageName); mCreateCredentialRequest = createCredentialRequest; mGetCredentialRequest = getCredentialRequest; mHasPermissionToOverrideDefault = in.readBoolean(); mDefaultProviderIds = in.createStringArrayList(); mRegistryProviderIds = in.createStringArrayList(); mIsShowAllOptionsRequested = in.readBoolean(); } @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeStrongBinder(mToken); dest.writeString8(mType); dest.writeString8(mPackageName); dest.writeTypedObject(mCreateCredentialRequest, flags); dest.writeTypedObject(mGetCredentialRequest, flags); dest.writeBoolean(mHasPermissionToOverrideDefault); dest.writeStringList(mDefaultProviderIds); dest.writeStringList(mRegistryProviderIds); dest.writeBoolean(mIsShowAllOptionsRequested); } @Override public int describeContents() { return 0; } @NonNull public static final Creator CREATOR = new Creator<>() { @Override public RequestInfo createFromParcel(@NonNull Parcel in) { return new RequestInfo(in); } @Override public RequestInfo[] newArray(int size) { return new RequestInfo[size]; } }; }