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

Commit dd18a16d authored by MingWei Liao's avatar MingWei Liao Committed by Android (Google) Code Review
Browse files

Merge "Enable content capture running on background thread" into main

parents d1b76b61 fa4334fc
Loading
Loading
Loading
Loading
+11 −49
Original line number Diff line number Diff line
@@ -130,7 +130,6 @@ import android.graphics.FrameInfo;
import android.graphics.HardwareRenderer;
import android.graphics.HardwareRenderer.FrameDrawingCallback;
import android.graphics.HardwareRendererObserver;
import android.graphics.Insets;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PixelFormat;
@@ -206,7 +205,6 @@ import android.view.accessibility.IAccessibilityInteractionConnection;
import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.Interpolator;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillManager;
import android.view.contentcapture.ContentCaptureManager;
import android.view.contentcapture.ContentCaptureSession;
@@ -4029,7 +4027,6 @@ public final class ViewRootImpl implements ViewParent,
    }

    private void notifyContentCaptureEvents() {
        try {
        if (!isContentCaptureEnabled()) {
            if (DEBUG_CONTENT_CAPTURE) {
                Log.d(mTag, "notifyContentCaptureEvents while disabled");
@@ -4037,48 +4034,13 @@ public final class ViewRootImpl implements ViewParent,
            mAttachInfo.mContentCaptureEvents = null;
            return;
        }
            if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
                Trace.traceBegin(Trace.TRACE_TAG_VIEW, "notifyContentCaptureEvents");
            }
            MainContentCaptureSession mainSession = mAttachInfo.mContentCaptureManager
                    .getMainContentCaptureSession();
            for (int i = 0; i < mAttachInfo.mContentCaptureEvents.size(); i++) {
                int sessionId = mAttachInfo.mContentCaptureEvents.keyAt(i);
                mainSession.notifyViewTreeEvent(sessionId, /* started= */ true);
                ArrayList<Object> events = mAttachInfo.mContentCaptureEvents
                        .valueAt(i);
                for_each_event: for (int j = 0; j < events.size(); j++) {
                    Object event = events.get(j);
                    if (event instanceof AutofillId) {
                        mainSession.notifyViewDisappeared(sessionId, (AutofillId) event);
                    } else if (event instanceof View) {
                        View view = (View) event;
                        ContentCaptureSession session = view.getContentCaptureSession();
                        if (session == null) {
                            Log.w(mTag, "no content capture session on view: " + view);
                            continue for_each_event;
                        }
                        int actualId = session.getId();
                        if (actualId != sessionId) {
                            Log.w(mTag, "content capture session mismatch for view (" + view
                                    + "): was " + sessionId + " before, it's " + actualId + " now");
                            continue for_each_event;
                        }
                        ViewStructure structure = session.newViewStructure(view);
                        view.onProvideContentCaptureStructure(structure, /* flags= */ 0);
                        session.notifyViewAppeared(structure);
                    } else if (event instanceof Insets) {
                        mainSession.notifyViewInsetsChanged(sessionId, (Insets) event);
                    } else {
                        Log.w(mTag, "invalid content capture event: " + event);
                    }
                }
                mainSession.notifyViewTreeEvent(sessionId, /* started= */ false);

        final ContentCaptureManager manager = mAttachInfo.mContentCaptureManager;
        if (manager != null && mAttachInfo.mContentCaptureEvents != null) {
            final MainContentCaptureSession session = manager.getMainContentCaptureSession();
            session.notifyContentCaptureEvents(mAttachInfo.mContentCaptureEvents);
        }
        mAttachInfo.mContentCaptureEvents = null;
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
        }
    }

    private void notifyHolderSurfaceDestroyed() {
+20 −10
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package android.view.contentcapture;
import static android.view.contentcapture.ContentCaptureHelper.sDebug;
import static android.view.contentcapture.ContentCaptureHelper.sVerbose;
import static android.view.contentcapture.ContentCaptureHelper.toSet;
import static android.view.contentcapture.flags.Flags.runOnBackgroundThreadEnabled;

import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
@@ -52,6 +53,7 @@ import android.view.contentcapture.ContentCaptureSession.FlushReason;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.RingBuffer;
import com.android.internal.util.SyncResultReceiver;

@@ -495,10 +497,9 @@ public final class ContentCaptureManager {
    @GuardedBy("mLock")
    private int mFlags;

    // TODO(b/119220549): use UI Thread directly (as calls are one-way) or a shared thread / handler
    // held at the Application level
    @NonNull
    private final Handler mHandler;
    @Nullable
    @GuardedBy("mLock")
    private Handler mHandler;

    @GuardedBy("mLock")
    private MainContentCaptureSession mMainSession;
@@ -562,11 +563,6 @@ public final class ContentCaptureManager {

        if (sVerbose) Log.v(TAG, "Constructor for " + context.getPackageName());

        // TODO(b/119220549): we might not even need a handler, as the IPCs are oneway. But if we
        // do, then we should optimize it to run the tests after the Choreographer finishes the most
        // important steps of the frame.
        mHandler = Handler.createAsync(Looper.getMainLooper());

        mDataShareAdapterResourceManager = new LocalDataShareAdapterResourceManager();

        if (mOptions.contentProtectionOptions.enableReceiver
@@ -594,13 +590,27 @@ public final class ContentCaptureManager {
    public MainContentCaptureSession getMainContentCaptureSession() {
        synchronized (mLock) {
            if (mMainSession == null) {
                mMainSession = new MainContentCaptureSession(mContext, this, mHandler, mService);
                mMainSession = new MainContentCaptureSession(
                        mContext, this, prepareContentCaptureHandler(), mService);
                if (sVerbose) Log.v(TAG, "getMainContentCaptureSession(): created " + mMainSession);
            }
            return mMainSession;
        }
    }

    @NonNull
    @GuardedBy("mLock")
    private Handler prepareContentCaptureHandler() {
        if (mHandler == null) {
            if (runOnBackgroundThreadEnabled()) {
                mHandler = BackgroundThread.getHandler();
            } else {
                mHandler = Handler.createAsync(Looper.getMainLooper());
            }
        }
        return mHandler;
    }

    /** @hide */
    @UiThread
    public void onActivityCreated(@NonNull IBinder applicationToken,
+135 −39
Original line number Diff line number Diff line
@@ -34,7 +34,6 @@ import static android.view.contentcapture.ContentCaptureManager.RESULT_CODE_FALS

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UiThread;
import android.content.ComponentName;
import android.content.pm.ParceledListSlice;
import android.graphics.Insets;
@@ -50,7 +49,10 @@ import android.text.Spannable;
import android.text.TextUtils;
import android.util.LocalLog;
import android.util.Log;
import android.util.SparseArray;
import android.util.TimeUtils;
import android.view.View;
import android.view.ViewStructure;
import android.view.autofill.AutofillId;
import android.view.contentcapture.ViewNode.ViewStructureImpl;
import android.view.contentprotection.ContentProtectionEventProcessor;
@@ -207,7 +209,8 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
            } else {
                binder = null;
            }
            mainSession.mHandler.post(() -> mainSession.onSessionStarted(resultCode, binder));
            mainSession.mHandler.post(() ->
                    mainSession.onSessionStarted(resultCode, binder));
        }
    }

@@ -244,9 +247,14 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
    /**
     * Starts this session.
     */
    @UiThread
    void start(@NonNull IBinder token, @NonNull IBinder shareableActivityToken,
            @NonNull ComponentName component, int flags) {
        runOnContentCaptureThread(() -> startImpl(token, shareableActivityToken, component, flags));
    }

    private void startImpl(@NonNull IBinder token, @NonNull IBinder shareableActivityToken,
               @NonNull ComponentName component, int flags) {
        checkOnContentCaptureThread();
        if (!isContentCaptureEnabled()) return;

        if (sVerbose) {
@@ -280,17 +288,15 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
            Log.w(TAG, "Error starting session for " + component.flattenToShortString() + ": " + e);
        }
    }

    @Override
    void onDestroy() {
        mHandler.removeMessages(MSG_FLUSH);
        mHandler.post(() -> {
        clearAndRunOnContentCaptureThread(() -> {
            try {
                flush(FLUSH_REASON_SESSION_FINISHED);
            } finally {
                destroySession();
            }
        });
        }, MSG_FLUSH);
    }

    /**
@@ -302,8 +308,8 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
     * @hide
     */
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
    @UiThread
    public void onSessionStarted(int resultCode, @Nullable IBinder binder) {
        checkOnContentCaptureThread();
        if (binder != null) {
            mDirectServiceInterface = IContentCaptureDirectManager.Stub.asInterface(binder);
            mDirectServiceVulture = () -> {
@@ -347,13 +353,12 @@ public final class MainContentCaptureSession extends ContentCaptureSession {

    /** @hide */
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
    @UiThread
    public void sendEvent(@NonNull ContentCaptureEvent event) {
        sendEvent(event, /* forceFlush= */ false);
    }

    @UiThread
    private void sendEvent(@NonNull ContentCaptureEvent event, boolean forceFlush) {
        checkOnContentCaptureThread();
        final int eventType = event.getType();
        if (sVerbose) Log.v(TAG, "handleSendEvent(" + getDebugState() + "): " + event);
        if (!hasStarted() && eventType != ContentCaptureEvent.TYPE_SESSION_STARTED
@@ -396,15 +401,15 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
        }
    }

    @UiThread
    private void sendContentProtectionEvent(@NonNull ContentCaptureEvent event) {
        checkOnContentCaptureThread();
        if (mContentProtectionEventProcessor != null) {
            mContentProtectionEventProcessor.processEvent(event);
        }
    }

    @UiThread
    private void sendContentCaptureEvent(@NonNull ContentCaptureEvent event, boolean forceFlush) {
        checkOnContentCaptureThread();
        final int eventType = event.getType();
        final int maxBufferSize = mManager.mOptions.maxBufferSize;
        if (mEvents == null) {
@@ -538,13 +543,13 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
        flush(flushReason);
    }

    @UiThread
    private boolean hasStarted() {
        checkOnContentCaptureThread();
        return mState != UNKNOWN_STATE;
    }

    @UiThread
    private void scheduleFlush(@FlushReason int reason, boolean checkExisting) {
        checkOnContentCaptureThread();
        if (sVerbose) {
            Log.v(TAG, "handleScheduleFlush(" + getDebugState(reason)
                    + ", checkExisting=" + checkExisting);
@@ -588,8 +593,8 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
        mHandler.postDelayed(() -> flushIfNeeded(reason), MSG_FLUSH, flushFrequencyMs);
    }

    @UiThread
    private void flushIfNeeded(@FlushReason int reason) {
        checkOnContentCaptureThread();
        if (mEvents == null || mEvents.isEmpty()) {
            if (sVerbose) Log.v(TAG, "Nothing to flush");
            return;
@@ -600,8 +605,12 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
    /** @hide */
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
    @Override
    @UiThread
    public void flush(@FlushReason int reason) {
        runOnContentCaptureThread(() -> flushImpl(reason));
    }

    private void flushImpl(@FlushReason int reason) {
        checkOnContentCaptureThread();
        if (mEvents == null || mEvents.size() == 0) {
            if (sVerbose) {
                Log.v(TAG, "Don't flush for empty event buffer.");
@@ -669,8 +678,8 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
     * Resets the buffer and return a {@link ParceledListSlice} with the previous events.
     */
    @NonNull
    @UiThread
    private ParceledListSlice<ContentCaptureEvent> clearEvents() {
        checkOnContentCaptureThread();
        // NOTE: we must save a reference to the current mEvents and then set it to to null,
        // otherwise clearing it would clear it in the receiving side if the service is also local.
        if (mEvents == null) {
@@ -684,8 +693,8 @@ public final class MainContentCaptureSession extends ContentCaptureSession {

    /** hide */
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
    @UiThread
    public void destroySession() {
        checkOnContentCaptureThread();
        if (sDebug) {
            Log.d(TAG, "Destroying session (ctx=" + mContext + ", id=" + mId + ") with "
                    + (mEvents == null ? 0 : mEvents.size()) + " event(s) for "
@@ -710,8 +719,8 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
    // clearings out.
    /** @hide */
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
    @UiThread
    public void resetSession(int newState) {
        checkOnContentCaptureThread();
        if (sVerbose) {
            Log.v(TAG, "handleResetSession(" + getActivityName() + "): from "
                    + getStateAsString(mState) + " to " + getStateAsString(newState));
@@ -794,24 +803,26 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
    // change should also get get rid of the "internalNotifyXXXX" methods above
    void notifyChildSessionStarted(int parentSessionId, int childSessionId,
            @NonNull ContentCaptureContext clientContext) {
        mHandler.post(() -> sendEvent(new ContentCaptureEvent(childSessionId, TYPE_SESSION_STARTED)
        runOnContentCaptureThread(
                () -> sendEvent(new ContentCaptureEvent(childSessionId, TYPE_SESSION_STARTED)
                .setParentSessionId(parentSessionId).setClientContext(clientContext),
                FORCE_FLUSH));
    }

    void notifyChildSessionFinished(int parentSessionId, int childSessionId) {
        mHandler.post(() -> sendEvent(new ContentCaptureEvent(childSessionId, TYPE_SESSION_FINISHED)
        runOnContentCaptureThread(
                () -> sendEvent(new ContentCaptureEvent(childSessionId, TYPE_SESSION_FINISHED)
                .setParentSessionId(parentSessionId), FORCE_FLUSH));
    }

    void notifyViewAppeared(int sessionId, @NonNull ViewStructureImpl node) {
        mHandler.post(() -> sendEvent(new ContentCaptureEvent(sessionId, TYPE_VIEW_APPEARED)
        runOnContentCaptureThread(() ->
                sendEvent(new ContentCaptureEvent(sessionId, TYPE_VIEW_APPEARED)
                .setViewNode(node.mNode)));
    }

    /** Public because is also used by ViewRootImpl */
    public void notifyViewDisappeared(int sessionId, @NonNull AutofillId id) {
        mHandler.post(() -> sendEvent(
    void notifyViewDisappeared(int sessionId, @NonNull AutofillId id) {
        runOnContentCaptureThread(() -> sendEvent(
                new ContentCaptureEvent(sessionId, TYPE_VIEW_DISAPPEARED).setAutofillId(id)));
    }

@@ -836,52 +847,102 @@ public final class MainContentCaptureSession extends ContentCaptureSession {

        final int startIndex = Selection.getSelectionStart(text);
        final int endIndex = Selection.getSelectionEnd(text);
        mHandler.post(() -> sendEvent(
        runOnContentCaptureThread(() -> sendEvent(
                new ContentCaptureEvent(sessionId, TYPE_VIEW_TEXT_CHANGED)
                        .setAutofillId(id).setText(eventText)
                        .setComposingIndex(composingStart, composingEnd)
                        .setSelectionIndex(startIndex, endIndex)));
    }

    /** Public because is also used by ViewRootImpl */
    public void notifyViewInsetsChanged(int sessionId, @NonNull Insets viewInsets) {
        mHandler.post(() -> sendEvent(new ContentCaptureEvent(sessionId, TYPE_VIEW_INSETS_CHANGED)
    void notifyViewInsetsChanged(int sessionId, @NonNull Insets viewInsets) {
        runOnContentCaptureThread(() ->
                sendEvent(new ContentCaptureEvent(sessionId, TYPE_VIEW_INSETS_CHANGED)
                .setInsets(viewInsets)));
    }

    /** Public because is also used by ViewRootImpl */
    public void notifyViewTreeEvent(int sessionId, boolean started) {
    void notifyViewTreeEvent(int sessionId, boolean started) {
        final int type = started ? TYPE_VIEW_TREE_APPEARING : TYPE_VIEW_TREE_APPEARED;
        final boolean disableFlush = mManager.getFlushViewTreeAppearingEventDisabled();

        mHandler.post(() -> sendEvent(
        runOnContentCaptureThread(() -> sendEvent(
                new ContentCaptureEvent(sessionId, type),
                disableFlush ? !started : FORCE_FLUSH));
    }

    void notifySessionResumed(int sessionId) {
        mHandler.post(() -> sendEvent(
        runOnContentCaptureThread(() -> sendEvent(
                new ContentCaptureEvent(sessionId, TYPE_SESSION_RESUMED), FORCE_FLUSH));
    }

    void notifySessionPaused(int sessionId) {
        mHandler.post(() -> sendEvent(
        runOnContentCaptureThread(() -> sendEvent(
                new ContentCaptureEvent(sessionId, TYPE_SESSION_PAUSED), FORCE_FLUSH));
    }

    void notifyContextUpdated(int sessionId, @Nullable ContentCaptureContext context) {
        mHandler.post(() -> sendEvent(new ContentCaptureEvent(sessionId, TYPE_CONTEXT_UPDATED)
        runOnContentCaptureThread(() ->
                sendEvent(new ContentCaptureEvent(sessionId, TYPE_CONTEXT_UPDATED)
                .setClientContext(context), FORCE_FLUSH));
    }

    /** public because is also used by ViewRootImpl */
    public void notifyWindowBoundsChanged(int sessionId, @NonNull Rect bounds) {
        mHandler.post(() -> sendEvent(
        runOnContentCaptureThread(() -> sendEvent(
                new ContentCaptureEvent(sessionId, TYPE_WINDOW_BOUNDS_CHANGED)
                .setBounds(bounds)
        ));
    }

    /** public because is also used by ViewRootImpl */
    public void notifyContentCaptureEvents(
            @NonNull SparseArray<ArrayList<Object>> contentCaptureEvents) {
        runOnContentCaptureThread(() -> notifyContentCaptureEventsImpl(contentCaptureEvents));
    }

    private void notifyContentCaptureEventsImpl(
            @NonNull SparseArray<ArrayList<Object>> contentCaptureEvents) {
        checkOnContentCaptureThread();
        try {
            if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
                Trace.traceBegin(Trace.TRACE_TAG_VIEW, "notifyContentCaptureEvents");
            }
            for (int i = 0; i < contentCaptureEvents.size(); i++) {
                int sessionId = contentCaptureEvents.keyAt(i);
                notifyViewTreeEvent(sessionId, /* started= */ true);
                ArrayList<Object> events = contentCaptureEvents.valueAt(i);
                for_each_event: for (int j = 0; j < events.size(); j++) {
                    Object event = events.get(j);
                    if (event instanceof AutofillId) {
                        notifyViewDisappeared(sessionId, (AutofillId) event);
                    } else if (event instanceof View) {
                        View view = (View) event;
                        ContentCaptureSession session = view.getContentCaptureSession();
                        if (session == null) {
                            Log.w(TAG, "no content capture session on view: " + view);
                            continue for_each_event;
                        }
                        int actualId = session.getId();
                        if (actualId != sessionId) {
                            Log.w(TAG, "content capture session mismatch for view (" + view
                                    + "): was " + sessionId + " before, it's " + actualId + " now");
                            continue for_each_event;
                        }
                        ViewStructure structure = session.newViewStructure(view);
                        view.onProvideContentCaptureStructure(structure, /* flags= */ 0);
                        session.notifyViewAppeared(structure);
                    } else if (event instanceof Insets) {
                        notifyViewInsetsChanged(sessionId, (Insets) event);
                    } else {
                        Log.w(TAG, "invalid content capture event: " + event);
                    }
                }
                notifyViewTreeEvent(sessionId, /* started= */ false);
            }
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
        }
    }

    @Override
    void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
        super.dump(prefix, pw);
@@ -960,17 +1021,14 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
        return getDebugState() + ", reason=" + getFlushReasonAsString(reason);
    }

    @UiThread
    private boolean isContentProtectionReceiverEnabled() {
        return mManager.mOptions.contentProtectionOptions.enableReceiver;
    }

    @UiThread
    private boolean isContentCaptureReceiverEnabled() {
        return mManager.mOptions.enableReceiver;
    }

    @UiThread
    private boolean isContentProtectionEnabled() {
        // Should not be possible for mComponentName to be null here but check anyway
        // Should not be possible for groups to be empty if receiver is enabled but check anyway
@@ -980,4 +1038,42 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
                && (!mManager.mOptions.contentProtectionOptions.requiredGroups.isEmpty()
                        || !mManager.mOptions.contentProtectionOptions.optionalGroups.isEmpty());
    }

    /**
     * Checks that the current work is running on the assigned thread from {@code mHandler}.
     *
     * <p>It is not guaranteed that the callers always invoke function from a single thread.
     * Therefore, accessing internal properties in {@link MainContentCaptureSession} should
     * always delegate to the assigned thread from {@code mHandler} for synchronization.</p>
     */
    private void checkOnContentCaptureThread() {
        // TODO(b/309411951): Add metrics to track the issue instead.
        final boolean onContentCaptureThread = mHandler.getLooper().isCurrentThread();
        if (!onContentCaptureThread) {
            Log.e(TAG, "MainContentCaptureSession running on " + Thread.currentThread());
        }
    }

    /**
     * Ensures that {@code r} will be running on the assigned thread.
     *
     * <p>This is to prevent unnecessary delegation to Handler that results in fragmented runnable.
     * </p>
     */
    private void runOnContentCaptureThread(@NonNull Runnable r) {
        if (!mHandler.getLooper().isCurrentThread()) {
            mHandler.post(r);
        } else {
            r.run();
        }
    }

    private void clearAndRunOnContentCaptureThread(@NonNull Runnable r, int what) {
        if (!mHandler.getLooper().isCurrentThread()) {
            mHandler.removeMessages(what);
            mHandler.post(r);
        } else {
            r.run();
        }
    }
}
+0 −9
Original line number Diff line number Diff line
@@ -18,7 +18,6 @@ package android.view.contentprotection;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UiThread;
import android.content.ContentCaptureOptions;
import android.content.pm.ParceledListSlice;
import android.os.Handler;
@@ -102,7 +101,6 @@ public class ContentProtectionEventProcessor {
    }

    /** Main entry point for {@link ContentCaptureEvent} processing. */
    @UiThread
    public void processEvent(@NonNull ContentCaptureEvent event) {
        if (EVENT_TYPES_TO_STORE.contains(event.getType())) {
            storeEvent(event);
@@ -112,7 +110,6 @@ public class ContentProtectionEventProcessor {
        }
    }

    @UiThread
    private void storeEvent(@NonNull ContentCaptureEvent event) {
        // Ensure receiver gets the package name which might not be set
        ViewNode viewNode = (event.getViewNode() != null) ? event.getViewNode() : new ViewNode();
@@ -121,7 +118,6 @@ public class ContentProtectionEventProcessor {
        mEventBuffer.append(event);
    }

    @UiThread
    private void processViewAppearedEvent(@NonNull ContentCaptureEvent event) {
        ViewNode viewNode = event.getViewNode();
        String eventText = ContentProtectionUtils.getEventTextLower(event);
@@ -154,7 +150,6 @@ public class ContentProtectionEventProcessor {
        }
    }

    @UiThread
    private void loginDetected() {
        if (mLastFlushTime == null
                || Instant.now().isAfter(mLastFlushTime.plus(MIN_DURATION_BETWEEN_FLUSHING))) {
@@ -163,13 +158,11 @@ public class ContentProtectionEventProcessor {
        resetLoginFlags();
    }

    @UiThread
    private void resetLoginFlags() {
        mGroupsAll.forEach(group -> group.mFound = false);
        mAnyGroupFound = false;
    }

    @UiThread
    private void maybeResetLoginFlags() {
        if (mAnyGroupFound) {
            if (mResetLoginRemainingEventsToProcess <= 0) {
@@ -183,7 +176,6 @@ public class ContentProtectionEventProcessor {
        }
    }

    @UiThread
    private void flush() {
        mLastFlushTime = Instant.now();

@@ -192,7 +184,6 @@ public class ContentProtectionEventProcessor {
        mHandler.post(() -> handlerOnLoginDetected(events));
    }

    @UiThread
    @NonNull
    private ParceledListSlice<ContentCaptureEvent> clearEvents() {
        List<ContentCaptureEvent> events = Arrays.asList(mEventBuffer.toArray());
+143 −4

File changed.

Preview size limit exceeded, changes collapsed.