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

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

Merge "Add support for virtual views" into main

parents 1c1bd35f 8bba1636
Loading
Loading
Loading
Loading
+64 −3
Original line number Diff line number Diff line
package android.app.assist;

import static android.credentials.Constants.FAILURE_CREDMAN_SELECTOR;
import static android.credentials.Constants.SUCCESS_CREDMAN_SELECTOR;
import static android.service.autofill.Flags.FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION;

import android.annotation.FlaggedApi;
@@ -20,14 +22,17 @@ import android.net.Uri;
import android.os.BadParcelableException;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.LocaleList;
import android.os.Looper;
import android.os.OutcomeReceiver;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.PooledStringReader;
import android.os.PooledStringWriter;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.SystemClock;
import android.service.autofill.FillRequest;
import android.service.credentials.CredentialProviderService;
@@ -37,6 +42,7 @@ import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Pair;
import android.util.Slog;
import android.view.View;
import android.view.View.AutofillImportance;
import android.view.ViewRootImpl;
@@ -652,6 +658,9 @@ public class AssistStructure implements Parcelable {
        @Nullable OutcomeReceiver<GetCredentialResponse, GetCredentialException>
                mGetCredentialCallback;

        @Nullable ResultReceiver mGetCredentialResultReceiver;


        AutofillValue mAutofillValue;
        CharSequence[] mAutofillOptions;
        boolean mSanitized;
@@ -916,6 +925,7 @@ public class AssistStructure implements Parcelable {
                mExtras = in.readBundle();
            }
            mGetCredentialRequest = in.readTypedObject(GetCredentialRequest.CREATOR);
            mGetCredentialResultReceiver = in.readTypedObject(ResultReceiver.CREATOR);
        }

        /**
@@ -1153,6 +1163,7 @@ public class AssistStructure implements Parcelable {
                out.writeBundle(mExtras);
            }
            out.writeTypedObject(mGetCredentialRequest, flags);
            out.writeTypedObject(mGetCredentialResultReceiver, flags);
            return flags;
        }

@@ -1295,9 +1306,8 @@ public class AssistStructure implements Parcelable {
         */
        @FlaggedApi(FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION)
        @Nullable
        public OutcomeReceiver<GetCredentialResponse,
                GetCredentialException> getCredentialManagerCallback() {
            return mGetCredentialCallback;
        public ResultReceiver getCredentialManagerCallback() {
            return mGetCredentialResultReceiver;
        }

        /**
@@ -1894,6 +1904,7 @@ public class AssistStructure implements Parcelable {
        final AssistStructure mAssist;
        final ViewNode mNode;
        final boolean mAsync;
        private Handler mHandler;

        /**
         * Used to instantiate a builder for a stand-alone {@link ViewNode} which is not associated
@@ -2271,6 +2282,56 @@ public class AssistStructure implements Parcelable {
                option.getCandidateQueryData()
                        .putParcelableArrayList(CredentialProviderService.EXTRA_AUTOFILL_ID, ids);
            }
            setUpResultReceiver(callback);
        }

        private void setUpResultReceiver(
                OutcomeReceiver<GetCredentialResponse, GetCredentialException> callback) {

            if (mHandler == null) {
                mHandler = new Handler(Looper.getMainLooper(), null, true);
            }
            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");
                        GetCredentialResponse getCredentialResponse =
                                resultData.getParcelable(
                                        CredentialProviderService.EXTRA_GET_CREDENTIAL_RESPONSE,
                                        GetCredentialResponse.class);

                        callback.onResult(getCredentialResponse);
                    } else if (resultCode == FAILURE_CREDMAN_SELECTOR) {
                        String[] exception =  resultData.getStringArray(
                                CredentialProviderService.EXTRA_GET_CREDENTIAL_EXCEPTION);
                        if (exception != null && exception.length >= 2) {
                            Slog.w(TAG, "Credman bottom sheet from pinned "
                                    + "entry failed with: + " + exception[0] + " , "
                                    + exception[1]);
                            callback.onError(new GetCredentialException(
                                    exception[0], exception[1]));
                        }
                    } else {
                        Slog.d(TAG, "Unknown resultCode from credential "
                                + "manager bottom sheet: " + resultCode);
                    }
                }
            };
            ResultReceiver ipcFriendlyResultReceiver =
                    toIpcFriendlyResultReceiver(resultReceiver);
            mNode.mGetCredentialResultReceiver = ipcFriendlyResultReceiver;
        }

        private ResultReceiver toIpcFriendlyResultReceiver(ResultReceiver resultReceiver) {
            final Parcel parcel = Parcel.obtain();
            resultReceiver.writeToParcel(parcel, 0);
            parcel.setDataPosition(0);

            final ResultReceiver ipcFriendly = ResultReceiver.CREATOR.createFromParcel(parcel);
            parcel.recycle();

            return ipcFriendly;
        }

        @Override
+2 −1
Original line number Diff line number Diff line
@@ -315,7 +315,8 @@ public abstract class ViewStructure {
    /**
     * Add to this view's child count.  This increases the current child count by
     * <var>num</var> children beyond what was last set by {@link #setChildCount}
     * or {@link #addChildCount}.  The index at which the new child starts in the child
     * or {@link #addChildCount}.  The index at which the new
     * child starts in the child
     * array is returned.
     *
     * @param num The number of new children to add.
+0 −41
Original line number Diff line number Diff line
@@ -21,8 +21,6 @@ import android.app.assist.AssistStructure
import android.content.Context
import android.credentials.CredentialManager
import android.credentials.GetCredentialRequest
import android.credentials.GetCredentialResponse
import android.credentials.GetCredentialException
import android.credentials.GetCandidateCredentialsResponse
import android.credentials.GetCandidateCredentialsException
import android.credentials.CredentialOption
@@ -124,13 +122,10 @@ class CredentialAutofillService : AutofillService() {
        // TODO(b/324635774): Use callback for validating. If the request is coming
        // directly from the view, there should be a corresponding callback, otherwise
        // we should fail fast,
        val getCredCallback = getCredManCallback(structure)
        if (getCredRequest == null) {
            Log.i(TAG, "No credential manager request found")
            callback.onFailure("No credential manager request found")
            return
        } else if (getCredCallback == null) {
            Log.i(TAG, "No credential manager callback found")
        }
        val credentialManager: CredentialManager =
                getSystemService(Context.CREDENTIAL_SERVICE) as CredentialManager
@@ -528,42 +523,6 @@ class CredentialAutofillService : AutofillService() {
        TODO("Not yet implemented")
    }

    private fun getCredManCallback(structure: AssistStructure): OutcomeReceiver<
            GetCredentialResponse, GetCredentialException>? {
        return traverseStructureForCallback(structure)
    }

    private fun traverseStructureForCallback(
            structure: AssistStructure
    ): OutcomeReceiver<GetCredentialResponse, GetCredentialException>? {
        val windowNodes: List<AssistStructure.WindowNode> =
                structure.run {
                    (0 until windowNodeCount).map { getWindowNodeAt(it) }
                }

        windowNodes.forEach { windowNode: AssistStructure.WindowNode ->
            return traverseNodeForCallback(windowNode.rootViewNode)
        }
        return null
    }

    private fun traverseNodeForCallback(
            viewNode: AssistStructure.ViewNode
    ): OutcomeReceiver<GetCredentialResponse, GetCredentialException>? {
        val children: List<AssistStructure.ViewNode> =
                viewNode.run {
                    (0 until childCount).map { getChildAt(it) }
                }

        children.forEach { childNode: AssistStructure.ViewNode ->
            if (childNode.isFocused() && childNode.credentialManagerCallback != null) {
                return childNode.credentialManagerCallback
            }
            return traverseNodeForCallback(childNode)
        }
        return null
    }

    private fun getCredManRequest(
            structure: AssistStructure,
            sessionId: Int,
+33 −1
Original line number Diff line number Diff line
@@ -3930,6 +3930,24 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
        return mSessionFlags.mShowingSaveUi;
    }

    /**
     * Gets the latest non-empty value for the given id in the autofill contexts.
     */
    @GuardedBy("mLock")
    @Nullable
    private ViewNode getViewNodeFromContextsLocked(@NonNull AutofillId autofillId) {
        final int numContexts = mContexts.size();
        for (int i = numContexts - 1; i >= 0; i--) {
            final FillContext context = mContexts.get(i);
            final ViewNode node = Helper.findViewNodeByAutofillId(context.getStructure(),
                    autofillId);
            if (node != null) {
                return node;
            }
        }
        return null;
    }

    /**
     * Gets the latest non-empty value for the given id in the autofill contexts.
     */
@@ -6417,7 +6435,21 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
                    mClient.onGetCredentialException(id, viewId, exception.getType(),
                            exception.getMessage());
                } else if (response != null) {
                    if (viewId.isVirtualInt()) {
                        ViewNode viewNode = getViewNodeFromContextsLocked(viewId);
                        if (viewNode != null && viewNode.getCredentialManagerCallback() != null) {
                            Bundle resultData = new Bundle();
                            resultData.putParcelable(
                                    CredentialProviderService.EXTRA_GET_CREDENTIAL_RESPONSE,
                                    response);
                            viewNode.getCredentialManagerCallback().send(SUCCESS_CREDMAN_SELECTOR,
                                        resultData);
                        } else {
                            Slog.w(TAG, "View node not found after GetCredentialResponse");
                        }
                    } else {
                        mClient.onGetCredentialResponse(id, viewId, response);
                    }
                } else {
                    Slog.w(TAG, "sendCredentialManagerResponseToApp called with null response"
                            + "and exception");