From 4b08ecf85400b8055018401e7f5492af2b1bf7c0 Mon Sep 17 00:00:00 2001 From: Garfield Tan Date: Mon, 18 Jul 2022 12:05:42 -0700 Subject: [PATCH] Change the strategy of handling batched input events This CL changed DragResizeInputListener to use the same strategy of handling batched input events as ViewRootImpl. This effectively throttles the resize requests by the refresh rate of the primary display. This CL also stops relying on WM core responding to WM shell on each size request, which may not be always true depending on the WM core state, e.g. when WM core detects the requested bounds violate the smallest dimension requirements. Bug: 239238690 Test: Fluid resizes work with both fingers and mice. Change-Id: Iad95ba7a5163138c52d902c94e1a3e4dc3180b6b --- .../windowdecor/DragResizeInputListener.java | 55 +++++++++++-------- 1 file changed, 31 insertions(+), 24 deletions(-) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java index c6bbb027c8e65..9869d2e53979b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java @@ -27,8 +27,8 @@ import android.hardware.input.InputManager; import android.os.Binder; import android.os.Handler; import android.os.IBinder; -import android.os.Looper; import android.os.RemoteException; +import android.view.Choreographer; import android.view.IWindowSession; import android.view.InputChannel; import android.view.InputEvent; @@ -97,7 +97,7 @@ class DragResizeInputListener implements AutoCloseable { e.rethrowFromSystemServer(); } - mInputEventReceiver = new TaskResizeInputEventReceiver(mInputChannel, mHandler.getLooper()); + mInputEventReceiver = new TaskResizeInputEventReceiver(mInputChannel, mHandler); mCallback = callback; } @@ -154,10 +154,6 @@ class DragResizeInputListener implements AutoCloseable { } catch (RemoteException e) { e.rethrowFromSystemServer(); } - - // This marks all relevant components have handled the previous resize event and can take - // the next one now. - mInputEventReceiver.onHandledLastResizeEvent(); } @Override @@ -171,28 +167,42 @@ class DragResizeInputListener implements AutoCloseable { } private class TaskResizeInputEventReceiver extends InputEventReceiver { - private boolean mWaitingForLastResizeEventHandled; + private final Choreographer mChoreographer; + private final Runnable mConsumeBatchEventRunnable; + private boolean mConsumeBatchEventScheduled; - private TaskResizeInputEventReceiver(InputChannel inputChannel, Looper looper) { - super(inputChannel, looper); - } + private TaskResizeInputEventReceiver(InputChannel inputChannel, Handler handler) { + super(inputChannel, handler.getLooper()); - private void onHandledLastResizeEvent() { - mWaitingForLastResizeEventHandled = false; - consumeBatchedInputEvents(-1); + final Choreographer[] choreographer = new Choreographer[1]; + handler.runWithScissors( + () -> choreographer[0] = Choreographer.getInstance(), 0); + mChoreographer = choreographer[0]; + + mConsumeBatchEventRunnable = () -> { + mConsumeBatchEventScheduled = false; + if (consumeBatchedInputEvents(mChoreographer.getFrameTimeNanos())) { + // If we consumed a batch here, we want to go ahead and schedule the + // consumption of batched input events on the next frame. Otherwise, we would + // wait until we have more input events pending and might get starved by other + // things occurring in the process. + scheduleConsumeBatchEvent(); + } + }; } @Override public void onBatchedInputEventPending(int source) { - // InputEventReceiver keeps continuous move events in a batched event until explicitly - // consuming it or an incompatible event shows up (likely an up event in this case). We - // continue to keep move events in the next batched event until we receive a geometry - // update so that we don't put too much pressure on the framework with excessive number - // of input events if it can't handle them fast enough. It's more responsive to always - // resize the task to the latest received coordinates. - if (!mWaitingForLastResizeEventHandled) { - consumeBatchedInputEvents(-1); + scheduleConsumeBatchEvent(); + } + + private void scheduleConsumeBatchEvent() { + if (mConsumeBatchEventScheduled) { + return; } + mChoreographer.postCallback( + Choreographer.CALLBACK_INPUT, mConsumeBatchEventRunnable, null); + mConsumeBatchEventScheduled = true; } @Override @@ -211,14 +221,12 @@ class DragResizeInputListener implements AutoCloseable { mDragPointerId = e.getPointerId(0); mCallback.onDragResizeStart( calculateCtrlType(e.getX(0), e.getY(0)), e.getRawX(0), e.getRawY(0)); - mWaitingForLastResizeEventHandled = false; break; } case MotionEvent.ACTION_MOVE: { int dragPointerIndex = e.findPointerIndex(mDragPointerId); mCallback.onDragResizeMove( e.getRawX(dragPointerIndex), e.getRawY(dragPointerIndex)); - mWaitingForLastResizeEventHandled = true; break; } case MotionEvent.ACTION_UP: @@ -226,7 +234,6 @@ class DragResizeInputListener implements AutoCloseable { int dragPointerIndex = e.findPointerIndex(mDragPointerId); mCallback.onDragResizeEnd( e.getRawX(dragPointerIndex), e.getRawY(dragPointerIndex)); - mWaitingForLastResizeEventHandled = false; mDragPointerId = -1; break; }