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

Commit efa29460 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Allow retainning entries across selections"

parents 6dda82f9 60aeccf6
Loading
Loading
Loading
Loading
+117 −72
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.server.credentials;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.credentials.CreateCredentialException;
@@ -56,14 +57,11 @@ public final class ProviderCreateSession extends ProviderSession<
    // Key to be used as an entry key for a remote entry
    private static final String REMOTE_ENTRY_KEY = "remote_entry_key";

    @NonNull
    private final Map<String, CreateEntry> mUiSaveEntries = new HashMap<>();
    /** The complete request to be used in the second round. */
    private final CreateCredentialRequest mCompleteRequest;

    private CreateCredentialException mProviderException;

    @Nullable protected Pair<String, CreateEntry> mUiRemoteEntry;
    private final ProviderResponseDataHandler mProviderResponseDataHandler;

    /** Creates a new provider session to be used by the request session. */
    @Nullable public static ProviderCreateSession createNewSession(
@@ -88,7 +86,8 @@ public final class ProviderCreateSession extends ProviderSession<
                            createRequestSession.mClientAppInfo,
                            createRequestSession
                                    .mClientRequest.alwaysSendAppInfoToProvider()),
                    providerCreateRequest
                    providerCreateRequest,
                    createRequestSession.mHybridService
            );
        }
        Log.i(TAG, "Unable to create provider session");
@@ -131,23 +130,20 @@ public final class ProviderCreateSession extends ProviderSession<
            @UserIdInt int userId,
            @NonNull RemoteCredentialService remoteCredentialService,
            @NonNull BeginCreateCredentialRequest beginCreateRequest,
            @NonNull CreateCredentialRequest completeCreateRequest) {
            @NonNull CreateCredentialRequest completeCreateRequest,
            String hybridService) {
        super(context, info, beginCreateRequest, callbacks, userId,
                remoteCredentialService);
        mCompleteRequest = completeCreateRequest;
        setStatus(Status.PENDING);
    }

    /** Returns the save entry maintained in state by this provider session. */
    public CreateEntry getUiSaveEntry(String entryId) {
        return mUiSaveEntries.get(entryId);
        mProviderResponseDataHandler = new ProviderResponseDataHandler(hybridService);
    }

    @Override
    public void onProviderResponseSuccess(
            @Nullable BeginCreateCredentialResponse response) {
        Log.i(TAG, "in onProviderResponseSuccess");
        onUpdateResponse(response);
        onSetInitialRemoteResponse(response);
    }

    /** Called when the provider response resulted in a failure. */
