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

Commit 2cd1ebbd authored by Reema Bajwa's avatar Reema Bajwa
Browse files

Propagate exceptions to developer

Test: Cts
Bug: 326313420

Change-Id: Ia4fa05402957582d0569bd02e35304e684bf3305
parent 678678fc
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -9923,6 +9923,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