Merge "Add provider facing GET APIs for Credential Manager."
This commit is contained in:
98
core/java/android/service/credentials/Action.java
Normal file
98
core/java/android/service/credentials/Action.java
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
100
core/java/android/service/credentials/Credential.java
Normal file
100
core/java/android/service/credentials/Credential.java
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
216
core/java/android/service/credentials/CredentialEntry.java
Normal file
216
core/java/android/service/credentials/CredentialEntry.java
Normal file
@@ -0,0 +1,216 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* 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.NonNull;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import com.android.internal.util.Preconditions;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
/**
|
||||
* A type specific credential request, containing the associated data to be used for
|
||||
* retrieving credentials.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public final class GetCredentialOption implements Parcelable {
|
||||
/** The type of credential requested. */
|
||||
private final @NonNull String mType;
|
||||
|
||||
/** The data associated with the request. */
|
||||
private final @NonNull Bundle mData;
|
||||
|
||||
/**
|
||||
* Constructs a new instance of {@link GetCredentialOption}
|
||||
*
|
||||
* @throws IllegalArgumentException If {@code type} string is null or empty.
|
||||
* @throws NullPointerException If {@code data} is null.
|
||||
*/
|
||||
public GetCredentialOption(@NonNull String type, @NonNull Bundle data) {
|
||||
Preconditions.checkStringNotEmpty(type, "type must not be null, or empty");
|
||||
requireNonNull(data, "data must not be null");
|
||||
mType = type;
|
||||
mData = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the data associated with this credential request option.
|
||||
*/
|
||||
public @NonNull Bundle getData() {
|
||||
return mData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type associated with this credential request option.
|
||||
*/
|
||||
public @NonNull String getType() {
|
||||
return mType;
|
||||
}
|
||||
|
||||
private GetCredentialOption(@NonNull Parcel in) {
|
||||
mType = in.readString16NoHelper();
|
||||
mData = in.readBundle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeString16NoHelper(mType);
|
||||
dest.writeBundle(mData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static final @NonNull Creator<GetCredentialOption> CREATOR =
|
||||
new Creator<GetCredentialOption>() {
|
||||
@Override
|
||||
public GetCredentialOption createFromParcel(@NonNull Parcel in) {
|
||||
return new GetCredentialOption(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GetCredentialOption[] newArray(int size) {
|
||||
return new GetCredentialOption[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* Callback to be invoked as a response to {@link GetCredentialsRequest}.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public final class GetCredentialsCallback {
|
||||
|
||||
private static final String TAG = "GetCredentialsCallback";
|
||||
|
||||
private final IGetCredentialsCallback mCallback;
|
||||
|
||||
/** @hide */
|
||||
public GetCredentialsCallback(@NonNull IGetCredentialsCallback callback) {
|
||||
mCallback = callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked on a successful response for {@link GetCredentialsRequest}
|
||||
* @param response The response from the credential provider.
|
||||
*/
|
||||
public void onSuccess(@Nullable GetCredentialsResponse response) {
|
||||
try {
|
||||
mCallback.onSuccess(response);
|
||||
} catch (RemoteException e) {
|
||||
e.rethrowAsRuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked on a failure response for {@link GetCredentialsRequest}
|
||||
* @param errorCode The code defining the kind of error.
|
||||
* @param message The message corresponding to the failure.
|
||||
*/
|
||||
public void onFailure(int errorCode, @Nullable CharSequence message) {
|
||||
Log.w(TAG, "onFailure: " + message);
|
||||
try {
|
||||
mCallback.onFailure(errorCode, message);
|
||||
} catch (RemoteException e) {
|
||||
e.rethrowAsRuntimeException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
package android.service.credentials;
|
||||
|
||||
parcelable GetCredentialsRequest;
|
||||
156
core/java/android/service/credentials/GetCredentialsRequest.java
Normal file
156
core/java/android/service/credentials/GetCredentialsRequest.java
Normal file
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* 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.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;
|
||||
|
||||
/**
|
||||
* Request for getting user's credentials from a given credential provider.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public final class GetCredentialsRequest implements Parcelable {
|
||||
/** Calling package of the app requesting for credentials. */
|
||||
private final @NonNull String mCallingPackage;
|
||||
|
||||
/**
|
||||
* List of credential options. Each {@link GetCredentialOption} object holds parameters to
|
||||
* be used for retrieving specific type of credentials.
|
||||
*/
|
||||
private final @NonNull List<GetCredentialOption> mGetCredentialOptions;
|
||||
|
||||
private GetCredentialsRequest(@NonNull String callingPackage,
|
||||
@NonNull List<GetCredentialOption> getCredentialOptions) {
|
||||
this.mCallingPackage = callingPackage;
|
||||
this.mGetCredentialOptions = getCredentialOptions;
|
||||
}
|
||||
|
||||
private GetCredentialsRequest(@NonNull Parcel in) {
|
||||
mCallingPackage = in.readString16NoHelper();
|
||||
mGetCredentialOptions = in.createTypedArrayList(GetCredentialOption.CREATOR);
|
||||
}
|
||||
|
||||
public static final @NonNull Creator<GetCredentialsRequest> CREATOR =
|
||||
new Creator<GetCredentialsRequest>() {
|
||||
@Override
|
||||
public GetCredentialsRequest createFromParcel(Parcel in) {
|
||||
return new GetCredentialsRequest(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GetCredentialsRequest[] newArray(int size) {
|
||||
return new GetCredentialsRequest[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeString16NoHelper(mCallingPackage);
|
||||
dest.writeTypedList(mGetCredentialOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the calling package of the app requesting credentials.
|
||||
*/
|
||||
public @NonNull String getCallingPackage() {
|
||||
return mCallingPackage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of type specific credential options to return credentials for.
|
||||
*/
|
||||
public @NonNull List<GetCredentialOption> getGetCredentialOptions() {
|
||||
return mGetCredentialOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder for {@link GetCredentialsRequest}.
|
||||
*/
|
||||
public static final class Builder {
|
||||
private String mCallingPackage;
|
||||
private List<GetCredentialOption> mGetCredentialOptions = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Creates a new builder.
|
||||
* @param callingPackage The calling package of the app requesting credentials.
|
||||
*
|
||||
* @throws IllegalArgumentException If {@code callingPackag}e is null or empty.
|
||||
*/
|
||||
public Builder(@NonNull String callingPackage) {
|
||||
mCallingPackage = Preconditions.checkStringNotEmpty(callingPackage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the list of credential options.
|
||||
*
|
||||
* @throws NullPointerException If {@code getCredentialOptions} itself or any of its
|
||||
* elements is null.
|
||||
* @throws IllegalArgumentException If {@code getCredentialOptions} is empty.
|
||||
*/
|
||||
public @NonNull Builder setGetCredentialOptions(
|
||||
@NonNull List<GetCredentialOption> getCredentialOptions) {
|
||||
Preconditions.checkCollectionNotEmpty(mGetCredentialOptions,
|
||||
"getCredentialOptions");
|
||||
Preconditions.checkCollectionElementsNotNull(mGetCredentialOptions,
|
||||
"getCredentialOptions");
|
||||
mGetCredentialOptions = getCredentialOptions;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a single {@link GetCredentialOption} object to the list of credential options.
|
||||
*
|
||||
* @throws NullPointerException If {@code getCredentialOption} is null.
|
||||
*/
|
||||
public @NonNull Builder addGetCredentialOption(
|
||||
@NonNull GetCredentialOption getCredentialOption) {
|
||||
Objects.requireNonNull(getCredentialOption,
|
||||
"getCredentialOption must not be null");
|
||||
mGetCredentialOptions.add(getCredentialOption);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a new {@link GetCredentialsRequest} instance.
|
||||
*
|
||||
* @throws NullPointerException If {@code getCredentialOptions} is null.
|
||||
* @throws IllegalArgumentException If {@code getCredentialOptions} is empty, or if
|
||||
* {@code callingPackage} is null or empty.
|
||||
*/
|
||||
public @NonNull GetCredentialsRequest build() {
|
||||
Preconditions.checkStringNotEmpty(mCallingPackage,
|
||||
"Must set the calling package");
|
||||
Preconditions.checkCollectionNotEmpty(mGetCredentialOptions,
|
||||
"getCredentialOptions");
|
||||
return new GetCredentialsRequest(mCallingPackage, mGetCredentialOptions);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
package android.service.credentials;
|
||||
|
||||
parcelable GetCredentialsResponse;
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* 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 java.util.Objects;
|
||||
|
||||
/**
|
||||
* Response from a credential provider, containing credential entries and other associated
|
||||
* data to be shown on the account selector UI.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public final class GetCredentialsResponse implements Parcelable {
|
||||
/** Content to be used for the UI. */
|
||||
private final @Nullable CredentialsDisplayContent mCredentialsDisplayContent;
|
||||
|
||||
/**
|
||||
* Authentication action that must be launched and completed before showing any content
|
||||
* from the provider.
|
||||
*/
|
||||
private final @Nullable Action mAuthenticationAction;
|
||||
|
||||
/**
|
||||
* Creates a {@link GetCredentialsRequest} instance with an authentication action set.
|
||||
* Providers must use this method when no content can be shown before authentication.
|
||||
*
|
||||
* @throws NullPointerException If {@code authenticationAction} is null.
|
||||
*/
|
||||
public static @NonNull GetCredentialsResponse createWithAuthentication(
|
||||
@NonNull Action authenticationAction) {
|
||||
Objects.requireNonNull(authenticationAction,
|
||||
"authenticationAction must not be null");
|
||||
return new GetCredentialsResponse(null, authenticationAction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link GetCredentialsRequest} instance with display content to be shown on the UI.
|
||||
* Providers must use this method when there is content to be shown without top level
|
||||
* authentication required.
|
||||
*
|
||||
* @throws NullPointerException If {@code credentialsDisplayContent} is null.
|
||||
*/
|
||||
public static @NonNull GetCredentialsResponse createWithDisplayContent(
|
||||
@NonNull CredentialsDisplayContent credentialsDisplayContent) {
|
||||
Objects.requireNonNull(credentialsDisplayContent,
|
||||
"credentialsDisplayContent must not be null");
|
||||
return new GetCredentialsResponse(credentialsDisplayContent, null);
|
||||
}
|
||||
|
||||
private GetCredentialsResponse(@Nullable CredentialsDisplayContent credentialsDisplayContent,
|
||||
@Nullable Action authenticationAction) {
|
||||
mCredentialsDisplayContent = credentialsDisplayContent;
|
||||
mAuthenticationAction = authenticationAction;
|
||||
}
|
||||
|
||||
private GetCredentialsResponse(@NonNull Parcel in) {
|
||||
mCredentialsDisplayContent = in.readParcelable(CredentialsDisplayContent.class
|
||||
.getClassLoader(), CredentialsDisplayContent.class);
|
||||
mAuthenticationAction = in.readParcelable(Action.class.getClassLoader(), Action.class);
|
||||
}
|
||||
|
||||
public static final @NonNull Creator<GetCredentialsResponse> CREATOR =
|
||||
new Creator<GetCredentialsResponse>() {
|
||||
@Override
|
||||
public GetCredentialsResponse createFromParcel(Parcel in) {
|
||||
return new GetCredentialsResponse(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GetCredentialsResponse[] newArray(int size) {
|
||||
return new GetCredentialsResponse[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeParcelable(mCredentialsDisplayContent, flags);
|
||||
dest.writeParcelable(mAuthenticationAction, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the response contains a top level authentication action.
|
||||
*/
|
||||
public @NonNull boolean isAuthenticationActionSet() {
|
||||
return mAuthenticationAction != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the authentication action to be invoked before any other content
|
||||
* can be shown to the user.
|
||||
*/
|
||||
public @NonNull Action getAuthenticationAction() {
|
||||
return mAuthenticationAction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the credentialDisplayContent that does not require authentication, and
|
||||
* can be shown to the user on the account selector UI.
|
||||
*/
|
||||
public @NonNull CredentialsDisplayContent getCredentialsDisplayContent() {
|
||||
return mCredentialsDisplayContent;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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.ICancellationSignal;
|
||||
import android.service.credentials.GetCredentialsRequest;
|
||||
import android.service.credentials.IGetCredentialsCallback;
|
||||
|
||||
/**
|
||||
* Interface from the system to a credential provider service.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
oneway interface ICredentialProviderService {
|
||||
void onGetCredentials(in GetCredentialsRequest request, in ICancellationSignal transport, in IGetCredentialsCallback callback);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package android.service.credentials;
|
||||
|
||||
import android.service.credentials.GetCredentialsResponse;
|
||||
|
||||
/**
|
||||
* Interface from the system to a credential provider service.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
oneway interface IGetCredentialsCallback {
|
||||
void onSuccess(in GetCredentialsResponse response);
|
||||
void onFailure(int errorCode, in CharSequence message);
|
||||
}
|
||||
Reference in New Issue
Block a user