@@ -171,21 +167,18 @@ public final class ProviderCreateSession extends ProviderSession<
        }
    }

    private void onUpdateResponse(BeginCreateCredentialResponse response) {
        Log.i(TAG, "updateResponse with save entries");
    private void onSetInitialRemoteResponse(BeginCreateCredentialResponse response) {
        Log.i(TAG, "onSetInitialRemoteResponse with save entries");
        mProviderResponse = response;
        if (isEmptyResponse(response)) {
        mProviderResponseDataHandler.addResponseContent(response.getCreateEntries(),
                response.getRemoteCreateEntry());
        if (mProviderResponseDataHandler.isEmptyResponse(response)) {
            updateStatusAndInvokeCallback(Status.EMPTY_RESPONSE);
        } else {
            updateStatusAndInvokeCallback(Status.SAVE_ENTRIES_RECEIVED);
        }
    }

    private boolean isEmptyResponse(BeginCreateCredentialResponse response) {
        return (response.getCreateEntries() == null || response.getCreateEntries().isEmpty())
                && response.getRemoteCreateEntry() == null;
    }

    @Override
    @Nullable protected CreateCredentialProviderData prepareUiData()
            throws IllegalArgumentException {
@@ -194,53 +187,37 @@ public final class ProviderCreateSession extends ProviderSession<
            Log.i(TAG, "In prepareUiData not in uiInvokingStatus");
            return null;
        }
        final BeginCreateCredentialResponse response = getProviderResponse();
        if (response == null) {
            Log.i(TAG, "In prepareUiData response null");
            throw new IllegalStateException("Response must be in completion mode");
        }
        if (response.getCreateEntries() != null) {

        if (mProviderResponse != null && !mProviderResponseDataHandler.isEmptyResponse()) {
            Log.i(TAG, "In prepareUiData save entries not null");
            return prepareUiProviderData(
                    prepareUiSaveEntries(response.getCreateEntries()),
                    prepareUiRemoteEntry(response.getRemoteCreateEntry()));
            return mProviderResponseDataHandler.toCreateCredentialProviderData();
        }
        return null;
    }

    private Entry prepareUiRemoteEntry(CreateEntry remoteCreateEntry) {
        if (remoteCreateEntry == null) {
            return null;
        }
        String entryId = generateUniqueId();
        Entry remoteEntry = new Entry(REMOTE_ENTRY_KEY, entryId, remoteCreateEntry.getSlice(),
                setUpFillInIntent());
        mUiRemoteEntry = new Pair<>(entryId, remoteCreateEntry);
        return remoteEntry;
    }

    @Override
    public void onUiEntrySelected(String entryType, String entryKey,
            ProviderPendingIntentResponse providerPendingIntentResponse) {
        switch (entryType) {
            case SAVE_ENTRY_KEY:
                if (mUiSaveEntries.containsKey(entryKey)) {
                    onSaveEntrySelected(providerPendingIntentResponse);
                } else {
                if (mProviderResponseDataHandler.getCreateEntry(entryKey) == null) {
                    Log.i(TAG, "Unexpected save entry key");
                    invokeCallbackOnInternalInvalidState();
                    return;
                }
                onCreateEntrySelected(providerPendingIntentResponse);
                break;
            case REMOTE_ENTRY_KEY:
                if (mUiRemoteEntry.first.equals(entryKey)) {
                    onRemoteEntrySelected(providerPendingIntentResponse);
                } else {
                if (mProviderResponseDataHandler.getRemoteEntry(entryKey) == null) {
                    Log.i(TAG, "Unexpected remote entry key");
                    invokeCallbackOnInternalInvalidState();
                    return;
                }
                onRemoteEntrySelected(providerPendingIntentResponse);
                break;
            default:
                Log.i(TAG, "Unsupported entry type selected");
                invokeCallbackOnInternalInvalidState();
        }
    }

@@ -252,21 +229,6 @@ public final class ProviderCreateSession extends ProviderSession<
        }
    }

    private List<Entry> prepareUiSaveEntries(@NonNull List<CreateEntry> saveEntries) {
        Log.i(TAG, "in populateUiSaveEntries");
        List<Entry> uiSaveEntries = new ArrayList<>();

        // Populate the save entries
        for (CreateEntry createEntry : saveEntries) {
            String entryId = generateUniqueId();
            mUiSaveEntries.put(entryId, createEntry);
            Log.i(TAG, "in prepareUiProviderData creating ui entry with id " + entryId);
            uiSaveEntries.add(new Entry(SAVE_ENTRY_KEY, entryId, createEntry.getSlice(),
                    setUpFillInIntent()));
        }
        return uiSaveEntries;
    }

    private Intent setUpFillInIntent() {
        Intent intent = new Intent();
        intent.putExtra(CredentialProviderService.EXTRA_CREATE_CREDENTIAL_REQUEST,
@@ -274,16 +236,7 @@ public final class ProviderCreateSession extends ProviderSession<
        return intent;
    }

    private CreateCredentialProviderData prepareUiProviderData(List<Entry> saveEntries,
            Entry remoteEntry) {
        return new CreateCredentialProviderData.Builder(
                mComponentName.flattenToString())
                .setSaveEntries(saveEntries)
                .setRemoteEntry(remoteEntry)
                .build();
    }

    private void onSaveEntrySelected(ProviderPendingIntentResponse pendingIntentResponse) {
    private void onCreateEntrySelected(ProviderPendingIntentResponse pendingIntentResponse) {
        CreateCredentialException exception = maybeGetPendingIntentException(
                pendingIntentResponse);
        if (exception != null) {
@@ -297,7 +250,6 @@ public final class ProviderCreateSession extends ProviderSession<
                        pendingIntentResponse.getResultData());
        if (credentialResponse != null) {
            mCallbacks.onFinalResponseReceived(mComponentName, credentialResponse);
            return;
        } else {
            Log.i(TAG, "onSaveEntrySelected - no response or error found in pending "
                    + "intent response");
@@ -305,6 +257,12 @@ public final class ProviderCreateSession extends ProviderSession<
        }
    }

    private void onRemoteEntrySelected(ProviderPendingIntentResponse pendingIntentResponse) {
        // Response from remote entry should be dealt with similar to a response from a
        // create entry
        onCreateEntrySelected(pendingIntentResponse);
    }

    @Nullable
    private CreateCredentialException maybeGetPendingIntentException(
            ProviderPendingIntentResponse pendingIntentResponse) {
@@ -336,4 +294,91 @@ public final class ProviderCreateSession extends ProviderSession<
                CreateCredentialException.TYPE_UNKNOWN,
                null);
    }

    private class ProviderResponseDataHandler {
        private final ComponentName mExpectedRemoteEntryProviderService;

        @NonNull
        private final Map<String, Pair<CreateEntry, Entry>> mUiCreateEntries = new HashMap<>();

        @Nullable private Pair<String, Pair<CreateEntry, Entry>> mUiRemoteEntry = null;

        ProviderResponseDataHandler(String hybridService) {
            mExpectedRemoteEntryProviderService = ComponentName.unflattenFromString(hybridService);
        }

        public void addResponseContent(List<CreateEntry> createEntries,
                CreateEntry remoteEntry) {
            createEntries.forEach(this::addCreateEntry);
            setRemoteEntry(remoteEntry);
        }
        public void addCreateEntry(CreateEntry createEntry) {
            String id = generateUniqueId();
            Entry entry = new Entry(SAVE_ENTRY_KEY,
                    id, createEntry.getSlice(), setUpFillInIntent());
            mUiCreateEntries.put(id, new Pair<>(createEntry, entry));
        }

        public void setRemoteEntry(@Nullable CreateEntry remoteEntry) {
            if (remoteEntry == null) {
                mUiRemoteEntry = null;
                return;
            }
            if (!mComponentName.equals(mExpectedRemoteEntryProviderService)) {
                Log.i(TAG, "Remote entry being dropped as it is not from the service "
                        + "configured by the OEM.");
                return;
            }
            String id = generateUniqueId();
            Entry entry = new Entry(REMOTE_ENTRY_KEY,
                    id, remoteEntry.getSlice(), setUpFillInIntent());
            mUiRemoteEntry = new Pair<>(id, new Pair<>(remoteEntry, entry));
        }

        public CreateCredentialProviderData toCreateCredentialProviderData() {
            return new CreateCredentialProviderData.Builder(
                    mComponentName.flattenToString())
                    .setSaveEntries(prepareUiCreateEntries())
                    .setRemoteEntry(prepareRemoteEntry())
                    .build();
        }

        private List<Entry> prepareUiCreateEntries() {
            List<Entry> createEntries = new ArrayList<>();
            for (String key : mUiCreateEntries.keySet()) {
                createEntries.add(mUiCreateEntries.get(key).second);
            }
            return createEntries;
        }

        private Entry prepareRemoteEntry() {
            if (mUiRemoteEntry == null || mUiRemoteEntry.first == null
                    || mUiRemoteEntry.second == null) {
                return null;
            }
            return mUiRemoteEntry.second.second;
        }

        private boolean isEmptyResponse() {
            return mUiCreateEntries.isEmpty() && mUiRemoteEntry == null;
        }
        @Nullable
        public CreateEntry getRemoteEntry(String entryKey) {
            return mUiRemoteEntry == null || mUiRemoteEntry
                    .first == null || !mUiRemoteEntry.first.equals(entryKey)
                    || mUiRemoteEntry.second == null
                    ? null : mUiRemoteEntry.second.first;
        }

        @Nullable
        public CreateEntry getCreateEntry(String entryKey) {
            return mUiCreateEntries.get(entryKey) == null
                    ? null : mUiCreateEntries.get(entryKey).first;
        }

        public boolean isEmptyResponse(BeginCreateCredentialResponse response) {
            return (response.getCreateEntries() == null || response.getCreateEntries().isEmpty())
                    && response.getRemoteCreateEntry() == null;
        }
    }
}
+319 −153

File changed.

Preview size limit exceeded, changes collapsed.

+1 −7
Original line number Diff line number Diff line
@@ -66,8 +66,7 @@ public abstract class ProviderSession<T, R>
     * on the credMan UI.
     */
    public static boolean isUiInvokingStatus(Status status) {
        return status == Status.CREDENTIALS_RECEIVED || status == Status.SAVE_ENTRIES_RECEIVED
                || status == Status.REQUIRES_AUTHENTICATION;
        return status == Status.CREDENTIALS_RECEIVED || status == Status.SAVE_ENTRIES_RECEIVED;
    }

    /**
@@ -208,11 +207,6 @@ public abstract class ProviderSession<T, R>
        }
    }

    protected void onRemoteEntrySelected(
            ProviderPendingIntentResponse providerPendingIntentResponse) {
        //TODO: Implement
    }

    /** Get the request to be sent to the provider. */
    protected T getProviderRequest() {
        return mProviderRequest;
+4 −0
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ import android.service.credentials.CallingAppInfo;
import android.service.credentials.CredentialProviderInfo;
import android.util.Log;

import com.android.internal.R;
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.credentials.metrics.CandidateProviderMetric;
import com.android.server.credentials.metrics.ChosenProviderMetric;
@@ -79,6 +80,7 @@ abstract class RequestSession<T, U> implements CredentialManagerUi.CredentialMan
    protected final Map<String, ProviderSession> mProviders = new HashMap<>();
    protected ChosenProviderMetric mChosenProviderMetric = new ChosenProviderMetric();
    //TODO improve design to allow grouped metrics per request
    protected final String mHybridService;

    protected RequestSession(@NonNull Context context,
            @UserIdInt int userId, int callingUid, @NonNull T clientRequest, U clientCallback,
@@ -97,6 +99,8 @@ abstract class RequestSession<T, U> implements CredentialManagerUi.CredentialMan
        mRequestId = new Binder();
        mCredentialManagerUi = new CredentialManagerUi(mContext,
                mUserId, this);
        mHybridService = context.getResources().getString(
                R.string.config_defaultCredentialManagerHybridService);
    }

    public abstract ProviderSession initiateProviderSession(CredentialProviderInfo providerInfo,