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

Commit 463a6e04 authored by Becca Hughes's avatar Becca Hughes
Browse files

Send intent for UI when providers are updated

Adds an intent that can be consumed by the UI app
with the list of current providers as an extra. The
intent is limited to the UI app component so this
won't be picked up by other apps.

Test: make & run on device
Bug: 253157366
Change-Id: I01fe9286eeb37f076af0fd0bf0d59659d92f5bab
parent 9ba77666
Loading
Loading
Loading
Loading
+6 −3
Original line number Diff line number Diff line
@@ -24,9 +24,12 @@ package android.credentials.ui;
public class Constants {

    /**
    * The intent extra key for the {@code ResultReceiver} object when launching the UX
    * activities.
     * The intent extra key for the {@code ResultReceiver} object when launching the UX activities.
     */
    public static final String EXTRA_RESULT_RECEIVER =
            "android.credentials.ui.extra.RESULT_RECEIVER";

    /** The intent action for when the enabled Credential Manager providers has been updated. */
    public static final String CREDMAN_ENABLED_PROVIDERS_UPDATED =
            "android.credentials.ui.action.CREDMAN_ENABLED_PROVIDERS_UPDATED";
}
+34 −11
Original line number Diff line number Diff line
@@ -39,14 +39,19 @@ public class IntentFactory {
    public static Intent createCredentialSelectorIntent(
            @NonNull RequestInfo requestInfo,
            @SuppressLint("ConcreteCollection") // Concrete collection needed for marshalling.
            @NonNull ArrayList<ProviderData> enabledProviderDataList,
                    @NonNull
                    ArrayList<ProviderData> enabledProviderDataList,
            @SuppressLint("ConcreteCollection") // Concrete collection needed for marshalling.
            @NonNull ArrayList<DisabledProviderData> disabledProviderDataList,
                    @NonNull
                    ArrayList<DisabledProviderData> disabledProviderDataList,
            @NonNull ResultReceiver resultReceiver) {
        Intent intent = new Intent();
        ComponentName componentName = ComponentName.unflattenFromString(
                Resources.getSystem().getString(
                        com.android.internal.R.string.config_credentialManagerDialogComponent));
        ComponentName componentName =
                ComponentName.unflattenFromString(
                        Resources.getSystem()
                                .getString(
                                        com.android.internal.R.string
                                                .config_credentialManagerDialogComponent));
        intent.setComponent(componentName);

        intent.putParcelableArrayListExtra(
@@ -54,16 +59,34 @@ public class IntentFactory {
        intent.putParcelableArrayListExtra(
                ProviderData.EXTRA_DISABLED_PROVIDER_DATA_LIST, disabledProviderDataList);
        intent.putExtra(RequestInfo.EXTRA_REQUEST_INFO, requestInfo);
        intent.putExtra(Constants.EXTRA_RESULT_RECEIVER,
                toIpcFriendlyResultReceiver(resultReceiver));
        intent.putExtra(
                Constants.EXTRA_RESULT_RECEIVER, toIpcFriendlyResultReceiver(resultReceiver));

        return intent;
    }

    /**
     * Notify the UI that providers have been enabled/disabled.
     *
     * @hide
     */
    @NonNull
    public static Intent createProviderUpdateIntent() {
        Intent intent = new Intent();
        ComponentName componentName =
                ComponentName.unflattenFromString(
                        Resources.getSystem()
                                .getString(
                                        com.android.internal.R.string
                                                .config_credentialManagerDialogComponent));
        intent.setComponent(componentName);
        intent.setAction(Constants.CREDMAN_ENABLED_PROVIDERS_UPDATED);
        return intent;
    }

    /**
    * Convert an instance of a "locally-defined" ResultReceiver to an instance of
    * {@link android.os.ResultReceiver} itself, which the receiving process will be able to
    * unmarshall.
     * Convert an instance of a "locally-defined" ResultReceiver to an instance of {@link
     * android.os.ResultReceiver} itself, which the receiving process will be able to unmarshall.
     */
    private static <T extends ResultReceiver> ResultReceiver toIpcFriendlyResultReceiver(
            T resultReceiver) {
+57 −40
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ import android.credentials.IGetCredentialCallback;
import android.credentials.IListEnabledProvidersCallback;
import android.credentials.ISetEnabledProvidersCallback;
import android.credentials.ListEnabledProvidersResponse;
import android.credentials.ui.IntentFactory;
import android.os.Binder;
import android.os.CancellationSignal;
import android.os.ICancellationSignal;
@@ -112,9 +113,8 @@ public final class CredentialManagerService
                continue;
            }
            try {
                serviceList.add(new CredentialManagerServiceImpl(this, mLock,
                        resolvedUserId,
                        serviceName));
                serviceList.add(
                        new CredentialManagerServiceImpl(this, mLock, resolvedUserId, serviceName));
            } catch (PackageManager.NameNotFoundException | SecurityException e) {
                Log.i(TAG, "Unable to add serviceInfo : " + e.getMessage());
            }
@@ -144,10 +144,12 @@ public final class CredentialManagerService
            RequestSession session, List<String> requestOptions) {
        List<ProviderSession> providerSessions = new ArrayList<>();
        // Invoke all services of a user to initiate a provider session
        runForUser((service) -> {
        runForUser(
                (service) -> {
                    synchronized (mLock) {
                ProviderSession providerSession = service
                        .initiateProviderSessionForRequestLocked(session, requestOptions);
                        ProviderSession providerSession =
                                service.initiateProviderSessionForRequestLocked(
                                        session, requestOptions);
                        if (providerSession != null) {
                            providerSessions.add(providerSession);
                        }
@@ -177,25 +179,33 @@ public final class CredentialManagerService

            // Initiate all provider sessions
            List<ProviderSession> providerSessions =
                    initiateProviderSessions(session, request.getGetCredentialOptions()
                            .stream().map(GetCredentialOption::getType)
                    initiateProviderSessions(
                            session,
                            request.getGetCredentialOptions().stream()
                                    .map(GetCredentialOption::getType)
                                    .collect(Collectors.toList()));

            if (providerSessions.isEmpty()) {
                try {
                    // TODO("Replace with properly defined error type")
                    callback.onError("unknown_type",
                            "No providers available to fulfill request.");
                    callback.onError("unknown_type", "No providers available to fulfill request.");
                } catch (RemoteException e) {
                    Log.i(TAG, "Issue invoking onError on IGetCredentialCallback "
                            + "callback: " + e.getMessage());
                    Log.i(
                            TAG,
                            "Issue invoking onError on IGetCredentialCallback "
                                    + "callback: "
                                    + e.getMessage());
                }
            }

            // Iterate over all provider sessions and invoke the request
            providerSessions.forEach(providerGetSession -> {
                providerGetSession.getRemoteCredentialService().onBeginGetCredential(
                        (BeginGetCredentialRequest) providerGetSession.getProviderRequest(),
            providerSessions.forEach(
                    providerGetSession -> {
                        providerGetSession
                                .getRemoteCredentialService()
                                .onBeginGetCredential(
                                        (BeginGetCredentialRequest)
                                                providerGetSession.getProviderRequest(),
                                        /* callback= */ providerGetSession);
                    });
            return cancelTransport;
@@ -226,11 +236,13 @@ public final class CredentialManagerService
            if (providerSessions.isEmpty()) {
                try {
                    // TODO("Replace with properly defined error type")
                    callback.onError("unknown_type",
                            "No providers available to fulfill request.");
                    callback.onError("unknown_type", "No providers available to fulfill request.");
                } catch (RemoteException e) {
                    Log.i(TAG, "Issue invoking onError on ICreateCredentialCallback "
                            + "callback: " + e.getMessage());
                    Log.i(
                            TAG,
                            "Issue invoking onError on ICreateCredentialCallback "
                                    + "callback: "
                                    + e.getMessage());
                }
            }

@@ -257,8 +269,7 @@ public final class CredentialManagerService
            List<String> enabledProviders = new ArrayList<>();
            runForUser(
                    (service) -> {
                        enabledProviders.add(
                                service.getComponentName().flattenToString());
                        enabledProviders.add(service.getComponentName().flattenToString());
                    });

            // Call the callback.
@@ -300,7 +311,7 @@ public final class CredentialManagerService
                            "Failed to store setting containing enabled providers");
                } catch (RemoteException e) {
                    Log.i(TAG, "Issue with invoking error response: " + e.getMessage());
                    // TODO: Propagate failure
                    return;
                }
            }

@@ -311,11 +322,16 @@ public final class CredentialManagerService
                Log.i(TAG, "Issue with invoking response: " + e.getMessage());
                // TODO: Propagate failure
            }

            // Send an intent to the UI that we have new enabled providers.
            getContext().sendBroadcast(IntentFactory.createProviderUpdateIntent());
        }

        @Override
        public ICancellationSignal clearCredentialState(ClearCredentialStateRequest request,
                IClearCredentialStateCallback callback, String callingPackage) {
        public ICancellationSignal clearCredentialState(
                ClearCredentialStateRequest request,
                IClearCredentialStateCallback callback,
                String callingPackage) {
            Log.i(TAG, "starting clearCredentialState with callingPackage: " + callingPackage);
            // TODO : Implement cancellation
            ICancellationSignal cancelTransport = CancellationSignal.createTransport();
@@ -331,17 +347,18 @@ public final class CredentialManagerService

            // Initiate all provider sessions
            // TODO: Determine if provider needs to have clear capability in their manifest
            List<ProviderSession> providerSessions =
                    initiateProviderSessions(session, List.of());
            List<ProviderSession> providerSessions = initiateProviderSessions(session, List.of());

            if (providerSessions.isEmpty()) {
                try {
                    // TODO("Replace with properly defined error type")
                    callback.onError("unknown_type",
                            "No providers available to fulfill request.");
                    callback.onError("unknown_type", "No providers available to fulfill request.");
                } catch (RemoteException e) {
                    Log.i(TAG, "Issue invoking onError on IClearCredentialStateCallback "
                            + "callback: " + e.getMessage());
                    Log.i(
                            TAG,
                            "Issue invoking onError on IClearCredentialStateCallback "
                                    + "callback: "
                                    + e.getMessage());
                }
            }