Loading core/java/android/service/credentials/Action.java 0 → 100644 +98 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.service.credentials; import android.app.PendingIntent; import android.app.slice.Slice; import android.os.Parcel; import android.os.Parcelable; import androidx.annotation.NonNull; import java.util.Objects; /** * An action defined by the provider that intents into the provider's app for specific * user actions. * * @hide */ public final class Action implements Parcelable { /** Info to be displayed with this action on the UI. */ private final @NonNull Slice mInfo; /** * The pending intent to be invoked when the user selects this action. */ private final @NonNull PendingIntent mPendingIntent; /** * Constructs an action to be displayed on the UI. * * @param actionInfo The info to be displayed along with this action. * @param pendingIntent The intent to be invoked when the user selects this action. * @throws NullPointerException If {@code actionInfo}, or {@code pendingIntent} is null. */ public Action(@NonNull Slice actionInfo, @NonNull PendingIntent pendingIntent) { Objects.requireNonNull(actionInfo, "actionInfo must not be null"); Objects.requireNonNull(pendingIntent, "pendingIntent must not be null"); mInfo = actionInfo; mPendingIntent = pendingIntent; } private Action(@NonNull Parcel in) { mInfo = in.readParcelable(Slice.class.getClassLoader(), Slice.class); mPendingIntent = in.readParcelable(PendingIntent.class.getClassLoader(), PendingIntent.class); } public static final @NonNull Creator<Action> CREATOR = new Creator<Action>() { @Override public Action createFromParcel(@NonNull Parcel in) { return new Action(in); } @Override public Action[] newArray(int size) { return new Action[size]; } }; @Override public int describeContents() { return 0; } @Override public void writeToParcel(@NonNull Parcel dest, int flags) { mInfo.writeToParcel(dest, flags); mPendingIntent.writeToParcel(dest, flags); } /** * Returns the action info as a {@link Slice} object, to be displayed on the UI. */ public @NonNull Slice getActionInfo() { return mInfo; } /** * Returns the {@link PendingIntent} to be invoked when the action is selected. */ public @NonNull PendingIntent getPendingIntent() { return mPendingIntent; } } core/java/android/service/credentials/Credential.java 0 → 100644 +100 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.service.credentials; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; import androidx.annotation.NonNull; import static java.util.Objects.requireNonNull; import com.android.internal.util.Preconditions; /** * A Credential object that contains type specific data that is returned from the credential * provider to the framework. Framework then converts it to an app facing representation and * returns to the calling app. * * @hide */ public final class Credential implements Parcelable { /** The type of this credential. */ private final @NonNull String mType; /** The data associated with this credential. */ private final @NonNull Bundle mData; /** * Constructs a credential object. * * @param type The type of the credential. * @param data The data of the credential that is passed back to the framework, and eventually * to the calling app. * @throws NullPointerException If {@code data} is null. * @throws IllegalArgumentException If {@code type} is null or empty. */ public Credential(@NonNull String type, @NonNull Bundle data) { Preconditions.checkStringNotEmpty(type, "type must not be null, or empty"); requireNonNull(data, "data must not be null"); this.mType = type; this.mData = data; } private Credential(@NonNull Parcel in) { mType = in.readString16NoHelper(); mData = in.readBundle(); } /** * Returns the type of the credential. */ public @NonNull String getType() { return mType; } /** * Returns the data associated with the credential. */ public @NonNull Bundle getData() { return mData; } public static final @NonNull Creator<Credential> CREATOR = new Creator<Credential>() { @Override public Credential createFromParcel(@NonNull Parcel in) { return new Credential(in); } @Override public Credential[] newArray(int size) { return new Credential[size]; } }; @Override public int describeContents() { return 0; } @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeString8(mType); dest.writeBundle(mData); } } core/java/android/service/credentials/CredentialEntry.java 0 → 100644 +216 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.service.credentials; import android.annotation.Nullable; import android.app.PendingIntent; import android.app.slice.Slice; import android.os.Parcel; import android.os.Parcelable; import androidx.annotation.NonNull; import com.android.internal.util.Preconditions; import java.util.Objects; /** * A credential entry that is displayed on the account selector UI. Each entry corresponds to * something that the user can select. * * @hide */ public final class CredentialEntry implements Parcelable { /** The type of the credential entry to be shown on the UI. */ private final @NonNull String mType; /** The info to be displayed along with this credential entry on the UI. */ private final @NonNull Slice mInfo; /** The pending intent to be invoked when this credential entry is selected. */ private final @Nullable PendingIntent mPendingIntent; /** * The underlying credential to be returned to the app when the user selects * this credential entry. */ private final @Nullable Credential mCredential; /** A flag denoting whether auto-select is enabled for this entry. */ private final @NonNull boolean mAutoSelectAllowed; private CredentialEntry(@NonNull String type, @NonNull Slice entryInfo, @Nullable PendingIntent pendingIntent, @Nullable Credential credential, @NonNull boolean autoSeletAllowed) { mType = type; mInfo = entryInfo; mPendingIntent = pendingIntent; mCredential = credential; mAutoSelectAllowed = autoSeletAllowed; } private CredentialEntry(@NonNull Parcel in) { mType = in.readString(); mInfo = in.readParcelable(Slice.class.getClassLoader(), Slice.class); mPendingIntent = in.readParcelable(PendingIntent.class.getClassLoader(), PendingIntent.class); mCredential = in.readParcelable(Credential.class.getClassLoader(), Credential.class); mAutoSelectAllowed = in.readBoolean(); } public static final @NonNull Creator<CredentialEntry> CREATOR = new Creator<CredentialEntry>() { @Override public CredentialEntry createFromParcel(@NonNull Parcel in) { return new CredentialEntry(in); } @Override public CredentialEntry[] newArray(int size) { return new CredentialEntry[size]; } }; @Override public int describeContents() { return 0; } @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeString8(mType); mInfo.writeToParcel(dest, flags); mPendingIntent.writeToParcel(dest, flags); mCredential.writeToParcel(dest, flags); dest.writeBoolean(mAutoSelectAllowed); } /** * Returns the specific credential type of the entry. */ public @NonNull String getType() { return mType; } /** * Returns the UI info to be displayed for this entry. */ public @NonNull Slice getInfo() { return mInfo; } /** * Returns the pending intent to be invoked if the user selects this entry. */ public @Nullable PendingIntent getPendingIntent() { return mPendingIntent; } /** * Returns the credential associated with this entry. */ public @Nullable Credential getCredential() { return mCredential; } /** * Returns whether this entry can be auto selected if it is the only option for the user. */ public @NonNull boolean isAutoSelectAllowed() { return mAutoSelectAllowed; } /** * Builder for {@link CredentialEntry}. */ public static final class Builder { private String mType; private Slice mInfo; private PendingIntent mPendingIntent; private Credential mCredential; private boolean mAutoSelectAllowed = false; /** * Builds the instance. * @param type The type of credential underlying this credential entry. * @param info The info to be displayed with this entry on the UI. * * @throws IllegalArgumentException If {@code type} is null or empty. * @throws NullPointerException If {@code info} is null. */ public Builder(@NonNull String type, @NonNull Slice info) { mType = Preconditions.checkStringNotEmpty(type, "type must not be " + "null, or empty"); mInfo = Objects.requireNonNull(info, "info must not be null"); } /** * Sets the pendingIntent to be invoked if the user selects this entry. * * @throws IllegalStateException If {@code credential} is already set. Must either set the * {@code credential}, or the {@code pendingIntent}. */ public @NonNull Builder setPendingIntent(@Nullable PendingIntent pendingIntent) { Preconditions.checkState(pendingIntent != null && mCredential != null, "credential is already set. Cannot set both the pendingIntent " + "and the credential"); mPendingIntent = pendingIntent; return this; } /** * Sets the credential to be used, if the user selects this entry. * * @throws IllegalStateException If {@code pendingIntent} is already set. Must either set * the {@code pendingIntent}, or the {@code credential}. */ public @NonNull Builder setCredential(@Nullable Credential credential) { Preconditions.checkState(credential != null && mPendingIntent != null, "pendingIntent is already set. Cannot set both the " + "pendingIntent and the credential"); mCredential = credential; return this; } /** * Sets whether the entry is allowed to be auto selected by the framework. * The default value is set to false. */ public @NonNull Builder setAutoSelectAllowed(@NonNull boolean autoSelectAllowed) { mAutoSelectAllowed = autoSelectAllowed; return this; } /** * Creates a new {@link CredentialEntry} instance. * * @throws NullPointerException If {@code info} is null. * @throws IllegalArgumentException If {@code type} is null, or empty. * @throws IllegalStateException If neither {@code pendingIntent} nor {@code credential} * is set, or if both are set. */ public @NonNull CredentialEntry build() { Preconditions.checkState(mPendingIntent == null && mCredential == null, "Either pendingIntent or credential must be set"); Preconditions.checkState(mPendingIntent != null && mCredential != null, "Cannot set both the pendingIntent and credential"); return new CredentialEntry(mType, mInfo, mPendingIntent, mCredential, mAutoSelectAllowed); } } } core/java/android/service/credentials/CredentialProviderService.java 0 → 100644 +91 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.service.credentials; import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; import android.annotation.CallSuper; import android.annotation.NonNull; import android.app.Service; import android.content.Intent; import android.os.CancellationSignal; import android.os.Handler; import android.os.IBinder; import android.os.ICancellationSignal; import android.os.Looper; import android.os.RemoteException; import android.util.Log; import java.util.Objects; /** * Main service to be extended by credential providers, in order to return user credentials * to the framework. * * @hide */ public abstract class CredentialProviderService extends Service { private static final String TAG = "CredProviderService"; private Handler mHandler; public static final String SERVICE_INTERFACE = "android.service.credentials.CredentialProviderService"; @CallSuper @Override public void onCreate() { super.onCreate(); mHandler = new Handler(Looper.getMainLooper(), null, true); } @Override public final @NonNull IBinder onBind(@NonNull Intent intent) { if (SERVICE_INTERFACE.equals(intent.getAction())) { return mInterface.asBinder(); } Log.i(TAG, "Failed to bind with intent: " + intent); return null; } private final ICredentialProviderService mInterface = new ICredentialProviderService.Stub() { @Override public void onGetCredentials(GetCredentialsRequest request, ICancellationSignal transport, IGetCredentialsCallback callback) throws RemoteException { Objects.requireNonNull(request); Objects.requireNonNull(callback); mHandler.sendMessage(obtainMessage( CredentialProviderService::onGetCredentials, CredentialProviderService.this, request, CancellationSignal.fromTransport(transport), new GetCredentialsCallback(callback) )); } }; /** * Called by the android system to retrieve user credentials from the connected provider * service. * @param request The credential request for the provider to handle. * @param cancellationSignal Signal for providers to listen to any cancellation requests from * the android system. * @param callback Object used to relay the response of the credentials request. */ public abstract void onGetCredentials(@NonNull GetCredentialsRequest request, @NonNull CancellationSignal cancellationSignal, @NonNull GetCredentialsCallback callback); } core/java/android/service/credentials/CredentialsDisplayContent.java 0 → 100644 +188 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.service.credentials; import android.annotation.Nullable; import android.os.Parcel; import android.os.Parcelable; import androidx.annotation.NonNull; import com.android.internal.util.Preconditions; import java.util.ArrayList; import java.util.List; import java.util.Objects; /** * Content to be displayed on the account selector UI, including credential entries, * actions etc. * * @hide */ public final class CredentialsDisplayContent implements Parcelable { /** Header to be displayed on the UI. */ private final @Nullable CharSequence mHeader; /** List of credential entries to be displayed on the UI. */ private final @NonNull List<CredentialEntry> mCredentialEntries; /** List of provider actions to be displayed on the UI. */ private final @NonNull List<Action> mActions; private CredentialsDisplayContent(@Nullable CharSequence header, @NonNull List<CredentialEntry> credentialEntries, @NonNull List<Action> actions) { mHeader = header; mCredentialEntries = credentialEntries; mActions = actions; } private CredentialsDisplayContent(@NonNull Parcel in) { mHeader = in.readCharSequence(); mCredentialEntries = in.createTypedArrayList(CredentialEntry.CREATOR); mActions = in.createTypedArrayList(Action.CREATOR); } public static final @NonNull Creator<CredentialsDisplayContent> CREATOR = new Creator<CredentialsDisplayContent>() { @Override public CredentialsDisplayContent createFromParcel(@NonNull Parcel in) { return new CredentialsDisplayContent(in); } @Override public CredentialsDisplayContent[] newArray(int size) { return new CredentialsDisplayContent[size]; } }; @Override public int describeContents() { return 0; } @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeCharSequence(mHeader); dest.writeTypedList(mCredentialEntries); dest.writeTypedList(mActions); } /** * Returns the header to be displayed on the UI. */ public @Nullable CharSequence getHeader() { return mHeader; } /** * Returns the list of credential entries to be displayed on the UI. */ public @NonNull List<CredentialEntry> getCredentialEntries() { return mCredentialEntries; } /** * Returns the list of actions to be displayed on the UI. */ public @NonNull List<Action> getActions() { return mActions; } /** * Builds an instance of {@link CredentialsDisplayContent}. */ public static final class Builder { private CharSequence mHeader = null; private List<CredentialEntry> mCredentialEntries = new ArrayList<>(); private List<Action> mActions = new ArrayList<>(); /** * Sets the header to be displayed on the UI. */ public @NonNull Builder setHeader(@Nullable CharSequence header) { mHeader = header; return this; } /** * Adds a {@link CredentialEntry} to the list of entries to be displayed on * the UI. * * @throws NullPointerException If the {@code credentialEntry} is null. */ public @NonNull Builder addCredentialEntry(@NonNull CredentialEntry credentialEntry) { mCredentialEntries.add(Objects.requireNonNull(credentialEntry)); return this; } /** * Adds an {@link Action} to the list of actions to be displayed on * the UI. * * @throws NullPointerException If {@code action} is null. */ public @NonNull Builder addAction(@NonNull Action action) { mActions.add(Objects.requireNonNull(action, "action must not be null")); return this; } /** * Sets the list of actions to be displayed on the UI. * * @throws NullPointerException If {@code actions} is null, or any of its elements * is null. */ public @NonNull Builder setActions(@NonNull List<Action> actions) { mActions = Preconditions.checkCollectionElementsNotNull(actions, "actions"); return this; } /** * Sets the list of credential entries to be displayed on the * account selector UI. * * @throws NullPointerException If {@code credentialEntries} is null, or any of its * elements is null. */ public @NonNull Builder setCredentialEntries( @NonNull List<CredentialEntry> credentialEntries) { mCredentialEntries = Preconditions.checkCollectionElementsNotNull( credentialEntries, "credentialEntries"); return this; } /** * Builds a {@link GetCredentialsResponse} instance. * * @throws NullPointerException If {@code credentialEntries} is null. * @throws IllegalStateException if both {@code credentialEntries} and * {@code actions} are empty. */ public @NonNull CredentialsDisplayContent build() { if (mCredentialEntries != null && mCredentialEntries.isEmpty() && mActions != null && mActions.isEmpty()) { throw new IllegalStateException("credentialEntries and actions must not both " + "be empty"); } return new CredentialsDisplayContent(mHeader, mCredentialEntries, mActions); } } } Loading
core/java/android/service/credentials/Action.java 0 → 100644 +98 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.service.credentials; import android.app.PendingIntent; import android.app.slice.Slice; import android.os.Parcel; import android.os.Parcelable; import androidx.annotation.NonNull; import java.util.Objects; /** * An action defined by the provider that intents into the provider's app for specific * user actions. * * @hide */ public final class Action implements Parcelable { /** Info to be displayed with this action on the UI. */ private final @NonNull Slice mInfo; /** * The pending intent to be invoked when the user selects this action. */ private final @NonNull PendingIntent mPendingIntent; /** * Constructs an action to be displayed on the UI. * * @param actionInfo The info to be displayed along with this action. * @param pendingIntent The intent to be invoked when the user selects this action. * @throws NullPointerException If {@code actionInfo}, or {@code pendingIntent} is null. */ public Action(@NonNull Slice actionInfo, @NonNull PendingIntent pendingIntent) { Objects.requireNonNull(actionInfo, "actionInfo must not be null"); Objects.requireNonNull(pendingIntent, "pendingIntent must not be null"); mInfo = actionInfo; mPendingIntent = pendingIntent; } private Action(@NonNull Parcel in) { mInfo = in.readParcelable(Slice.class.getClassLoader(), Slice.class); mPendingIntent = in.readParcelable(PendingIntent.class.getClassLoader(), PendingIntent.class); } public static final @NonNull Creator<Action> CREATOR = new Creator<Action>() { @Override public Action createFromParcel(@NonNull Parcel in) { return new Action(in); } @Override public Action[] newArray(int size) { return new Action[size]; } }; @Override public int describeContents() { return 0; } @Override public void writeToParcel(@NonNull Parcel dest, int flags) { mInfo.writeToParcel(dest, flags); mPendingIntent.writeToParcel(dest, flags); } /** * Returns the action info as a {@link Slice} object, to be displayed on the UI. */ public @NonNull Slice getActionInfo() { return mInfo; } /** * Returns the {@link PendingIntent} to be invoked when the action is selected. */ public @NonNull PendingIntent getPendingIntent() { return mPendingIntent; } }
core/java/android/service/credentials/Credential.java 0 → 100644 +100 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.service.credentials; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; import androidx.annotation.NonNull; import static java.util.Objects.requireNonNull; import com.android.internal.util.Preconditions; /** * A Credential object that contains type specific data that is returned from the credential * provider to the framework. Framework then converts it to an app facing representation and * returns to the calling app. * * @hide */ public final class Credential implements Parcelable { /** The type of this credential. */ private final @NonNull String mType; /** The data associated with this credential. */ private final @NonNull Bundle mData; /** * Constructs a credential object. * * @param type The type of the credential. * @param data The data of the credential that is passed back to the framework, and eventually * to the calling app. * @throws NullPointerException If {@code data} is null. * @throws IllegalArgumentException If {@code type} is null or empty. */ public Credential(@NonNull String type, @NonNull Bundle data) { Preconditions.checkStringNotEmpty(type, "type must not be null, or empty"); requireNonNull(data, "data must not be null"); this.mType = type; this.mData = data; } private Credential(@NonNull Parcel in) { mType = in.readString16NoHelper(); mData = in.readBundle(); } /** * Returns the type of the credential. */ public @NonNull String getType() { return mType; } /** * Returns the data associated with the credential. */ public @NonNull Bundle getData() { return mData; } public static final @NonNull Creator<Credential> CREATOR = new Creator<Credential>() { @Override public Credential createFromParcel(@NonNull Parcel in) { return new Credential(in); } @Override public Credential[] newArray(int size) { return new Credential[size]; } }; @Override public int describeContents() { return 0; } @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeString8(mType); dest.writeBundle(mData); } }
core/java/android/service/credentials/CredentialEntry.java 0 → 100644 +216 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.service.credentials; import android.annotation.Nullable; import android.app.PendingIntent; import android.app.slice.Slice; import android.os.Parcel; import android.os.Parcelable; import androidx.annotation.NonNull; import com.android.internal.util.Preconditions; import java.util.Objects; /** * A credential entry that is displayed on the account selector UI. Each entry corresponds to * something that the user can select. * * @hide */ public final class CredentialEntry implements Parcelable { /** The type of the credential entry to be shown on the UI. */ private final @NonNull String mType; /** The info to be displayed along with this credential entry on the UI. */ private final @NonNull Slice mInfo; /** The pending intent to be invoked when this credential entry is selected. */ private final @Nullable PendingIntent mPendingIntent; /** * The underlying credential to be returned to the app when the user selects * this credential entry. */ private final @Nullable Credential mCredential; /** A flag denoting whether auto-select is enabled for this entry. */ private final @NonNull boolean mAutoSelectAllowed; private CredentialEntry(@NonNull String type, @NonNull Slice entryInfo, @Nullable PendingIntent pendingIntent, @Nullable Credential credential, @NonNull boolean autoSeletAllowed) { mType = type; mInfo = entryInfo; mPendingIntent = pendingIntent; mCredential = credential; mAutoSelectAllowed = autoSeletAllowed; } private CredentialEntry(@NonNull Parcel in) { mType = in.readString(); mInfo = in.readParcelable(Slice.class.getClassLoader(), Slice.class); mPendingIntent = in.readParcelable(PendingIntent.class.getClassLoader(), PendingIntent.class); mCredential = in.readParcelable(Credential.class.getClassLoader(), Credential.class); mAutoSelectAllowed = in.readBoolean(); } public static final @NonNull Creator<CredentialEntry> CREATOR = new Creator<CredentialEntry>() { @Override public CredentialEntry createFromParcel(@NonNull Parcel in) { return new CredentialEntry(in); } @Override public CredentialEntry[] newArray(int size) { return new CredentialEntry[size]; } }; @Override public int describeContents() { return 0; } @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeString8(mType); mInfo.writeToParcel(dest, flags); mPendingIntent.writeToParcel(dest, flags); mCredential.writeToParcel(dest, flags); dest.writeBoolean(mAutoSelectAllowed); } /** * Returns the specific credential type of the entry. */ public @NonNull String getType() { return mType; } /** * Returns the UI info to be displayed for this entry. */ public @NonNull Slice getInfo() { return mInfo; } /** * Returns the pending intent to be invoked if the user selects this entry. */ public @Nullable PendingIntent getPendingIntent() { return mPendingIntent; } /** * Returns the credential associated with this entry. */ public @Nullable Credential getCredential() { return mCredential; } /** * Returns whether this entry can be auto selected if it is the only option for the user. */ public @NonNull boolean isAutoSelectAllowed() { return mAutoSelectAllowed; } /** * Builder for {@link CredentialEntry}. */ public static final class Builder { private String mType; private Slice mInfo; private PendingIntent mPendingIntent; private Credential mCredential; private boolean mAutoSelectAllowed = false; /** * Builds the instance. * @param type The type of credential underlying this credential entry. * @param info The info to be displayed with this entry on the UI. * * @throws IllegalArgumentException If {@code type} is null or empty. * @throws NullPointerException If {@code info} is null. */ public Builder(@NonNull String type, @NonNull Slice info) { mType = Preconditions.checkStringNotEmpty(type, "type must not be " + "null, or empty"); mInfo = Objects.requireNonNull(info, "info must not be null"); } /** * Sets the pendingIntent to be invoked if the user selects this entry. * * @throws IllegalStateException If {@code credential} is already set. Must either set the * {@code credential}, or the {@code pendingIntent}. */ public @NonNull Builder setPendingIntent(@Nullable PendingIntent pendingIntent) { Preconditions.checkState(pendingIntent != null && mCredential != null, "credential is already set. Cannot set both the pendingIntent " + "and the credential"); mPendingIntent = pendingIntent; return this; } /** * Sets the credential to be used, if the user selects this entry. * * @throws IllegalStateException If {@code pendingIntent} is already set. Must either set * the {@code pendingIntent}, or the {@code credential}. */ public @NonNull Builder setCredential(@Nullable Credential credential) { Preconditions.checkState(credential != null && mPendingIntent != null, "pendingIntent is already set. Cannot set both the " + "pendingIntent and the credential"); mCredential = credential; return this; } /** * Sets whether the entry is allowed to be auto selected by the framework. * The default value is set to false. */ public @NonNull Builder setAutoSelectAllowed(@NonNull boolean autoSelectAllowed) { mAutoSelectAllowed = autoSelectAllowed; return this; } /** * Creates a new {@link CredentialEntry} instance. * * @throws NullPointerException If {@code info} is null. * @throws IllegalArgumentException If {@code type} is null, or empty. * @throws IllegalStateException If neither {@code pendingIntent} nor {@code credential} * is set, or if both are set. */ public @NonNull CredentialEntry build() { Preconditions.checkState(mPendingIntent == null && mCredential == null, "Either pendingIntent or credential must be set"); Preconditions.checkState(mPendingIntent != null && mCredential != null, "Cannot set both the pendingIntent and credential"); return new CredentialEntry(mType, mInfo, mPendingIntent, mCredential, mAutoSelectAllowed); } } }
core/java/android/service/credentials/CredentialProviderService.java 0 → 100644 +91 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.service.credentials; import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; import android.annotation.CallSuper; import android.annotation.NonNull; import android.app.Service; import android.content.Intent; import android.os.CancellationSignal; import android.os.Handler; import android.os.IBinder; import android.os.ICancellationSignal; import android.os.Looper; import android.os.RemoteException; import android.util.Log; import java.util.Objects; /** * Main service to be extended by credential providers, in order to return user credentials * to the framework. * * @hide */ public abstract class CredentialProviderService extends Service { private static final String TAG = "CredProviderService"; private Handler mHandler; public static final String SERVICE_INTERFACE = "android.service.credentials.CredentialProviderService"; @CallSuper @Override public void onCreate() { super.onCreate(); mHandler = new Handler(Looper.getMainLooper(), null, true); } @Override public final @NonNull IBinder onBind(@NonNull Intent intent) { if (SERVICE_INTERFACE.equals(intent.getAction())) { return mInterface.asBinder(); } Log.i(TAG, "Failed to bind with intent: " + intent); return null; } private final ICredentialProviderService mInterface = new ICredentialProviderService.Stub() { @Override public void onGetCredentials(GetCredentialsRequest request, ICancellationSignal transport, IGetCredentialsCallback callback) throws RemoteException { Objects.requireNonNull(request); Objects.requireNonNull(callback); mHandler.sendMessage(obtainMessage( CredentialProviderService::onGetCredentials, CredentialProviderService.this, request, CancellationSignal.fromTransport(transport), new GetCredentialsCallback(callback) )); } }; /** * Called by the android system to retrieve user credentials from the connected provider * service. * @param request The credential request for the provider to handle. * @param cancellationSignal Signal for providers to listen to any cancellation requests from * the android system. * @param callback Object used to relay the response of the credentials request. */ public abstract void onGetCredentials(@NonNull GetCredentialsRequest request, @NonNull CancellationSignal cancellationSignal, @NonNull GetCredentialsCallback callback); }
core/java/android/service/credentials/CredentialsDisplayContent.java 0 → 100644 +188 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.service.credentials; import android.annotation.Nullable; import android.os.Parcel; import android.os.Parcelable; import androidx.annotation.NonNull; import com.android.internal.util.Preconditions; import java.util.ArrayList; import java.util.List; import java.util.Objects; /** * Content to be displayed on the account selector UI, including credential entries, * actions etc. * * @hide */ public final class CredentialsDisplayContent implements Parcelable { /** Header to be displayed on the UI. */ private final @Nullable CharSequence mHeader; /** List of credential entries to be displayed on the UI. */ private final @NonNull List<CredentialEntry> mCredentialEntries; /** List of provider actions to be displayed on the UI. */ private final @NonNull List<Action> mActions; private CredentialsDisplayContent(@Nullable CharSequence header, @NonNull List<CredentialEntry> credentialEntries, @NonNull List<Action> actions) { mHeader = header; mCredentialEntries = credentialEntries; mActions = actions; } private CredentialsDisplayContent(@NonNull Parcel in) { mHeader = in.readCharSequence(); mCredentialEntries = in.createTypedArrayList(CredentialEntry.CREATOR); mActions = in.createTypedArrayList(Action.CREATOR); } public static final @NonNull Creator<CredentialsDisplayContent> CREATOR = new Creator<CredentialsDisplayContent>() { @Override public CredentialsDisplayContent createFromParcel(@NonNull Parcel in) { return new CredentialsDisplayContent(in); } @Override public CredentialsDisplayContent[] newArray(int size) { return new CredentialsDisplayContent[size]; } }; @Override public int describeContents() { return 0; } @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeCharSequence(mHeader); dest.writeTypedList(mCredentialEntries); dest.writeTypedList(mActions); } /** * Returns the header to be displayed on the UI. */ public @Nullable CharSequence getHeader() { return mHeader; } /** * Returns the list of credential entries to be displayed on the UI. */ public @NonNull List<CredentialEntry> getCredentialEntries() { return mCredentialEntries; } /** * Returns the list of actions to be displayed on the UI. */ public @NonNull List<Action> getActions() { return mActions; } /** * Builds an instance of {@link CredentialsDisplayContent}. */ public static final class Builder { private CharSequence mHeader = null; private List<CredentialEntry> mCredentialEntries = new ArrayList<>(); private List<Action> mActions = new ArrayList<>(); /** * Sets the header to be displayed on the UI. */ public @NonNull Builder setHeader(@Nullable CharSequence header) { mHeader = header; return this; } /** * Adds a {@link CredentialEntry} to the list of entries to be displayed on * the UI. * * @throws NullPointerException If the {@code credentialEntry} is null. */ public @NonNull Builder addCredentialEntry(@NonNull CredentialEntry credentialEntry) { mCredentialEntries.add(Objects.requireNonNull(credentialEntry)); return this; } /** * Adds an {@link Action} to the list of actions to be displayed on * the UI. * * @throws NullPointerException If {@code action} is null. */ public @NonNull Builder addAction(@NonNull Action action) { mActions.add(Objects.requireNonNull(action, "action must not be null")); return this; } /** * Sets the list of actions to be displayed on the UI. * * @throws NullPointerException If {@code actions} is null, or any of its elements * is null. */ public @NonNull Builder setActions(@NonNull List<Action> actions) { mActions = Preconditions.checkCollectionElementsNotNull(actions, "actions"); return this; } /** * Sets the list of credential entries to be displayed on the * account selector UI. * * @throws NullPointerException If {@code credentialEntries} is null, or any of its * elements is null. */ public @NonNull Builder setCredentialEntries( @NonNull List<CredentialEntry> credentialEntries) { mCredentialEntries = Preconditions.checkCollectionElementsNotNull( credentialEntries, "credentialEntries"); return this; } /** * Builds a {@link GetCredentialsResponse} instance. * * @throws NullPointerException If {@code credentialEntries} is null. * @throws IllegalStateException if both {@code credentialEntries} and * {@code actions} are empty. */ public @NonNull CredentialsDisplayContent build() { if (mCredentialEntries != null && mCredentialEntries.isEmpty() && mActions != null && mActions.isEmpty()) { throw new IllegalStateException("credentialEntries and actions must not both " + "be empty"); } return new CredentialsDisplayContent(mHeader, mCredentialEntries, mActions); } } }