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

Commit 53827bfa authored by Matt Sziklay's avatar Matt Sziklay Committed by Android (Google) Code Review
Browse files

Merge "Fix for ANRs due to InputMonitor" into tm-qpr-dev

parents 5db8d1ea 8c0f81ca
Loading
Loading
Loading
Loading
+89 −16
Original line number Diff line number Diff line
@@ -75,10 +75,10 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
    private final SyncTransactionQueue mSyncQueue;
    private FreeformTaskTransitionStarter mTransitionStarter;
    private DesktopModeController mDesktopModeController;
    private EventReceiver mEventReceiver;
    private InputMonitor mInputMonitor;
    private boolean mTransitionDragActive;

    private SparseArray<EventReceiver> mEventReceiversByDisplay = new SparseArray<>();

    private final SparseArray<CaptionWindowDecoration> mWindowDecorByTaskId = new SparseArray<>();
    private final DragStartListenerImpl mDragStartListener = new DragStartListenerImpl();
    private EventReceiverFactory mEventReceiverFactory = new EventReceiverFactory();
@@ -150,8 +150,15 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
    @Override
    public void onTaskInfoChanged(RunningTaskInfo taskInfo) {
        final CaptionWindowDecoration decoration = mWindowDecorByTaskId.get(taskInfo.taskId);

        if (decoration == null) return;

        int oldDisplayId = decoration.mDisplay.getDisplayId();
        if (taskInfo.displayId != oldDisplayId) {
            removeTaskFromEventReceiver(oldDisplayId);
            incrementEventReceiverTasks(taskInfo.displayId);
        }

        decoration.relayout(taskInfo);
    }

@@ -195,6 +202,11 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
        if (decoration == null) return;

        decoration.close();
        int displayId = taskInfo.displayId;
        if (mEventReceiversByDisplay.contains(displayId)) {
            EventReceiver eventReceiver = mEventReceiversByDisplay.get(displayId);
            removeTaskFromEventReceiver(displayId);
        }
    }

    private class CaptionTouchEventListener implements
