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

Commit 7828e37b authored by Reema Bajwa's avatar Reema Bajwa Committed by Android (Google) Code Review
Browse files

Merge "Propagate exceptions to developer" into main

parents 083168e4 2cd1ebbd
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -9957,6 +9957,17 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
        getCredentialManagerCallback().onResult(response);
    }
    /**
     * @hide
     */
    public void onGetCredentialException(String errorType, String errorMsg) {
        if (getCredentialManagerCallback() == null) {
            Log.w(AUTOFILL_LOG_TAG, "onGetCredentialException called but no callback found");
            return;
        }
        getCredentialManagerCallback().onError(new GetCredentialException(errorType, errorMsg));
    }
    /**
     * Gets the unique, logical identifier of this view in the activity, for autofill purposes.
     *
+60 −0
Original line number Diff line number Diff line
@@ -50,6 +50,7 @@ import android.content.Intent;
import android.content.IntentSender;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.credentials.GetCredentialException;
import android.credentials.GetCredentialResponse;
import android.graphics.Rect;
import android.metrics.LogMaker;
@@ -105,6 +106,7 @@ import org.xmlpull.v1.XmlPullParserException;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.Serializable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
@@ -2400,6 +2402,13 @@ public final class AutofillManager {

            final Bundle responseData = new Bundle();
            responseData.putParcelable(EXTRA_AUTHENTICATION_RESULT, result);
            Serializable exception = data.getSerializableExtra(
                    CredentialProviderService.EXTRA_GET_CREDENTIAL_EXCEPTION,
                    GetCredentialException.class);
            if (exception != null && Flags.autofillCredmanIntegration()) {
                responseData.putSerializable(
                        CredentialProviderService.EXTRA_GET_CREDENTIAL_EXCEPTION, exception);
            }
            final Bundle newClientState = data.getBundleExtra(EXTRA_CLIENT_STATE);
            if (newClientState != null) {
                responseData.putBundle(EXTRA_CLIENT_STATE, newClientState);
@@ -2926,6 +2935,48 @@ public final class AutofillManager {
        }
    }

    private void onGetCredentialException(int sessionId, AutofillId id, String errorType,
            String errorMsg) {
        synchronized (mLock) {
            if (sessionId != mSessionId) {
                Log.w(TAG, "onGetCredentialException afm sessionIds don't match");
                return;
            }

            final AutofillClient client = getClient();
            if (client == null) {
                Log.w(TAG, "onGetCredentialException afm client id null");
                return;
            }
            ArrayList<AutofillId> failedIds = new ArrayList<>();
            final View[] views = client.autofillClientFindViewsByAutofillIdTraversal(
                    Helper.toArray(new ArrayList<>(Collections.singleton(id))));
            if (views == null || views.length == 0) {
                Log.w(TAG, "onGetCredentialException afm client view not found");
                return;
            }

            final View view = views[0];
            if (view == null) {
                Log.i(TAG, "onGetCredentialException View is null");

                // Most likely view has been removed after the initial request was sent to the
                // the service; this is fine, but we need to update the view status in the
                // server side so it can be triggered again.
                Log.d(TAG, "onGetCredentialException(): no View with id " + id);
                failedIds.add(id);
            }
            if (id.isVirtualInt()) {
                Log.i(TAG, "onGetCredentialException afm client id is virtual");
                // TODO(b/326314286): Handle virtual views
            } else {
                Log.i(TAG, "onGetCredentialException afm client id is NOT virtual");
                view.onGetCredentialException(errorType, errorMsg);
            }
            handleFailedIdsLocked(failedIds);
        }
    }

    private void onGetCredentialResponse(int sessionId, AutofillId id,
            GetCredentialResponse response) {
        synchronized (mLock) {
@@ -4381,6 +4432,15 @@ public final class AutofillManager {
            }
        }

        @Override
        public void onGetCredentialException(int sessionId, AutofillId id,
                String errorType, String errorMsg) {
            final AutofillManager afm = mAfm.get();
            if (afm != null) {
                afm.post(() -> afm.onGetCredentialException(sessionId, id, errorType, errorMsg));
            }
        }

        @Override
        public void autofillContent(int sessionId, AutofillId id, ClipData content) {
            final AutofillManager afm = mAfm.get();
+4 −1
Original line number Diff line number Diff line
@@ -52,6 +52,9 @@ oneway interface IAutoFillManagerClient {
    void onGetCredentialResponse(int sessionId, in AutofillId id,
                 in GetCredentialResponse response);

    void onGetCredentialException(int sessionId, in AutofillId id,
                     in String errorType, in String errorMsg);

    /**
     * Autofills the activity with rich content data (e.g. an image) from a dataset.
     */
