Skip to content

Commit 1f4786b

Browse files
committed
Improve Launcher drag performance.
Launcher swiping looks choppy. It's because we deliver the motion events of the drags asynchronously, and sometimes we may get an event to redraw before the motion event is posted, so we end up drawing again without updating to the latest motion information. This fix makes input event processing more proactive. Every time we run ViewRootImpl.performTraversals() (which is what happens whenever we need to layout, measure, and/or draw), we first process all pending input events, ensuring that we are completely up-to-date with posted events prior to drawing, so that the drawing we do is synchronous with the events we've received. This eliminates the choppiness and means that we can now get the full refresh rate on the screen with drag events. The fix was done for Launcher, but it is pervasive in the system, so this may fix other laggy drag behavior as well. Change-Id: I8dbed6acadc2662f317f736e769f536f555701aa
1 parent 914972b commit 1f4786b

File tree

1 file changed

+99
-6
lines changed

1 file changed

+99
-6
lines changed

core/java/android/view/ViewRootImpl.java

Lines changed: 99 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ public final class ViewRootImpl extends Handler implements ViewParent,
218218
boolean mNewSurfaceNeeded;
219219
boolean mHasHadWindowFocus;
220220
boolean mLastWasImTarget;
221+
InputEventMessage mPendingInputEvents = null;
221222

222223
boolean mWindowAttributesChanged = false;
223224
int mWindowAttributesChangesFlag = 0;
@@ -832,10 +833,24 @@ public void requestTransitionStart(LayoutTransition transition) {
832833
}
833834
}
834835