@@ -329,8 +341,12 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel {

    // InputEventReceiver to listen for touch input outside of caption bounds
    class EventReceiver extends InputEventReceiver {
        EventReceiver(InputChannel channel, Looper looper) {
        private InputMonitor mInputMonitor;
        private int mTasksOnDisplay;
        EventReceiver(InputMonitor inputMonitor, InputChannel channel, Looper looper) {
            super(channel, looper);
            mInputMonitor = inputMonitor;
            mTasksOnDisplay = 1;
        }

        @Override
@@ -338,15 +354,62 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
            boolean handled = false;
            if (event instanceof MotionEvent) {
                handled = true;
                CaptionWindowDecorViewModel.this.handleReceivedMotionEvent((MotionEvent) event);
                CaptionWindowDecorViewModel.this
                        .handleReceivedMotionEvent((MotionEvent) event, mInputMonitor);
            }
            finishInputEvent(event, handled);
        }

        @Override
        public void dispose() {
            if (mInputMonitor != null) {
                mInputMonitor.dispose();
                mInputMonitor = null;
            }
            super.dispose();
        }

        private void incrementTaskNumber() {
            mTasksOnDisplay++;
        }

        private void decrementTaskNumber() {
            mTasksOnDisplay--;
        }

        private int getTasksOnDisplay() {
            return mTasksOnDisplay;
        }
    }

    /**
     * Check if an EventReceiver exists on a particular display.
     * If it does, increment its task count. Otherwise, create one for that display.
     * @param displayId the display to check against
     */
    private void incrementEventReceiverTasks(int displayId) {
        if (mEventReceiversByDisplay.contains(displayId)) {
            EventReceiver eventReceiver = mEventReceiversByDisplay.get(displayId);
            eventReceiver.incrementTaskNumber();
        } else {
            createInputChannel(displayId);
        }
    }

    // If all tasks on this display are gone, we don't need to monitor its input.
    private void removeTaskFromEventReceiver(int displayId) {
        if (!mEventReceiversByDisplay.contains(displayId)) return;
        EventReceiver eventReceiver = mEventReceiversByDisplay.get(displayId);
        if (eventReceiver == null) return;
        eventReceiver.decrementTaskNumber();
        if (eventReceiver.getTasksOnDisplay() == 0) {
            disposeInputChannel(displayId);
        }
    }

    class EventReceiverFactory {
        EventReceiver create(InputChannel channel, Looper looper) {
            return new EventReceiver(channel, looper);
        EventReceiver create(InputMonitor inputMonitor, InputChannel channel, Looper looper) {
            return new EventReceiver(inputMonitor, channel, looper);
        }
    }

@@ -355,14 +418,14 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
     *
     * @param ev the {@link MotionEvent} received by {@link EventReceiver}
     */
    private void handleReceivedMotionEvent(MotionEvent ev) {
    private void handleReceivedMotionEvent(MotionEvent ev, InputMonitor inputMonitor) {
        if (!DesktopModeStatus.isActive(mContext)) {
            handleCaptionThroughStatusBar(ev);
        }
        handleEventOutsideFocusedCaption(ev);
        // Prevent status bar from reacting to a caption drag.
        if (mTransitionDragActive && !DesktopModeStatus.isActive(mContext)) {
            mInputMonitor.pilferPointers();
            inputMonitor.pilferPointers();
        }
    }

@@ -381,6 +444,7 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
        }
    }


    /**
     * Perform caption actions if not able to through normal means.
     * Turn on desktop mode if handle is dragged below status bar.
@@ -434,6 +498,22 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
        return focusedDecor;
    }

    private void createInputChannel(int displayId) {
        InputManager inputManager = mInputManagerSupplier.get();
        InputMonitor inputMonitor =
                inputManager.monitorGestureInput("caption-touch", mContext.getDisplayId());
        EventReceiver eventReceiver = mEventReceiverFactory.create(
                inputMonitor, inputMonitor.getInputChannel(), Looper.myLooper());
        mEventReceiversByDisplay.put(displayId, eventReceiver);
    }

    private void disposeInputChannel(int displayId) {
        EventReceiver eventReceiver = mEventReceiversByDisplay.removeReturnOld(displayId);
        if (eventReceiver != null) {
            eventReceiver.dispose();
        }
    }

    private boolean shouldShowWindowDecor(RunningTaskInfo taskInfo) {
        if (taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) return true;
        return DesktopModeStatus.IS_SUPPORTED
@@ -472,14 +552,7 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
        windowDecoration.setCaptionListeners(touchEventListener, touchEventListener);
        windowDecoration.setDragResizeCallback(taskPositioner);
        windowDecoration.relayout(taskInfo, startT, finishT);
        if (mInputMonitor == null) {
            InputManager inputManager = mInputManagerSupplier.get();
            mInputMonitor =
                    inputManager.monitorGestureInput("caption-touch", mContext.getDisplayId());
            mEventReceiver =
                    mEventReceiverFactory.create(
                            mInputMonitor.getInputChannel(), Looper.myLooper());
        }
        incrementEventReceiverTasks(taskInfo.displayId);
    }

    private class DragStartListenerImpl implements TaskPositioner.DragStartListener {
+1 −1
Original line number Diff line number Diff line
@@ -111,7 +111,7 @@ public class CaptionWindowDecorViewModelTests extends ShellTestCase {
            .create(any(), any(), any(), any(), any(), any(), any(), any());

        when(mInputManager.monitorGestureInput(any(), anyInt())).thenReturn(mInputMonitor);
        when(mEventReceiverFactory.create(any(), any())).thenReturn(mEventReceiver);
        when(mEventReceiverFactory.create(any(), any(), any())).thenReturn(mEventReceiver);
        when(mInputMonitor.getInputChannel()).thenReturn(mInputChannel);
    }