Merge "Fix for ANRs due to InputMonitor" into tm-qpr-dev am: 53827bfa31

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/20458174

Change-Id: Ifab158832e9ce13b323eb1c29044911bbd4b7cc0
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Matt Sziklay
2022-12-05 17:01:38 +00:00
committed by Automerger Merge Worker
2 changed files with 90 additions and 17 deletions

View File

@@ -75,10 +75,10 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
private final SyncTransactionQueue mSyncQueue; private final SyncTransactionQueue mSyncQueue;
private FreeformTaskTransitionStarter mTransitionStarter; private FreeformTaskTransitionStarter mTransitionStarter;
private DesktopModeController mDesktopModeController; private DesktopModeController mDesktopModeController;
private EventReceiver mEventReceiver;
private InputMonitor mInputMonitor;
private boolean mTransitionDragActive; private boolean mTransitionDragActive;
private SparseArray<EventReceiver> mEventReceiversByDisplay = new SparseArray<>();
private final SparseArray<CaptionWindowDecoration> mWindowDecorByTaskId = new SparseArray<>(); private final SparseArray<CaptionWindowDecoration> mWindowDecorByTaskId = new SparseArray<>();
private final DragStartListenerImpl mDragStartListener = new DragStartListenerImpl(); private final DragStartListenerImpl mDragStartListener = new DragStartListenerImpl();
private EventReceiverFactory mEventReceiverFactory = new EventReceiverFactory(); private EventReceiverFactory mEventReceiverFactory = new EventReceiverFactory();
@@ -150,8 +150,15 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
@Override @Override
public void onTaskInfoChanged(RunningTaskInfo taskInfo) { public void onTaskInfoChanged(RunningTaskInfo taskInfo) {
final CaptionWindowDecoration decoration = mWindowDecorByTaskId.get(taskInfo.taskId); final CaptionWindowDecoration decoration = mWindowDecorByTaskId.get(taskInfo.taskId);
if (decoration == null) return; if (decoration == null) return;
int oldDisplayId = decoration.mDisplay.getDisplayId();
if (taskInfo.displayId != oldDisplayId) {
removeTaskFromEventReceiver(oldDisplayId);
incrementEventReceiverTasks(taskInfo.displayId);
}
decoration.relayout(taskInfo); decoration.relayout(taskInfo);
} }
@@ -195,6 +202,11 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
if (decoration == null) return; if (decoration == null) return;
decoration.close(); decoration.close();
int displayId = taskInfo.displayId;
if (mEventReceiversByDisplay.contains(displayId)) {
EventReceiver eventReceiver = mEventReceiversByDisplay.get(displayId);
removeTaskFromEventReceiver(displayId);
}
} }
private class CaptionTouchEventListener implements private class CaptionTouchEventListener implements
@@ -329,8 +341,12 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
// InputEventReceiver to listen for touch input outside of caption bounds // InputEventReceiver to listen for touch input outside of caption bounds
class EventReceiver extends InputEventReceiver { 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); super(channel, looper);
mInputMonitor = inputMonitor;
mTasksOnDisplay = 1;
} }
@Override @Override
@@ -338,15 +354,62 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
boolean handled = false; boolean handled = false;
if (event instanceof MotionEvent) { if (event instanceof MotionEvent) {
handled = true; handled = true;
CaptionWindowDecorViewModel.this.handleReceivedMotionEvent((MotionEvent) event); CaptionWindowDecorViewModel.this
.handleReceivedMotionEvent((MotionEvent) event, mInputMonitor);
} }
finishInputEvent(event, handled); 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 { class EventReceiverFactory {
EventReceiver create(InputChannel channel, Looper looper) { EventReceiver create(InputMonitor inputMonitor, InputChannel channel, Looper looper) {
return new EventReceiver(channel, 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} * @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)) { if (!DesktopModeStatus.isActive(mContext)) {
handleCaptionThroughStatusBar(ev); handleCaptionThroughStatusBar(ev);
} }
handleEventOutsideFocusedCaption(ev); handleEventOutsideFocusedCaption(ev);
// Prevent status bar from reacting to a caption drag. // Prevent status bar from reacting to a caption drag.
if (mTransitionDragActive && !DesktopModeStatus.isActive(mContext)) { 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. * Perform caption actions if not able to through normal means.
* Turn on desktop mode if handle is dragged below status bar. * Turn on desktop mode if handle is dragged below status bar.
@@ -434,6 +498,22 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
return focusedDecor; 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) { private boolean shouldShowWindowDecor(RunningTaskInfo taskInfo) {
if (taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) return true; if (taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) return true;
return DesktopModeStatus.IS_SUPPORTED return DesktopModeStatus.IS_SUPPORTED
@@ -472,14 +552,7 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
windowDecoration.setCaptionListeners(touchEventListener, touchEventListener); windowDecoration.setCaptionListeners(touchEventListener, touchEventListener);
windowDecoration.setDragResizeCallback(taskPositioner); windowDecoration.setDragResizeCallback(taskPositioner);
windowDecoration.relayout(taskInfo, startT, finishT); windowDecoration.relayout(taskInfo, startT, finishT);
if (mInputMonitor == null) { incrementEventReceiverTasks(taskInfo.displayId);
InputManager inputManager = mInputManagerSupplier.get();
mInputMonitor =
inputManager.monitorGestureInput("caption-touch", mContext.getDisplayId());
mEventReceiver =
mEventReceiverFactory.create(
mInputMonitor.getInputChannel(), Looper.myLooper());
}
} }
private class DragStartListenerImpl implements TaskPositioner.DragStartListener { private class DragStartListenerImpl implements TaskPositioner.DragStartListener {

View File

@@ -111,7 +111,7 @@ public class CaptionWindowDecorViewModelTests extends ShellTestCase {
.create(any(), any(), any(), any(), any(), any(), any(), any()); .create(any(), any(), any(), any(), any(), any(), any(), any());
when(mInputManager.monitorGestureInput(any(), anyInt())).thenReturn(mInputMonitor); 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); when(mInputMonitor.getInputChannel()).thenReturn(mInputChannel);
} }