836+
private void processInputEvents(boolean outOfOrder) {
837+
while (mPendingInputEvents != null) {
838+
handleMessage(mPendingInputEvents.mMessage);
839+
InputEventMessage tmpMessage = mPendingInputEvents;
840+
mPendingInputEvents = mPendingInputEvents.mNext;
841+
tmpMessage.recycle();
842+
if (outOfOrder) {
843+
removeMessages(PROCESS_INPUT_EVENTS);
844+
}
845+
}
846+
}
847+
835848
private void performTraversals() {
836849
// cache mView since it is used so much below...
837850
final View host = mView;
838851

852+
processInputEvents(true);
853+
839854
if (DBG) {
840855
System.out.println("======================================");
841856
System.out.println("performTraversals");
@@ -2336,6 +2351,7 @@ private static void forceLayout(View view) {
23362351
public final static int DO_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID = 1021;
23372352
public final static int DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID = 1022;
23382353
public final static int DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_TEXT = 1023;
2354+
public final static int PROCESS_INPUT_EVENTS = 1024;
23392355

23402356
@Override
23412357
public String getMessageName(Message message) {
@@ -2388,7 +2404,9 @@ public String getMessageName(Message message) {
23882404
return "DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID";
23892405
case DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_TEXT:
23902406
return "DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_TEXT";
2391-
2407+
case PROCESS_INPUT_EVENTS:
2408+
return "PROCESS_INPUT_EVENTS";
2409+
23922410
}
23932411
return super.getMessageName(message);
23942412
}
@@ -2447,6 +2465,9 @@ public void handleMessage(Message msg) {
24472465
case DISPATCH_GENERIC_MOTION:
24482466
deliverGenericMotionEvent((MotionEvent) msg.obj, msg.arg1 != 0);
24492467
break;
2468+
case PROCESS_INPUT_EVENTS:
2469+
processInputEvents(false);
2470+
break;
24502471
case DISPATCH_APP_VISIBILITY:
24512472
handleAppVisibility(msg.arg1 != 0);
24522473
break;
@@ -3744,7 +3765,7 @@ public void dispatchResized(int w, int h, Rect coveredInsets,
37443765
msg.obj = ri;
37453766
sendMessage(msg);
37463767
}
3747-
3768+
37483769
private long mInputEventReceiveTimeNanos;
37493770
private long mInputEventDeliverTimeNanos;
37503771
private long mInputEventDeliverPostImeTimeNanos;
@@ -3762,6 +3783,78 @@ public void handleMotion(MotionEvent event, InputQueue.FinishedCallback finished
37623783
}
37633784
};
37643785

3786+
/**
3787+
* Utility class used to queue up input events which are then handled during
3788+
* performTraversals(). Doing it this way allows us to ensure that we are up to date with
3789+
* all input events just prior to drawing, instead of placing those events on the regular
3790+
* handler queue, potentially behind a drawing event.
3791+
*/
3792+
static class InputEventMessage {
3793+
Message mMessage;
3794+
InputEventMessage mNext;
3795+
3796+
private static final Object sPoolSync = new Object();
3797+
private static InputEventMessage sPool;
3798+
private static int sPoolSize = 0;
3799+
3800+
private static final int MAX_POOL_SIZE = 10;
3801+
3802+
private InputEventMessage(Message m) {
3803+
mMessage = m;
3804+
mNext = null;
3805+
}
3806+
3807+
/**
3808+
* Return a new Message instance from the global pool. Allows us to
3809+
* avoid allocating new objects in many cases.
3810+
*/
3811+
public static InputEventMessage obtain(Message msg) {
3812+
synchronized (sPoolSync) {
3813+
if (sPool != null) {
3814+
InputEventMessage m = sPool;
3815+
sPool = m.mNext;
3816+
m.mNext = null;
3817+
sPoolSize--;
3818+
m.mMessage = msg;
3819+
return m;
3820+
}
3821+
}
3822+
return new InputEventMessage(msg);
3823+
}
3824+
3825+
/**
3826+
* Return the message to the pool.
3827+
*/
3828+
public void recycle() {
3829+
mMessage.recycle();
3830+
synchronized (sPoolSync) {
3831+
if (sPoolSize < MAX_POOL_SIZE) {
3832+
mNext = sPool;
3833+
sPool = this;
3834+
sPoolSize++;
3835+
}
3836+
}
3837+
3838+
}
3839+
}
3840+
3841+
/**
3842+
* Place the input event message at the end of the current pending list
3843+
*/
3844+
private void enqueueInputEvent(Message msg, long when) {
3845+
InputEventMessage inputMessage = InputEventMessage.obtain(msg);
3846+
if (mPendingInputEvents == null) {
3847+
mPendingInputEvents = inputMessage;
3848+
} else {
3849+
InputEventMessage currMessage = mPendingInputEvents;
3850+
while (currMessage.mNext != null) {
3851+
currMessage = currMessage.mNext;
3852+
}
3853+
currMessage.mNext = inputMessage;
3854+
}
3855+
sendEmptyMessageAtTime(PROCESS_INPUT_EVENTS, when);
3856+
}
3857+
37653858
public void dispatchKey(KeyEvent event) {
37663859
dispatchKey(event, false);
37673860
}
@@ -3786,7 +3879,7 @@ private void dispatchKey(KeyEvent event, boolean sendDone) {
37863879
if (LOCAL_LOGV) Log.v(
37873880
TAG, "sending key " + event + " to " + mView);
37883881

3789-
sendMessageAtTime(msg, event.getEventTime());
3882+
enqueueInputEvent(msg, event.getEventTime());
37903883
}
37913884

37923885
private void dispatchMotion(MotionEvent event, boolean sendDone) {
@@ -3804,21 +3897,21 @@ private void dispatchPointer(MotionEvent event, boolean sendDone) {
38043897
Message msg = obtainMessage(DISPATCH_POINTER);
38053898
msg.obj = event;
38063899
msg.arg1 = sendDone ? 1 : 0;
3807-
sendMessageAtTime(msg, event.getEventTime());
3900+
enqueueInputEvent(msg, event.getEventTime());
38083901
}
38093902

38103903
private void dispatchTrackball(MotionEvent event, boolean sendDone) {
38113904
Message msg = obtainMessage(DISPATCH_TRACKBALL);
38123905
msg.obj = event;
38133906
msg.arg1 = sendDone ? 1 : 0;
3814-
sendMessageAtTime(msg, event.getEventTime());
3907+
enqueueInputEvent(msg, event.getEventTime());
38153908
}
38163909

38173910
private void dispatchGenericMotion(MotionEvent event, boolean sendDone) {
38183911
Message msg = obtainMessage(DISPATCH_GENERIC_MOTION);
38193912
msg.obj = event;
38203913
msg.arg1 = sendDone ? 1 : 0;
3821-
sendMessageAtTime(msg, event.getEventTime());
3914+
enqueueInputEvent(msg, event.getEventTime());
38223915
}
38233916

38243917
public void dispatchAppVisibility(boolean visible) {

0 commit comments

Comments
 (0)