Merge "Allow unbuffered MotionEvent dispatch for View (1/2)"
This commit is contained in:
committed by
Android (Google) Code Review
commit
4090e95ba6
@@ -53892,6 +53892,7 @@ package android.view {
|
||||
method public boolean requestRectangleOnScreen(android.graphics.Rect);
|
||||
method public boolean requestRectangleOnScreen(android.graphics.Rect, boolean);
|
||||
method public final void requestUnbufferedDispatch(android.view.MotionEvent);
|
||||
method public final void requestUnbufferedDispatch(int);
|
||||
method @NonNull public final <T extends android.view.View> T requireViewById(@IdRes int);
|
||||
method public void resetPivot();
|
||||
method public static int resolveSize(int, int);
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package android.view;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.RequiresPermission;
|
||||
import android.annotation.TestApi;
|
||||
import android.compat.annotation.UnsupportedAppUsage;
|
||||
@@ -28,6 +29,8 @@ import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.os.Vibrator;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -138,6 +141,19 @@ public final class InputDevice implements Parcelable {
|
||||
*/
|
||||
public static final int SOURCE_CLASS_JOYSTICK = 0x00000010;
|
||||
|
||||
/** @hide */
|
||||
@IntDef(flag = true, prefix = { "SOURCE_CLASS_" }, value = {
|
||||
SOURCE_CLASS_NONE,
|
||||
SOURCE_CLASS_BUTTON,
|
||||
SOURCE_CLASS_POINTER,
|
||||
SOURCE_CLASS_POINTER,
|
||||
SOURCE_CLASS_TRACKBALL,
|
||||
SOURCE_CLASS_POSITION,
|
||||
SOURCE_CLASS_JOYSTICK
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@interface InputSourceClass {}
|
||||
|
||||
/**
|
||||
* The input source is unknown.
|
||||
*/
|
||||
|
||||
@@ -110,6 +110,7 @@ import android.view.AccessibilityIterators.ParagraphTextSegmentIterator;
|
||||
import android.view.AccessibilityIterators.TextSegmentIterator;
|
||||
import android.view.AccessibilityIterators.WordTextSegmentIterator;
|
||||
import android.view.ContextMenu.ContextMenuInfo;
|
||||
import android.view.InputDevice.InputSourceClass;
|
||||
import android.view.Window.OnContentApplyWindowInsetsListener;
|
||||
import android.view.WindowInsets.Type;
|
||||
import android.view.WindowInsetsAnimation.Bounds;
|
||||
@@ -5204,6 +5205,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
@StyleRes
|
||||
private int mExplicitStyle;
|
||||
|
||||
/**
|
||||
* Specifies which input source classes should provide unbuffered input events to this view
|
||||
*
|
||||
* @see View#requestUnbufferedDispatch(int)
|
||||
*/
|
||||
@InputSourceClass
|
||||
int mUnbufferedInputSource = InputDevice.SOURCE_CLASS_NONE;
|
||||
|
||||
/**
|
||||
* Simple constructor to use when creating a view from code.
|
||||
*
|
||||
@@ -8013,6 +8022,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
mAttachInfo.mKeyDispatchState.reset(this);
|
||||
}
|
||||
|
||||
if (mParent != null) {
|
||||
mParent.onDescendantUnbufferedRequested();
|
||||
}
|
||||
|
||||
notifyEnterOrExitForAutoFillIfNeeded(gainFocus);
|
||||
}
|
||||
|
||||
@@ -15820,12 +15833,17 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
* system not batch {@link MotionEvent}s but instead deliver them as soon as they're
|
||||
* available. This method should only be called for touch events.
|
||||
*
|
||||
* <p class="note">This api is not intended for most applications. Buffered dispatch
|
||||
* <p class="note">This API is not intended for most applications. Buffered dispatch
|
||||
* provides many of benefits, and just requesting unbuffered dispatch on most MotionEvent
|
||||
* streams will not improve your input latency. Side effects include: increased latency,
|
||||
* jittery scrolls and inability to take advantage of system resampling. Talk to your input
|
||||
* professional to see if {@link #requestUnbufferedDispatch(MotionEvent)} is right for
|
||||
* you.</p>
|
||||
*
|
||||
* To receive unbuffered events for arbitrary input device source classes, use
|
||||
* {@link #requestUnbufferedDispatch(int)},
|
||||
*
|
||||
* @see View#requestUnbufferedDispatch(int)
|
||||
*/
|
||||
public final void requestUnbufferedDispatch(MotionEvent event) {
|
||||
final int action = event.getAction();
|
||||
@@ -15837,6 +15855,27 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
mAttachInfo.mUnbufferedDispatchRequested = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Request unbuffered dispatch of the given event source class to this view.
|
||||
* This is similar to {@link View#requestUnbufferedDispatch(MotionEvent)}, but does not
|
||||
* automatically terminate, and allows the specification of arbitrary input source classes.
|
||||
*
|
||||
* @param source The combined input source class to request unbuffered dispatch for. All
|
||||
* events coming from these source classes will not be buffered. Set to
|
||||
* {@link InputDevice#SOURCE_CLASS_NONE} in order to return to default behaviour.
|
||||
*
|
||||
* @see View#requestUnbufferedDispatch(MotionEvent)
|
||||
*/
|
||||
public final void requestUnbufferedDispatch(@InputSourceClass int source) {
|
||||
if (mUnbufferedInputSource == source) {
|
||||
return;
|
||||
}
|
||||
mUnbufferedInputSource = source;
|
||||
if (mParent != null) {
|
||||
mParent.onDescendantUnbufferedRequested();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasSize() {
|
||||
return (mBottom > mTop) && (mRight > mLeft);
|
||||
}
|
||||
|
||||
@@ -9029,4 +9029,30 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
|
||||
getChildAt(i).encode(encoder);
|
||||
}
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@Override
|
||||
public final void onDescendantUnbufferedRequested() {
|
||||
// First look at the focused child for focused events
|
||||
int focusedChildNonPointerSource = InputDevice.SOURCE_CLASS_NONE;
|
||||
if (mFocused != null) {
|
||||
focusedChildNonPointerSource = mFocused.mUnbufferedInputSource
|
||||
& (~InputDevice.SOURCE_CLASS_POINTER);
|
||||
}
|
||||
mUnbufferedInputSource = focusedChildNonPointerSource;
|
||||
|
||||
// Request unbuffered dispatch for pointer events for this view if any child requested
|
||||
// unbuffered dispatch for pointer events. This is because we can't expect that the pointer
|
||||
// source would dispatch to the focused view.
|
||||
for (int i = 0; i < mChildrenCount; i++) {
|
||||
final View child = mChildren[i];
|
||||
if ((child.mUnbufferedInputSource & InputDevice.SOURCE_CLASS_POINTER) != 0) {
|
||||
mUnbufferedInputSource |= InputDevice.SOURCE_CLASS_POINTER;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (mParent != null) {
|
||||
mParent.onDescendantUnbufferedRequested();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -675,4 +675,18 @@ public interface ViewParent {
|
||||
*/
|
||||
default void subtractObscuredTouchableRegion(Region touchableRegion, View view) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Unbuffered dispatch has been requested by a child of this view parent.
|
||||
* This method is called by the View hierarchy to signal ancestors that a View needs to
|
||||
* request unbuffered dispatch.
|
||||
*
|
||||
* @see View#requestUnbufferedDispatch(int)
|
||||
* @hide
|
||||
*/
|
||||
default void onDescendantUnbufferedRequested() {
|
||||
if (getParent() != null) {
|
||||
getParent().onDescendantUnbufferedRequested();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package android.view;
|
||||
|
||||
import static android.view.Display.DEFAULT_DISPLAY;
|
||||
import static android.view.Display.INVALID_DISPLAY;
|
||||
import static android.view.InputDevice.SOURCE_CLASS_NONE;
|
||||
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
|
||||
import static android.view.InsetsState.ITYPE_STATUS_BAR;
|
||||
import static android.view.View.PFLAG_DRAW_ANIMATION;
|
||||
@@ -116,6 +117,7 @@ import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
import android.util.TimeUtils;
|
||||
import android.util.TypedValue;
|
||||
import android.view.InputDevice.InputSourceClass;
|
||||
import android.view.InsetsState.InternalInsetsType;
|
||||
import android.view.Surface.OutOfResourcesException;
|
||||
import android.view.SurfaceControl.Transaction;
|
||||
@@ -499,6 +501,10 @@ public final class ViewRootImpl implements ViewParent,
|
||||
int mPendingInputEventCount;
|
||||
boolean mProcessInputEventsScheduled;
|
||||
boolean mUnbufferedInputDispatch;
|
||||
boolean mUnbufferedInputDispatchBySource;
|
||||
@InputSourceClass
|
||||
int mUnbufferedInputSource = SOURCE_CLASS_NONE;
|
||||
|
||||
String mPendingInputEventQueueLengthCounterName = "pq";
|
||||
|
||||
InputStage mFirstInputStage;
|
||||
@@ -1849,7 +1855,7 @@ public final class ViewRootImpl implements ViewParent,
|
||||
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
|
||||
mChoreographer.postCallback(
|
||||
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
|
||||
if (!mUnbufferedInputDispatch) {
|
||||
if (!mUnbufferedInputDispatch && !mUnbufferedInputDispatchBySource) {
|
||||
scheduleConsumeBatchedInput();
|
||||
}
|
||||
notifyRendererOfFramePending();
|
||||
@@ -7505,6 +7511,9 @@ public final class ViewRootImpl implements ViewParent,
|
||||
writer.print(mTraversalScheduled);
|
||||
writer.print(innerPrefix); writer.print("mIsAmbientMode=");
|
||||
writer.print(mIsAmbientMode);
|
||||
writer.print(innerPrefix); writer.print("mUnbufferedInputSource=");
|
||||
writer.print(Integer.toHexString(mUnbufferedInputSource));
|
||||
|
||||
if (mTraversalScheduled) {
|
||||
writer.print(" (barrier="); writer.print(mTraversalBarrier); writer.println(")");
|
||||
} else {
|
||||
@@ -8109,6 +8118,7 @@ public final class ViewRootImpl implements ViewParent,
|
||||
@Override
|
||||
public void onInputEvent(InputEvent event) {
|
||||
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "processInputEventForCompatibility");
|
||||
processUnbufferedRequest(event);
|
||||
List<InputEvent> processedEvents;
|
||||
try {
|
||||
processedEvents =
|
||||
@@ -8134,7 +8144,7 @@ public final class ViewRootImpl implements ViewParent,
|
||||
|
||||
@Override
|
||||
public void onBatchedInputEventPending() {
|
||||
if (mUnbufferedInputDispatch) {
|
||||
if (mUnbufferedInputDispatch || mUnbufferedInputDispatchBySource) {
|
||||
super.onBatchedInputEventPending();
|
||||
} else {
|
||||
scheduleConsumeBatchedInput();
|
||||
@@ -8151,6 +8161,17 @@ public final class ViewRootImpl implements ViewParent,
|
||||
unscheduleConsumeBatchedInput();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
private void processUnbufferedRequest(InputEvent event) {
|
||||
if (!(event instanceof MotionEvent)) {
|
||||
return;
|
||||
}
|
||||
mUnbufferedInputDispatchBySource =
|
||||
(event.getSource() & mUnbufferedInputSource) != SOURCE_CLASS_NONE;
|
||||
if (mUnbufferedInputDispatchBySource && mConsumeBatchedInputScheduled) {
|
||||
scheduleConsumeBatchedInputImmediately();
|
||||
}
|
||||
}
|
||||
}
|
||||
WindowInputEventReceiver mInputEventReceiver;
|
||||
|
||||
@@ -9601,4 +9622,9 @@ public final class ViewRootImpl implements ViewParent,
|
||||
return mSurfaceControl;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDescendantUnbufferedRequested() {
|
||||
mUnbufferedInputSource = mView.mUnbufferedInputSource;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user