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

Commit 2f517c26 authored by Philip P. Moltmann's avatar Philip P. Moltmann
Browse files

Take new autofill structure for each partition

Bug: 36481649
Test: CtsAutofillServiceTestCases (now with a test that has an autofill
      session over two full screen fragments)
Change-Id: I55f2f6203f3bd5a7082b4ce90500d2c16a260c7d
parent 85d1c2d2
Loading
Loading
Loading
Loading
+0 −4
Original line number Diff line number Diff line
@@ -66,10 +66,6 @@ public abstract class AutofillService extends Service {
     */
    public static final String SERVICE_META_DATA = "android.autofill";

    // Internal extras
    /** @hide */
    public static final String EXTRA_SESSION_ID = "android.service.autofill.extra.SESSION_ID";

    // Handler messages.
    private static final int MSG_CONNECT = 1;
    private static final int MSG_DISCONNECT = 2;
+2 −9
Original line number Diff line number Diff line
@@ -39,8 +39,6 @@ import java.util.concurrent.atomic.AtomicInteger;
 * @see AutofillService#onFillRequest(FillRequest, CancellationSignal, FillCallback)
 */
public final class FillRequest implements Parcelable {
    private static AtomicInteger sIdCounter = new AtomicInteger();

    /**
     * Indicates autofill was explicitly requested by the user.
     */
@@ -58,12 +56,6 @@ public final class FillRequest implements Parcelable {
    private final @NonNull AssistStructure mStructure;
    private final @Nullable Bundle mClientState;

    /** @hide */
    public FillRequest(@NonNull AssistStructure structure,
            @Nullable Bundle clientState, @RequestFlags int flags) {
        this(sIdCounter.incrementAndGet(), structure, clientState, flags);
    }

    private FillRequest(@NonNull Parcel parcel) {
        mId = parcel.readInt();
        mStructure = parcel.readParcelable(null);
@@ -71,7 +63,8 @@ public final class FillRequest implements Parcelable {
        mFlags = parcel.readInt();
    }

    private FillRequest(int id, @NonNull AssistStructure structure,
    /** @hide */
    public FillRequest(int id, @NonNull AssistStructure structure,
            @Nullable Bundle clientState, @RequestFlags int flags) {
        mId = id;
        mFlags = Preconditions.checkFlagsArgument(flags, FLAG_MANUAL_REQUEST);
+0 −73
Original line number Diff line number Diff line
@@ -16,9 +16,6 @@

package com.android.server.autofill;

import static android.service.autofill.AutofillService.EXTRA_SESSION_ID;
import static android.service.voice.VoiceInteractionSession.KEY_RECEIVER_EXTRAS;
import static android.service.voice.VoiceInteractionSession.KEY_STRUCTURE;
import static android.view.autofill.AutofillManager.FLAG_START_SESSION;
import static android.view.autofill.AutofillManager.NO_SESSION;

@@ -27,10 +24,7 @@ import static com.android.server.autofill.Helper.VERBOSE;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.AppGlobals;
import android.app.assist.AssistStructure;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ApplicationInfo;
@@ -50,7 +44,6 @@ import android.service.autofill.AutofillService;
import android.service.autofill.AutofillServiceInfo;
import android.service.autofill.FillEventHistory;
import android.service.autofill.FillEventHistory.Event;
import android.service.autofill.FillRequest;
import android.service.autofill.FillResponse;
import android.service.autofill.IAutoFillService;
import android.text.TextUtils;
@@ -66,7 +59,6 @@ import android.view.autofill.IAutoFillManagerClient;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.os.HandlerCaller;
import com.android.internal.os.IResultReceiver;
import com.android.server.autofill.ui.AutoFillUI;

import java.io.PrintWriter;
@@ -127,56 +119,6 @@ final class AutofillManagerServiceImpl {
    @GuardedBy("mLock")
    private FillEventHistory mEventHistory;

    /**
     * Receiver of assist data from the app's {@link Activity}.
     */
    private final IResultReceiver mAssistReceiver = new IResultReceiver.Stub() {
        @Override
        public void send(int resultCode, Bundle resultData) throws RemoteException {
            if (VERBOSE) {
                Slog.v(TAG, "resultCode on mAssistReceiver: " + resultCode);
            }

            final AssistStructure structure = resultData.getParcelable(KEY_STRUCTURE);
            if (structure == null) {
                Slog.wtf(TAG, "no assist structure for id " + resultCode);
                return;
            }

            final Bundle receiverExtras = resultData.getBundle(KEY_RECEIVER_EXTRAS);
            if (receiverExtras == null) {
                Slog.wtf(TAG, "No " + KEY_RECEIVER_EXTRAS + " on receiver");
                return;
            }

            final int sessionId = receiverExtras.getInt(EXTRA_SESSION_ID);
            final Session session;
            synchronized (mLock) {
                session = mSessions.get(sessionId);
                if (session == null) {
                    Slog.w(TAG, "no server session for " + sessionId);
                    return;
                }
                session.setStructureLocked(structure);
            }


            // TODO(b/35708678): Must fetch the data so it's available later on
            // handleSave(), even if if the activity is gone by then, but structure.ensureData()
            // gives a ONE_WAY warning because system_service could block on app calls.
            // We need to change AssistStructure so it provides a "one-way" writeToParcel()
            // method that sends all the data
            structure.ensureData();

            // Sanitize structure before it's sent to service.
            structure.sanitizeForParceling(true);

            // This is the first request, hence there is no Bundle to be sent as clientState
            final FillRequest request = new FillRequest(structure, null, session.mFlags);
            session.mRemoteFillService.onFillRequest(request);
        }
    };

    AutofillManagerServiceImpl(Context context, Object lock, LocalLog requestsHistory,
            int userId, AutoFillUI ui, boolean disabled) {
        mContext = context;
@@ -393,21 +335,6 @@ final class AutofillManagerServiceImpl {
                mInfo.getServiceInfo().getComponentName(), packageName);
        mSessions.put(newSession.id, newSession);

        try {
            final Bundle receiverExtras = new Bundle();
            receiverExtras.putInt(EXTRA_SESSION_ID, sessionId);
            final long identity = Binder.clearCallingIdentity();
            try {
                if (!ActivityManager.getService().requestAutofillData(mAssistReceiver,
                        receiverExtras, activityToken)) {
                    Slog.w(TAG, "failed to request autofill data for " + activityToken);
                }
            } finally {
                Binder.restoreCallingIdentity(identity);
            }
        } catch (RemoteException e) {
            // Should not happen, it's a local call.
        }
        return newSession;
    }

+38 −0
Original line number Diff line number Diff line
@@ -16,7 +16,12 @@

package com.android.server.autofill;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.assist.AssistStructure;
import android.app.assist.AssistStructure.ViewNode;
import android.os.Bundle;
import android.view.autofill.AutofillId;

import java.util.Arrays;
import java.util.Objects;
@@ -53,4 +58,37 @@ final class Helper {
    private Helper() {
        throw new UnsupportedOperationException("contains static members only");
    }

    static ViewNode findViewNodeById(@NonNull AssistStructure structure, @NonNull AutofillId id) {
        final int size = structure.getWindowNodeCount();
        for (int i = 0; i < size; i++) {
            final AssistStructure.WindowNode window = structure.getWindowNodeAt(i);
            final ViewNode root = window.getRootViewNode();
            if (id.equals(root.getAutofillId())) {
                return root;
            }
            final ViewNode child = findViewNodeById(root, id);
            if (child != null) {
                return child;
            }
        }
        return null;
    }

    static ViewNode findViewNodeById(@NonNull ViewNode parent, @NonNull AutofillId id) {
        final int childrenSize = parent.getChildCount();
        if (childrenSize > 0) {
            for (int i = 0; i < childrenSize; i++) {
                final ViewNode child = parent.getChildAt(i);
                if (id.equals(child.getAutofillId())) {
                    return child;
                }
                final ViewNode grandChild = findViewNodeById(child, id);
                if (grandChild != null && id.equals(grandChild.getAutofillId())) {
                    return grandChild;
                }
            }
        }
        return null;
    }
}
+17 −0
Original line number Diff line number Diff line
@@ -134,6 +134,23 @@ final class RemoteFillService implements DeathRecipient {
        mCallbacks.onServiceDied(this);
    }

    /**
     * Cancel the currently pending request.
     *
     * <p>This can be used when the request is unnecessary or will be superceeded by a request that
     * will soon be queued.
     */
    public void cancelCurrentRequest() {
        if (mDestroyed) {
            return;
        }

        if (mPendingRequest != null) {
            mPendingRequest.cancel();
            mPendingRequest = null;
        }
    }

    public void onFillRequest(@NonNull FillRequest request) {
        cancelScheduledUnbind();
        final PendingFillRequest pendingRequest = new PendingFillRequest(request, this);
Loading