+46 −13
Original line number Diff line number Diff line
@@ -193,6 +193,7 @@ import com.android.server.inputmethod.InputMethodManagerInternal;
import com.android.server.wm.ActivityTaskManagerInternal;

import java.io.PrintWriter;
import java.io.Serializable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
@@ -2802,9 +2803,10 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState

        final int datasetIdx = AutofillManager.getDatasetIdFromAuthenticationId(
                authenticationId);
        Dataset dataset = null;
        // Authenticated a dataset - reset view state regardless if we got a response or a dataset
        if (datasetIdx != AutofillManager.AUTHENTICATION_ID_DATASET_ID_UNDEFINED) {
            final Dataset dataset = authenticatedResponse.getDatasets().get(datasetIdx);
            dataset = authenticatedResponse.getDatasets().get(datasetIdx);
            if (dataset == null) {
                Slog.w(TAG, "no dataset with index " + datasetIdx + " on fill response");
                mPresentationStatsEventLogger.maybeSetAuthenticationResult(
@@ -2819,12 +2821,28 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
        mSessionFlags.mExpiredResponse = false;

        final Parcelable result = data.getParcelable(AutofillManager.EXTRA_AUTHENTICATION_RESULT);
        final Serializable exception = data.getSerializable(
                CredentialProviderService.EXTRA_GET_CREDENTIAL_EXCEPTION);

        final Bundle newClientState = data.getBundle(AutofillManager.EXTRA_CLIENT_STATE);
        if (sDebug) {
            Slog.d(TAG, "setAuthenticationResultLocked(): result=" + result
                    + ", clientState=" + newClientState + ", authenticationId=" + authenticationId);
        }
        if (Flags.autofillCredmanDevIntegration() && exception != null
                && exception instanceof GetCredentialException) {
            if (dataset != null && dataset.getFieldIds().size() == 1) {
                if (sDebug) {
                    Slog.d(TAG, "setAuthenticationResultLocked(): result returns with"
                            + "Credential Manager Exception");
                }
                AutofillId autofillId = dataset.getFieldIds().get(0);
                sendCredentialManagerResponseToApp(/*response=*/ null,
                        (GetCredentialException) exception, autofillId);
            }
            return;
        }

        if (result instanceof FillResponse) {
            if (sDebug) {
                Slog.d(TAG, "setAuthenticationResultLocked(): received FillResponse from"
@@ -2840,13 +2858,21 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
            }
            if (Flags.autofillCredmanDevIntegration()) {
                GetCredentialResponse response = (GetCredentialResponse) result;
                if (dataset != null && dataset.getFieldIds().size() == 1) {
                    AutofillId autofillId = dataset.getFieldIds().get(0);
                    if (sDebug) {
                        Slog.d(TAG, "Received GetCredentialResponse from authentication flow,"
                                + "for autofillId: " + autofillId);
                    }
                    sendCredentialManagerResponseToApp(response,
                        /*exception=*/ null, response.getAutofillId());
                            /*exception=*/ null, autofillId);
                }
            } else if (Flags.autofillCredmanIntegration()) {
                Dataset dataset = getDatasetFromCredentialResponse(
                Dataset datasetFromCredentialResponse = getDatasetFromCredentialResponse(
                        (GetCredentialResponse) result);
                if (dataset != null) {
                    autoFill(requestId, datasetIdx, dataset, false, UI_TYPE_UNKNOWN);
                if (datasetFromCredentialResponse != null) {
                    autoFill(requestId, datasetIdx, datasetFromCredentialResponse,
                            false, UI_TYPE_UNKNOWN);
                }
            }
        } else if (result instanceof Dataset) {
@@ -2863,12 +2889,12 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
                    if (sDebug) Slog.d(TAG,  "Updating client state from auth dataset");
                    mClientState = newClientState;
                }
                Dataset dataset = getEffectiveDatasetForAuthentication((Dataset) result);
                Dataset datasetFromResult = getEffectiveDatasetForAuthentication((Dataset) result);
                final Dataset oldDataset = authenticatedResponse.getDatasets().get(datasetIdx);
                if (!isAuthResultDatasetEphemeral(oldDataset, data)) {
                    authenticatedResponse.getDatasets().set(datasetIdx, dataset);
                    authenticatedResponse.getDatasets().set(datasetIdx, datasetFromResult);
                }
                autoFill(requestId, datasetIdx, dataset, false, UI_TYPE_UNKNOWN);
                autoFill(requestId, datasetIdx, datasetFromResult, false, UI_TYPE_UNKNOWN);
            } else {
                Slog.w(TAG, "invalid index (" + datasetIdx + ") for authentication id "
                        + authenticationId);
@@ -5052,12 +5078,16 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
    }

    private void addCredentialManagerCallbackForDataset(Dataset dataset, int requestId) {
        AutofillId autofillId = null;
        if (dataset != null && dataset.getFieldIds().size() == 1) {
            autofillId = dataset.getFieldIds().get(0);
        }
        final AutofillId finalAutofillId = autofillId;
        final ResultReceiver resultReceiver = new ResultReceiver(mHandler) {
            @Override
            protected void onReceiveResult(int resultCode, Bundle resultData) {
                if (resultCode == SUCCESS_CREDMAN_SELECTOR) {
                    Slog.d(TAG, "onReceiveResult from Credential Manager bottom sheet");
                    boolean isCredmanCallbackInvoked = false;
                    GetCredentialResponse getCredentialResponse =
                            resultData.getParcelable(
                                    CredentialProviderService.EXTRA_GET_CREDENTIAL_RESPONSE,
@@ -5065,7 +5095,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState

                    if (Flags.autofillCredmanDevIntegration()) {
                        sendCredentialManagerResponseToApp(getCredentialResponse,
                                /*exception=*/ null, getCredentialResponse.getAutofillId());
                                /*exception=*/ null, finalAutofillId);
                    } else {
                        Dataset datasetFromCredential = getDatasetFromCredentialResponse(
                                getCredentialResponse);
@@ -5082,7 +5112,9 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
                        Slog.w(TAG, "Credman bottom sheet from pinned "
                                + "entry failed with: + " + exception[0] + " , "
                                + exception[1]);
                        // TODO(b/326313420): Propagate exception
                        sendCredentialManagerResponseToApp(/*response=*/ null,
                                new GetCredentialException(exception[0], exception[1]),
                                finalAutofillId);
                    }
                } else {
                    Slog.d(TAG, "Unknown resultCode from credential "
@@ -6380,7 +6412,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
                    }
                }
                if (exception != null) {
                    // TODO(b/326313420): Add Exception support
                    mClient.onGetCredentialException(id, viewId, exception.getType(),
                            exception.getMessage());
                } else if (response != null) {
                    mClient.onGetCredentialResponse(id, viewId, response);
                } else {
+12 −4
Original line number Diff line number Diff line
@@ -150,7 +150,8 @@ public class GetCandidateRequestSession extends RequestSession<GetCredentialRequ
    @Override
    public void onFinalErrorReceived(ComponentName componentName, String errorType,
            String message) {
        respondToClientWithErrorAndFinish(errorType, message);
        Slog.d(TAG, "onFinalErrorReceived");
        respondToFinalReceiverWithFailureAndFinish(this.mFinalResponseReceiver, errorType, message);
    }

    @Override
@@ -163,6 +164,13 @@ public class GetCandidateRequestSession extends RequestSession<GetCredentialRequ
            message = "The UI was interrupted - please try again.";
        }
        mRequestSessionMetric.collectFrameworkException(exception);
        respondToFinalReceiverWithFailureAndFinish(finalResponseReceiver, exception, message);
    }

    private void respondToFinalReceiverWithFailureAndFinish(
            ResultReceiver finalResponseReceiver,
            String exception, String message
    ) {
        if (finalResponseReceiver != null) {
            Bundle resultData = new Bundle();
            resultData.putStringArray(
@@ -170,16 +178,16 @@ public class GetCandidateRequestSession extends RequestSession<GetCredentialRequ
                    new String[] {exception, message});
            finalResponseReceiver.send(Constants.FAILURE_CREDMAN_SELECTOR, resultData);
        } else {
            respondToClientWithErrorAndFinish(exception, message);
            Slog.w(TAG, "onUiCancellation called but finalResponseReceiver not found");
        }
        finishSession(/*propagateCancellation=*/false);
    }

    @Override
    public void onUiSelectorInvocationFailure() {
        String exception = GetCandidateCredentialsException.TYPE_NO_CREDENTIAL;
        mRequestSessionMetric.collectFrameworkException(exception);
        respondToClientWithErrorAndFinish(exception,
                "No credentials available.");
        // TODO(): Propagate through final receiver
    }

    @Override
Loading