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

Commit fc24beab authored by Felipe Leme's avatar Felipe Leme
Browse files

Changed ContentCaptureService to receive one event at time.

The initial implementation was using a batch the events to optimize the
performance, but that can be optimize behind the scenes (i.e., we can still
send the batches in the binder, but deliver them one by one).

This change not only makes it easier for the service to use the API, but it
paves the way to implement multiple sessions (so we can buffer children events
while the parent session is not completely started yet).

Bug: 121033016
Bug: 117944706
Bug: 121051220

Test: atest CtsContentCaptureServiceTestCases

Change-Id: I713ceb998bd81733255fd3ef8d0b8d7a3fcac20c
parent b63e0ddc
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -5049,7 +5049,7 @@ package android.service.carrier {

package android.service.contentcapture {

  public final class ContentCaptureEventsRequest implements android.os.Parcelable {
  public final deprecated class ContentCaptureEventsRequest implements android.os.Parcelable {
    method public int describeContents();
    method public java.util.List<android.view.contentcapture.ContentCaptureEvent> getEvents();
    method public void writeToParcel(android.os.Parcel, int);
@@ -5061,7 +5061,8 @@ package android.service.contentcapture {
    method public final java.util.Set<android.content.ComponentName> getContentCaptureDisabledActivities();
    method public final java.util.Set<java.lang.String> getContentCaptureDisabledPackages();
    method public void onActivitySnapshot(android.view.contentcapture.ContentCaptureSessionId, android.service.contentcapture.SnapshotData);
    method public void onContentCaptureEventsRequest(android.view.contentcapture.ContentCaptureSessionId, android.service.contentcapture.ContentCaptureEventsRequest);
    method public void onContentCaptureEvent(android.view.contentcapture.ContentCaptureSessionId, android.view.contentcapture.ContentCaptureEvent);
    method public deprecated void onContentCaptureEventsRequest(android.view.contentcapture.ContentCaptureSessionId, android.service.contentcapture.ContentCaptureEventsRequest);
    method public void onCreateContentCaptureSession(android.view.contentcapture.ContentCaptureContext, android.view.contentcapture.ContentCaptureSessionId);
    method public void onDestroyContentCaptureSession(android.view.contentcapture.ContentCaptureSessionId);
    method public final void setActivityContentCaptureEnabled(android.content.ComponentName, boolean);
+11 −7
Original line number Diff line number Diff line
@@ -17,26 +17,30 @@ package android.service.contentcapture;

import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.content.pm.ParceledListSlice;
import android.os.Parcel;
import android.os.Parcelable;
import android.view.contentcapture.ContentCaptureEvent;

import java.util.Arrays;
import java.util.List;

/**
 * Batch of content capture events.
 * Not needed anymore...
 *
 * @deprecated
 *
 * @hide
 */
@SystemApi
@Deprecated
public final class ContentCaptureEventsRequest implements Parcelable {
// TODO(b/121033016): remove .java and .aidl once service implementation doesn't use it anymore

    private final ParceledListSlice<ContentCaptureEvent> mEvents;
    private final ContentCaptureEvent mEvent;

    /** @hide */
    public ContentCaptureEventsRequest(@NonNull ParceledListSlice<ContentCaptureEvent> events) {
        mEvents = events;
    public ContentCaptureEventsRequest(@NonNull ContentCaptureEvent event) {
        mEvent = event;
    }

    /**
@@ -44,7 +48,7 @@ public final class ContentCaptureEventsRequest implements Parcelable {
     */
    @NonNull
    public List<ContentCaptureEvent> getEvents() {
        return mEvents.getList();
        return Arrays.asList(mEvent);
    }

    @Override
@@ -54,7 +58,7 @@ public final class ContentCaptureEventsRequest implements Parcelable {

    @Override
    public void writeToParcel(Parcel parcel, int flags) {
        parcel.writeParcelable(mEvents, flags);
        parcel.writeParcelable(mEvent, flags);
    }

    public static final Parcelable.Creator<ContentCaptureEventsRequest> CREATOR =
+35 −12
Original line number Diff line number Diff line
@@ -109,10 +109,9 @@ public abstract class ContentCaptureService extends Service {
            new IContentCaptureDirectManager.Stub() {

        @Override
        public void sendEvents(String sessionId,
                @SuppressWarnings("rawtypes") ParceledListSlice events) {
        public void sendEvents(@SuppressWarnings("rawtypes") ParceledListSlice events) {
            mHandler.sendMessage(obtainMessage(ContentCaptureService::handleSendEvents,
                            ContentCaptureService.this, sessionId, Binder.getCallingUid(), events));
                            ContentCaptureService.this, Binder.getCallingUid(), events));
        }
    };

@@ -218,17 +217,28 @@ public abstract class ContentCaptureService extends Service {
    }

    /**
     * Notifies the service of {@link ContentCaptureEvent events} associated with a content capture
     * session.
     *
     * @param sessionId the session's Id
     * @param request the events
     * @deprecated use {@link #onContentCaptureEvent(ContentCaptureSessionId, ContentCaptureEvent)}
     * instead.
     */
    @Deprecated
    public void onContentCaptureEventsRequest(@NonNull ContentCaptureSessionId sessionId,
            @NonNull ContentCaptureEventsRequest request) {
        if (VERBOSE) Log.v(TAG, "onContentCaptureEventsRequest(id=" + sessionId + ")");
    }

    /**
     * Notifies the service of {@link ContentCaptureEvent events} associated with a content capture
     * session.
     *
     * @param sessionId the session's Id
     * @param event the event
     */
    public void onContentCaptureEvent(@NonNull ContentCaptureSessionId sessionId,
            @NonNull ContentCaptureEvent event) {
        if (VERBOSE) Log.v(TAG, "onContentCaptureEventsRequest(id=" + sessionId + ")");
        onContentCaptureEventsRequest(sessionId, new ContentCaptureEventsRequest(event));
    }
    /**
     * Notifies the service of {@link SnapshotData snapshot data} associated with a session.
     *
@@ -272,11 +282,24 @@ public abstract class ContentCaptureService extends Service {
                mClientInterface.asBinder());
    }

    private void handleSendEvents(@NonNull String sessionId, int uid,
            @NonNull ParceledListSlice<ContentCaptureEvent> events) {
        if (handleIsRightCallerFor(sessionId, uid)) {
            onContentCaptureEventsRequest(new ContentCaptureSessionId(sessionId),
                    new ContentCaptureEventsRequest(events));
    private void handleSendEvents(int uid,
            @NonNull ParceledListSlice<ContentCaptureEvent> parceledEvents) {

        // Most events belong to the same session, so we can keep a reference to the last one
        // to avoid creating too many ContentCaptureSessionId objects
        String lastSessionId = null;
        ContentCaptureSessionId sessionId = null;

        final List<ContentCaptureEvent> events = parceledEvents.getList();
        for (int i = 0; i < events.size(); i++) {
            final ContentCaptureEvent event = events.get(i);
            String sessionIdString = event.getSessionId();
            if (!sessionIdString.equals(lastSessionId)) {
                if (!handleIsRightCallerFor(sessionIdString, uid)) continue;
                sessionId = new ContentCaptureSessionId(sessionIdString);
                lastSessionId = sessionIdString;
            }
            onContentCaptureEvent(sessionId, event);
        }
    }

+4 −4
Original line number Diff line number Diff line
@@ -327,7 +327,7 @@ public final class ActivityContentCaptureSession extends ContentCaptureSession {
            mHandler.removeMessages(MSG_FLUSH);

            final ParceledListSlice<ContentCaptureEvent> events = handleClearEvents();
            mDirectServiceInterface.sendEvents(mId, events);
            mDirectServiceInterface.sendEvents(events);
        } catch (RemoteException e) {
            Log.w(mTag, "Error sending " + numberEvents + " for " + getActivityDebugName()
                    + ": " + e);
@@ -387,14 +387,14 @@ public final class ActivityContentCaptureSession extends ContentCaptureSession {
    @Override
    void internalNotifyViewAppeared(@NonNull ViewStructureImpl node) {
        mHandler.sendMessage(obtainMessage(ActivityContentCaptureSession::handleSendEvent, this,
                new ContentCaptureEvent(TYPE_VIEW_APPEARED)
                new ContentCaptureEvent(mId, TYPE_VIEW_APPEARED)
                        .setViewNode(node.mNode), /* forceFlush= */ false));
    }

    @Override
    void internalNotifyViewDisappeared(@NonNull AutofillId id) {
        mHandler.sendMessage(obtainMessage(ActivityContentCaptureSession::handleSendEvent, this,
                new ContentCaptureEvent(TYPE_VIEW_DISAPPEARED).setAutofillId(id),
                new ContentCaptureEvent(mId, TYPE_VIEW_DISAPPEARED).setAutofillId(id),
                        /* forceFlush= */ false));
    }

@@ -402,7 +402,7 @@ public final class ActivityContentCaptureSession extends ContentCaptureSession {
    void internalNotifyViewTextChanged(@NonNull AutofillId id, @Nullable CharSequence text,
            int flags) {
        mHandler.sendMessage(obtainMessage(ActivityContentCaptureSession::handleSendEvent, this,
                new ContentCaptureEvent(TYPE_VIEW_TEXT_CHANGED, flags).setAutofillId(id)
                new ContentCaptureEvent(mId, TYPE_VIEW_TEXT_CHANGED, flags).setAutofillId(id)
                        .setText(text), /* forceFlush= */ false));
    }

+19 −8
Original line number Diff line number Diff line
@@ -29,7 +29,6 @@ import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

// TODO(b/111276913): add javadocs / implement Parcelable / implement
/** @hide */
@SystemApi
public final class ContentCaptureEvent implements Parcelable {
@@ -72,6 +71,7 @@ public final class ContentCaptureEvent implements Parcelable {
    @Retention(RetentionPolicy.SOURCE)
    public @interface EventType{}

    private final @NonNull String mSessionId;
    private final int mType;
    private final long mEventTime;
    private final int mFlags;
@@ -80,21 +80,21 @@ public final class ContentCaptureEvent implements Parcelable {
    private @Nullable CharSequence mText;

    /** @hide */
    public ContentCaptureEvent(int type, long eventTime, int flags) {
    public ContentCaptureEvent(@NonNull String sessionId, int type, long eventTime, int flags) {
        mSessionId = sessionId;
        mType = type;
        mEventTime = eventTime;
        mFlags = flags;
    }


    /** @hide */
    public ContentCaptureEvent(int type, int flags) {
        this(type, System.currentTimeMillis(), flags);
    public ContentCaptureEvent(@NonNull String sessionId, int type, int flags) {
        this(sessionId, type, System.currentTimeMillis(), flags);
    }

    /** @hide */
    public ContentCaptureEvent(int type) {
        this(type, /* flags= */ 0);
    public ContentCaptureEvent(@NonNull String sessionId, int type) {
        this(sessionId, type, /* flags= */ 0);
    }

    /** @hide */
@@ -104,12 +104,20 @@ public final class ContentCaptureEvent implements Parcelable {
    }

    /** @hide */
    @NonNull
    public String getSessionId() {
        return mSessionId;
    }

    /** @hide */
    @NonNull
    public ContentCaptureEvent setViewNode(@NonNull ViewNode node) {
        mNode = Preconditions.checkNotNull(node);
        return this;
    }

    /** @hide */
    @NonNull
    public ContentCaptureEvent setText(@Nullable CharSequence text) {
        mText = text;
        return this;
@@ -214,6 +222,7 @@ public final class ContentCaptureEvent implements Parcelable {

    @Override
    public void writeToParcel(Parcel parcel, int flags) {
        parcel.writeString(mSessionId);
        parcel.writeInt(mType);
        parcel.writeLong(mEventTime);
        parcel.writeInt(mFlags);
@@ -227,10 +236,12 @@ public final class ContentCaptureEvent implements Parcelable {

        @Override
        public ContentCaptureEvent createFromParcel(Parcel parcel) {
            final String sessionId = parcel.readString();
            final int type = parcel.readInt();
            final long eventTime  = parcel.readLong();
            final int flags = parcel.readInt();
            final ContentCaptureEvent event = new ContentCaptureEvent(type, eventTime, flags);
            final ContentCaptureEvent event =
                    new ContentCaptureEvent(sessionId, type, eventTime, flags);
            final AutofillId id = parcel.readParcelable(null);
            if (id != null) {
                event.setAutofillId(id);
Loading