Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 91f05736 authored by Becca Hughes's avatar Becca Hughes Committed by Android (Google) Code Review
Browse files

Merge "Add SetEnabledProviders API method for Credential Manager"

parents ee08e5f8 5fea7f67
Loading
Loading
Loading
Loading
+103 −35
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import static java.util.Objects.requireNonNull;
import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemService;
import android.app.Activity;
import android.app.PendingIntent;
@@ -32,6 +33,7 @@ import android.os.OutcomeReceiver;
import android.os.RemoteException;
import android.util.Log;

import java.util.List;
import java.util.concurrent.Executor;

/**
@@ -40,9 +42,9 @@ import java.util.concurrent.Executor;
 * <p>Note that an application should call the Jetpack CredentialManager apis instead of directly
 * calling these framework apis.
 *
 * <p>The CredentialManager apis launch framework UI flows for a user to
 * register a new credential or to consent to a saved credential from supported credential
 * providers, which can then be used to authenticate to the app.
 * <p>The CredentialManager apis launch framework UI flows for a user to register a new credential
 * or to consent to a saved credential from supported credential providers, which can then be used
 * to authenticate to the app.
 */
@SystemService(Context.CREDENTIAL_SERVICE)
public final class CredentialManager {
@@ -76,8 +78,7 @@ public final class CredentialManager {
            @NonNull Activity activity,
            @Nullable CancellationSignal cancellationSignal,
            @CallbackExecutor @NonNull Executor executor,
            @NonNull OutcomeReceiver<
                    GetCredentialResponse, GetCredentialException> callback) {
            @NonNull OutcomeReceiver<GetCredentialResponse, GetCredentialException> callback) {
        requireNonNull(request, "request must not be null");
        requireNonNull(activity, "activity must not be null");
        requireNonNull(executor, "executor must not be null");
@@ -90,7 +91,8 @@ public final class CredentialManager {

        ICancellationSignal cancelRemote = null;
        try {
            cancelRemote = mService.executeGetCredential(
            cancelRemote =
                    mService.executeGetCredential(
                            request,
                            new GetCredentialTransport(activity, executor, callback),
                            mContext.getOpPackageName());
@@ -106,8 +108,8 @@ public final class CredentialManager {
    /**
     * Launches the necessary flows to register an app credential for the user.
     *
     * <p>The execution can potentially launch UI flows to collect user consent to creating
     * or storing the new credential, etc.
     * <p>The execution can potentially launch UI flows to collect user consent to creating or
     * storing the new credential, etc.
     *
     * @param request the request specifying type(s) of credentials to get from the user
     * @param activity the activity used to launch any UI needed
@@ -120,8 +122,8 @@ public final class CredentialManager {
            @NonNull Activity activity,
            @Nullable CancellationSignal cancellationSignal,
            @CallbackExecutor @NonNull Executor executor,
            @NonNull OutcomeReceiver<
                    CreateCredentialResponse, CreateCredentialException> callback) {
            @NonNull
                    OutcomeReceiver<CreateCredentialResponse, CreateCredentialException> callback) {
        requireNonNull(request, "request must not be null");
        requireNonNull(activity, "activity must not be null");
        requireNonNull(executor, "executor must not be null");
@@ -134,7 +136,9 @@ public final class CredentialManager {

        ICancellationSignal cancelRemote = null;
        try {
            cancelRemote = mService.executeCreateCredential(request,
            cancelRemote =
                    mService.executeCreateCredential(
                            request,
                            new CreateCredentialTransport(activity, executor, callback),
                            mContext.getOpPackageName());
        } catch (RemoteException e) {
@@ -149,10 +153,10 @@ public final class CredentialManager {
    /**
     * Clears the current user credential state from all credential providers.
     *
     * You should invoked this api after your user signs out of your app to notify all credential
     * <p>You should invoked this api after your user signs out of your app to notify all credential
     * providers that any stored credential session for the given app should be cleared.
     *
     * A credential provider may have stored an active credential session and use it to limit
     * <p>A credential provider may have stored an active credential session and use it to limit
     * sign-in options for future get-credential calls. For example, it may prioritize the active
     * credential over any other available credential. When your user explicitly signs out of your
     * app and in order to get the holistic sign-in options the next time, you should call this API
@@ -178,7 +182,9 @@ public final class CredentialManager {

        ICancellationSignal cancelRemote = null;
        try {
            cancelRemote = mService.clearCredentialState(request,
            cancelRemote =
                    mService.clearCredentialState(
                            request,
                            new ClearCredentialStateTransport(executor, callback),
                            mContext.getOpPackageName());
        } catch (RemoteException e) {
@@ -190,15 +196,44 @@ public final class CredentialManager {
        }
    }

    /**
     * Sets a list of all user configurable credential providers registered on the system. This API
     * is intended for settings apps.
     *
     * @param providers the list of enabled providers
     * @param userId the user ID to configure credential manager for
     * @param executor the callback will take place on this {@link Executor}
     * @param callback the callback invoked when the request succeeds or fails
     * @hide
     */
    @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
    public void setEnabledProviders(
            @NonNull List<String> providers,
            int userId,
            @CallbackExecutor @NonNull Executor executor,
            @NonNull OutcomeReceiver<Void, SetEnabledProvidersException> callback) {
        requireNonNull(executor, "executor must not be null");
        requireNonNull(callback, "callback must not be null");
        requireNonNull(providers, "providers must not be null");

        try {
            mService.setEnabledProviders(
                    providers, userId, new SetEnabledProvidersTransport(executor, callback));
        } catch (RemoteException e) {
            e.rethrowFromSystemServer();
        }
    }

    private static class GetCredentialTransport extends IGetCredentialCallback.Stub {
        // TODO: listen for cancellation to release callback.

        private final Activity mActivity;
        private final Executor mExecutor;
        private final OutcomeReceiver<
                GetCredentialResponse, GetCredentialException> mCallback;
        private final OutcomeReceiver<GetCredentialResponse, GetCredentialException> mCallback;

        private GetCredentialTransport(Activity activity, Executor executor,
        private GetCredentialTransport(
                Activity activity,
                Executor executor,
                OutcomeReceiver<GetCredentialResponse, GetCredentialException> callback) {
            mActivity = activity;
            mExecutor = executor;
@@ -210,8 +245,10 @@ public final class CredentialManager {
            try {
                mActivity.startIntentSender(pendingIntent.getIntentSender(), null, 0, 0, 0);
            } catch (IntentSender.SendIntentException e) {
                Log.e(TAG, "startIntentSender() failed for intent:"
                        + pendingIntent.getIntentSender(), e);
                Log.e(
                        TAG,
                        "startIntentSender() failed for intent:" + pendingIntent.getIntentSender(),
                        e);
                // TODO: propagate the error.
            }
        }
@@ -233,10 +270,12 @@ public final class CredentialManager {

        private final Activity mActivity;
        private final Executor mExecutor;
        private final OutcomeReceiver<
                CreateCredentialResponse, CreateCredentialException> mCallback;
        private final OutcomeReceiver<CreateCredentialResponse, CreateCredentialException>
                mCallback;

        private CreateCredentialTransport(Activity activity, Executor executor,
        private CreateCredentialTransport(
                Activity activity,
                Executor executor,
                OutcomeReceiver<CreateCredentialResponse, CreateCredentialException> callback) {
            mActivity = activity;
            mExecutor = executor;
@@ -248,8 +287,10 @@ public final class CredentialManager {
            try {
                mActivity.startIntentSender(pendingIntent.getIntentSender(), null, 0, 0, 0);
            } catch (IntentSender.SendIntentException e) {
                Log.e(TAG, "startIntentSender() failed for intent:"
                        + pendingIntent.getIntentSender(), e);
                Log.e(
                        TAG,
                        "startIntentSender() failed for intent:" + pendingIntent.getIntentSender(),
                        e);
                // TODO: propagate the error.
            }
        }
@@ -266,15 +307,14 @@ public final class CredentialManager {
        }
    }

    private static class ClearCredentialStateTransport
            extends IClearCredentialStateCallback.Stub {
    private static class ClearCredentialStateTransport extends IClearCredentialStateCallback.Stub {
        // TODO: listen for cancellation to release callback.

        private final Executor mExecutor;
        private final OutcomeReceiver<Void, ClearCredentialStateException> mCallback;

        private ClearCredentialStateTransport(Executor executor,
                OutcomeReceiver<Void, ClearCredentialStateException> callback) {
        private ClearCredentialStateTransport(
                Executor executor, OutcomeReceiver<Void, ClearCredentialStateException> callback) {
            mExecutor = executor;
            mCallback = callback;
        }
@@ -290,4 +330,32 @@ public final class CredentialManager {
                    () -> mCallback.onError(new ClearCredentialStateException(errorType, message)));
        }
    }

    private static class SetEnabledProvidersTransport extends ISetEnabledProvidersCallback.Stub {
        // TODO: listen for cancellation to release callback.

        private final Executor mExecutor;
        private final OutcomeReceiver<Void, SetEnabledProvidersException> mCallback;

        private SetEnabledProvidersTransport(
                Executor executor, OutcomeReceiver<Void, SetEnabledProvidersException> callback) {
            mExecutor = executor;
            mCallback = callback;
        }

        public void onResponse(Void result) {
            mExecutor.execute(() -> mCallback.onResult(result));
        }

        @Override
        public void onResponse() {
            mExecutor.execute(() -> mCallback.onResult(null));
        }

        @Override
        public void onError(String errorType, String message) {
            mExecutor.execute(
                    () -> mCallback.onError(new SetEnabledProvidersException(errorType, message)));
        }
    }
}
+5 −0
Original line number Diff line number Diff line
@@ -16,12 +16,15 @@

package android.credentials;

import java.util.List;

import android.credentials.ClearCredentialStateRequest;
import android.credentials.CreateCredentialRequest;
import android.credentials.GetCredentialRequest;
import android.credentials.IClearCredentialStateCallback;
import android.credentials.ICreateCredentialCallback;
import android.credentials.IGetCredentialCallback;
import android.credentials.ISetEnabledProvidersCallback;
import android.os.ICancellationSignal;

/**
@@ -36,4 +39,6 @@ interface ICredentialManager {
    @nullable ICancellationSignal executeCreateCredential(in CreateCredentialRequest request, in ICreateCredentialCallback callback, String callingPackage);

    @nullable ICancellationSignal clearCredentialState(in ClearCredentialStateRequest request, in IClearCredentialStateCallback callback, String callingPackage);

    void setEnabledProviders(in List<String> providers, in int userId, in ISetEnabledProvidersCallback callback);
}
+27 −0
Original line number Diff line number Diff line
/*
 * 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;

/**
 * Listener for an setEnabledProviders request.
 *
 * @hide
 */
interface ISetEnabledProvidersCallback {
    oneway void onResponse();
    oneway void onError(String errorType, String message);
}
 No newline at end of file
+74 −0
Original line number Diff line number Diff line
/*
 * 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;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.CancellationSignal;
import android.os.OutcomeReceiver;

import com.android.internal.util.Preconditions;

/**
 * Represents an error encountered during the {@link
 * CredentialManager#setEnabledProviders(CancellationSignal Executor, OutcomeReceiver)} operation.
 *
 * @hide
 */
public class SetEnabledProvidersException extends Exception {

    @NonNull public final String errorType;

    /**
     * Constructs a {@link SetEnabledProvidersException}.
     *
     * @throws IllegalArgumentException If errorType is empty.
     */
    public SetEnabledProvidersException(@NonNull String errorType, @Nullable String message) {
        this(errorType, message, null);
    }

    /**
     * Constructs a {@link SetEnabledProvidersException}.
     *
     * @throws IllegalArgumentException If errorType is empty.
     */
    public SetEnabledProvidersException(
            @NonNull String errorType, @Nullable String message, @Nullable Throwable cause) {
        super(message, cause);
        this.errorType =
                Preconditions.checkStringNotEmpty(errorType, "errorType must not be empty");
    }

    /**
     * Constructs a {@link SetEnabledProvidersException}.
     *
     * @throws IllegalArgumentException If errorType is empty.
     */
    public SetEnabledProvidersException(@NonNull String errorType, @Nullable Throwable cause) {
        this(errorType, null, cause);
    }

    /**
     * Constructs a {@link SetEnabledProvidersException}.
     *
     * @throws IllegalArgumentException If errorType is empty.
     */
    public SetEnabledProvidersException(@NonNull String errorType) {
        this(errorType, null, null);
    }
}
+19 −0
Original line number Diff line number Diff line
/*
 * 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;

parcelable SetEnabledProvidersRequest;
 No newline at end of file
Loading