Merge "Add MotionEvent.HOVER_ENTER and HOVER_EXIT."
This commit is contained in:
@@ -172,6 +172,8 @@ public final class MotionEvent extends InputEvent implements Parcelable {
|
||||
* recent point, as well as any intermediate points since the last
|
||||
* hover move event.
|
||||
* <p>
|
||||
* This action is always delivered to the window or view under the pointer.
|
||||
* </p><p>
|
||||
* This action is not a touch event so it is delivered to
|
||||
* {@link View#onGenericMotionEvent(MotionEvent)} rather than
|
||||
* {@link View#onTouchEvent(MotionEvent)}.
|
||||
@@ -184,8 +186,9 @@ public final class MotionEvent extends InputEvent implements Parcelable {
|
||||
* vertical and/or horizontal scroll offsets. Use {@link #getAxisValue(int)}
|
||||
* to retrieve the information from {@link #AXIS_VSCROLL} and {@link #AXIS_HSCROLL}.
|
||||
* The pointer may or may not be down when this event is dispatched.
|
||||
* This action is always delivered to the winder under the pointer, which
|
||||
* may not be the window currently touched.
|
||||
* <p></p>
|
||||
* This action is always delivered to the window or view under the pointer, which
|
||||
* may not be the window or view currently touched.
|
||||
* <p>
|
||||
* This action is not a touch event so it is delivered to
|
||||
* {@link View#onGenericMotionEvent(MotionEvent)} rather than
|
||||
@@ -194,6 +197,32 @@ public final class MotionEvent extends InputEvent implements Parcelable {
|
||||
*/
|
||||
public static final int ACTION_SCROLL = 8;
|
||||
|
||||
/**
|
||||
* Constant for {@link #getAction}: The pointer is not down but has entered the
|
||||
* boundaries of a window or view.
|
||||
* <p>
|
||||
* This action is always delivered to the window or view under the pointer.
|
||||
* </p><p>
|
||||
* This action is not a touch event so it is delivered to
|
||||
* {@link View#onGenericMotionEvent(MotionEvent)} rather than
|
||||
* {@link View#onTouchEvent(MotionEvent)}.
|
||||
* </p>
|
||||
*/
|
||||
public static final int ACTION_HOVER_ENTER = 9;
|
||||
|
||||
/**
|
||||
* Constant for {@link #getAction}: The pointer is not down but has exited the
|
||||
* boundaries of a window or view.
|
||||
* <p>
|
||||
* This action is always delivered to the window or view that was previously under the pointer.
|
||||
* </p><p>
|
||||
* This action is not a touch event so it is delivered to
|
||||
* {@link View#onGenericMotionEvent(MotionEvent)} rather than
|
||||
* {@link View#onTouchEvent(MotionEvent)}.
|
||||
* </p>
|
||||
*/
|
||||
public static final int ACTION_HOVER_EXIT = 10;
|
||||
|
||||
/**
|
||||
* Bits in the action code that represent a pointer index, used with
|
||||
* {@link #ACTION_POINTER_DOWN} and {@link #ACTION_POINTER_UP}. Shifting
|
||||
@@ -1354,9 +1383,9 @@ public final class MotionEvent extends InputEvent implements Parcelable {
|
||||
/**
|
||||
* Returns true if this motion event is a touch event.
|
||||
* <p>
|
||||
* Specifically excludes pointer events with action {@link #ACTION_HOVER_MOVE}
|
||||
* or {@link #ACTION_SCROLL} because they are not actually touch events
|
||||
* (the pointer is not down).
|
||||
* Specifically excludes pointer events with action {@link #ACTION_HOVER_MOVE},
|
||||
* {@link #ACTION_HOVER_ENTER}, {@link #ACTION_HOVER_EXIT}, or {@link #ACTION_SCROLL}
|
||||
* because they are not actually touch events (the pointer is not down).
|
||||
* </p>
|
||||
* @return True if this motion event is a touch event.
|
||||
* @hide
|
||||
@@ -2313,6 +2342,10 @@ public final class MotionEvent extends InputEvent implements Parcelable {
|
||||
return "ACTION_HOVER_MOVE";
|
||||
case ACTION_SCROLL:
|
||||
return "ACTION_SCROLL";
|
||||
case ACTION_HOVER_ENTER:
|
||||
return "ACTION_HOVER_ENTER";
|
||||
case ACTION_HOVER_EXIT:
|
||||
return "ACTION_HOVER_EXIT";
|
||||
}
|
||||
int index = (action & ACTION_POINTER_INDEX_MASK) >> ACTION_POINTER_INDEX_SHIFT;
|
||||
switch (action & ACTION_MASK) {
|
||||
|
||||
@@ -1622,6 +1622,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
|
||||
*/
|
||||
private static final int AWAKEN_SCROLL_BARS_ON_ATTACH = 0x08000000;
|
||||
|
||||
/**
|
||||
* Indicates that the view has received HOVER_ENTER. Cleared on HOVER_EXIT.
|
||||
* @hide
|
||||
*/
|
||||
private static final int HOVERED = 0x10000000;
|
||||
|
||||
/**
|
||||
* Indicates that pivotX or pivotY were explicitly set and we should not assume the center
|
||||
* for transform operations
|
||||
@@ -4643,22 +4649,80 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
|
||||
* <p>
|
||||
* Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER}
|
||||
* are delivered to the view under the pointer. All other generic motion events are
|
||||
* delivered to the focused view.
|
||||
* delivered to the focused view. Hover events are handled specially and are delivered
|
||||
* to {@link #onHoverEvent}.
|
||||
* </p>
|
||||
*
|
||||
* @param event The motion event to be dispatched.
|
||||
* @return True if the event was handled by the view, false otherwise.
|
||||
*/
|
||||
public boolean dispatchGenericMotionEvent(MotionEvent event) {
|
||||
final int source = event.getSource();
|
||||
if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
|
||||
final int action = event.getAction();
|
||||
if (action == MotionEvent.ACTION_HOVER_ENTER
|
||||
|| action == MotionEvent.ACTION_HOVER_MOVE
|
||||
|| action == MotionEvent.ACTION_HOVER_EXIT) {
|
||||
if (dispatchHoverEvent(event)) {
|
||||
return true;
|
||||
}
|
||||
} else if (dispatchGenericPointerEvent(event)) {
|
||||
return true;
|
||||
}
|
||||
} else if (dispatchGenericFocusedEvent(event)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//noinspection SimplifiableIfStatement
|
||||
if (mOnGenericMotionListener != null && (mViewFlags & ENABLED_MASK) == ENABLED
|
||||
&& mOnGenericMotionListener.onGenericMotion(this, event)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return onGenericMotionEvent(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch a hover event.
|
||||
* <p>
|
||||
* Do not call this method directly. Call {@link #dispatchGenericMotionEvent} instead.
|
||||
* </p>
|
||||
*
|
||||
* @param event The motion event to be dispatched.
|
||||
* @return True if the event was handled by the view, false otherwise.
|
||||
* @hide
|
||||
*/
|
||||
protected boolean dispatchHoverEvent(MotionEvent event) {
|
||||
return onHoverEvent(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch a generic motion event to the view under the first pointer.
|
||||
* <p>
|
||||
* Do not call this method directly. Call {@link #dispatchGenericMotionEvent} instead.
|
||||
* </p>
|
||||
*
|
||||
* @param event The motion event to be dispatched.
|
||||
* @return True if the event was handled by the view, false otherwise.
|
||||
* @hide
|
||||
*/
|
||||
protected boolean dispatchGenericPointerEvent(MotionEvent event) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch a generic motion event to the currently focused view.
|
||||
* <p>
|
||||
* Do not call this method directly. Call {@link #dispatchGenericMotionEvent} instead.
|
||||
* </p>
|
||||
*
|
||||
* @param event The motion event to be dispatched.
|
||||
* @return True if the event was handled by the view, false otherwise.
|
||||
* @hide
|
||||
*/
|
||||
protected boolean dispatchGenericFocusedEvent(MotionEvent event) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch a pointer event.
|
||||
* <p>
|
||||
@@ -5223,14 +5287,91 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
|
||||
* </code>
|
||||
*
|
||||
* @param event The generic motion event being processed.
|
||||
*
|
||||
* @return Return true if you have consumed the event, false if you haven't.
|
||||
* The default implementation always returns false.
|
||||
* @return True if the event was handled, false otherwise.
|
||||
*/
|
||||
public boolean onGenericMotionEvent(MotionEvent event) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement this method to handle hover events.
|
||||
* <p>
|
||||
* Hover events are pointer events with action {@link MotionEvent#ACTION_HOVER_ENTER},
|
||||
* {@link MotionEvent#ACTION_HOVER_MOVE}, or {@link MotionEvent#ACTION_HOVER_EXIT}.
|
||||
* </p><p>
|
||||
* The view receives hover enter as the pointer enters the bounds of the view and hover
|
||||
* exit as the pointer exits the bound of the view or just before the pointer goes down
|
||||
* (which implies that {@link #onTouchEvent} will be called soon).
|
||||
* </p><p>
|
||||
* If the view would like to handle the hover event itself and prevent its children
|
||||
* from receiving hover, it should return true from this method. If this method returns
|
||||
* true and a child has already received a hover enter event, the child will
|
||||
* automatically receive a hover exit event.
|
||||
* </p><p>
|
||||
* The default implementation sets the hovered state of the view if the view is
|
||||
* clickable.
|
||||
* </p>
|
||||
*
|
||||
* @param event The motion event that describes the hover.
|
||||
* @return True if this view handled the hover event and does not want its children
|
||||
* to receive the hover event.
|
||||
*/
|
||||
public boolean onHoverEvent(MotionEvent event) {
|
||||
final int viewFlags = mViewFlags;
|
||||
|
||||
if (((viewFlags & CLICKABLE) != CLICKABLE &&
|
||||
(viewFlags & LONG_CLICKABLE) != LONG_CLICKABLE)) {
|
||||
// Nothing to do if the view is not clickable.
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((viewFlags & ENABLED_MASK) == DISABLED) {
|
||||
// A disabled view that is clickable still consumes the hover events, it just doesn't
|
||||
// respond to them.
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (event.getAction()) {
|
||||
case MotionEvent.ACTION_HOVER_ENTER:
|
||||
setHovered(true);
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_HOVER_EXIT:
|
||||
setHovered(false);
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the view is currently hovered.
|
||||
*
|
||||
* @return True if the view is currently hovered.
|
||||
*/
|
||||
public boolean isHovered() {
|
||||
return (mPrivateFlags & HOVERED) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the view is currently hovered.
|
||||
*
|
||||
* @param hovered True if the view is hovered.
|
||||
*/
|
||||
public void setHovered(boolean hovered) {
|
||||
if (hovered) {
|
||||
if ((mPrivateFlags & HOVERED) == 0) {
|
||||
mPrivateFlags |= HOVERED;
|
||||
refreshDrawableState();
|
||||
}
|
||||
} else {
|
||||
if ((mPrivateFlags & HOVERED) != 0) {
|
||||
mPrivateFlags &= ~HOVERED;
|
||||
refreshDrawableState();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement this method to handle touch screen motion events.
|
||||
*
|
||||
@@ -9882,6 +10023,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
|
||||
// windows to better match their app.
|
||||
viewStateIndex |= VIEW_STATE_ACCELERATED;
|
||||
}
|
||||
if ((privateFlags & HOVERED) != 0) viewStateIndex |= VIEW_STATE_PRESSED; // temporary
|
||||
|
||||
drawableState = VIEW_STATE_SETS[viewStateIndex];
|
||||
|
||||
|
||||
@@ -147,6 +147,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
|
||||
@ViewDebug.ExportedProperty(category = "events")
|
||||
private float mLastTouchDownY;
|
||||
|
||||
// Child which last received ACTION_HOVER_ENTER and ACTION_HOVER_MOVE.
|
||||
private View mHoveredChild;
|
||||
|
||||
/**
|
||||
* Internal flags.
|
||||
*
|
||||
@@ -1140,13 +1143,50 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
/** @hide */
|
||||
@Override
|
||||
public boolean dispatchGenericMotionEvent(MotionEvent event) {
|
||||
if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
|
||||
// Send the event to the child under the pointer.
|
||||
protected boolean dispatchHoverEvent(MotionEvent event) {
|
||||
// Send the hover enter or hover move event to the view group first.
|
||||
// If it handles the event then a hovered child should receive hover exit.
|
||||
boolean handled = false;
|
||||
final boolean interceptHover;
|
||||
final int action = event.getAction();
|
||||
if (action == MotionEvent.ACTION_HOVER_EXIT) {
|
||||
interceptHover = true;
|
||||
} else {
|
||||
handled = super.dispatchHoverEvent(event);
|
||||
interceptHover = handled;
|
||||
}
|
||||
|
||||
// Send successive hover events to the hovered child as long as the pointer
|
||||
// remains within the child's bounds.
|
||||
MotionEvent eventNoHistory = event;
|
||||
if (mHoveredChild != null) {
|
||||
final float x = event.getX();
|
||||
final float y = event.getY();
|
||||
|
||||
if (interceptHover
|
||||
|| !isTransformedTouchPointInView(x, y, mHoveredChild, null)) {
|
||||
// Pointer exited the child.
|
||||
// Send it a hover exit with only the most recent coordinates. We could
|
||||
// try to find the exact point in history when the pointer left the view
|
||||
// but it is not worth the effort.
|
||||
eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory);
|
||||
eventNoHistory.setAction(MotionEvent.ACTION_HOVER_EXIT);
|
||||
handled |= dispatchTransformedGenericPointerEvent(eventNoHistory, mHoveredChild);
|
||||
eventNoHistory.setAction(action);
|
||||
|
||||
mHoveredChild = null;
|
||||
} else if (action == MotionEvent.ACTION_HOVER_MOVE) {
|
||||
// Pointer is still within the child.
|
||||
handled |= dispatchTransformedGenericPointerEvent(event, mHoveredChild);
|
||||
}
|
||||
}
|
||||
|
||||
// Find a new hovered child if needed.
|
||||
if (!interceptHover && mHoveredChild == null
|
||||
&& (action == MotionEvent.ACTION_HOVER_ENTER
|
||||
|| action == MotionEvent.ACTION_HOVER_MOVE)) {
|
||||
final int childrenCount = mChildrenCount;
|
||||
if (childrenCount != 0) {
|
||||
final View[] children = mChildren;
|
||||
@@ -1155,51 +1195,121 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
|
||||
|
||||
for (int i = childrenCount - 1; i >= 0; i--) {
|
||||
final View child = children[i];
|
||||
if ((child.mViewFlags & VISIBILITY_MASK) != VISIBLE
|
||||
&& child.getAnimation() == null) {
|
||||
// Skip invisible child unless it is animating.
|
||||
if (!canViewReceivePointerEvents(child)
|
||||
|| !isTransformedTouchPointInView(x, y, child, null)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isTransformedTouchPointInView(x, y, child, null)) {
|
||||
// Scroll point is out of child's bounds.
|
||||
continue;
|
||||
}
|
||||
// Found the hovered child.
|
||||
mHoveredChild = child;
|
||||
if (action == MotionEvent.ACTION_HOVER_MOVE) {
|
||||
// Pointer was moving within the view group and entered the child.
|
||||
// Send it a hover enter and hover move with only the most recent
|
||||
// coordinates. We could try to find the exact point in history when
|
||||
// the pointer entered the view but it is not worth the effort.
|
||||
eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory);
|
||||
eventNoHistory.setAction(MotionEvent.ACTION_HOVER_ENTER);
|
||||
handled |= dispatchTransformedGenericPointerEvent(eventNoHistory, child);
|
||||
eventNoHistory.setAction(action);
|
||||
|
||||
final float offsetX = mScrollX - child.mLeft;
|
||||
final float offsetY = mScrollY - child.mTop;
|
||||
final boolean handled;
|
||||
if (!child.hasIdentityMatrix()) {
|
||||
MotionEvent transformedEvent = MotionEvent.obtain(event);
|
||||
transformedEvent.offsetLocation(offsetX, offsetY);
|
||||
transformedEvent.transform(child.getInverseMatrix());
|
||||
handled = child.dispatchGenericMotionEvent(transformedEvent);
|
||||
transformedEvent.recycle();
|
||||
} else {
|
||||
event.offsetLocation(offsetX, offsetY);
|
||||
handled = child.dispatchGenericMotionEvent(event);
|
||||
event.offsetLocation(-offsetX, -offsetY);
|
||||
}
|
||||
|
||||
if (handled) {
|
||||
return true;
|
||||
handled |= dispatchTransformedGenericPointerEvent(eventNoHistory, child);
|
||||
} else { /* must be ACTION_HOVER_ENTER */
|
||||
// Pointer entered the child.
|
||||
handled |= dispatchTransformedGenericPointerEvent(event, child);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// No child handled the event. Send it to this view group.
|
||||
return super.dispatchGenericMotionEvent(event);
|
||||
}
|
||||
|
||||
// Recycle the copy of the event that we made.
|
||||
if (eventNoHistory != event) {
|
||||
eventNoHistory.recycle();
|
||||
}
|
||||
|
||||
// Send hover exit to the view group. If there was a child, we will already have
|
||||
// sent the hover exit to it.
|
||||
if (action == MotionEvent.ACTION_HOVER_EXIT) {
|
||||
handled |= super.dispatchHoverEvent(event);
|
||||
}
|
||||
|
||||
// Done.
|
||||
return handled;
|
||||
}
|
||||
|
||||
private static MotionEvent obtainMotionEventNoHistoryOrSelf(MotionEvent event) {
|
||||
if (event.getHistorySize() == 0) {
|
||||
return event;
|
||||
}
|
||||
return MotionEvent.obtainNoHistory(event);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@Override
|
||||
protected boolean dispatchGenericPointerEvent(MotionEvent event) {
|
||||
// Send the event to the child under the pointer.
|
||||
final int childrenCount = mChildrenCount;
|
||||
if (childrenCount != 0) {
|
||||
final View[] children = mChildren;
|
||||
final float x = event.getX();
|
||||
final float y = event.getY();
|
||||
|
||||
for (int i = childrenCount - 1; i >= 0; i--) {
|
||||
final View child = children[i];
|
||||
if (!canViewReceivePointerEvents(child)
|
||||
|| !isTransformedTouchPointInView(x, y, child, null)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dispatchTransformedGenericPointerEvent(event, child)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No child handled the event. Send it to this view group.
|
||||
return super.dispatchGenericPointerEvent(event);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@Override
|
||||
protected boolean dispatchGenericFocusedEvent(MotionEvent event) {
|
||||
// Send the event to the focused child or to this view group if it has focus.
|
||||
if ((mPrivateFlags & (FOCUSED | HAS_BOUNDS)) == (FOCUSED | HAS_BOUNDS)) {
|
||||
return super.dispatchGenericMotionEvent(event);
|
||||
return super.dispatchGenericFocusedEvent(event);
|
||||
} else if (mFocused != null && (mFocused.mPrivateFlags & HAS_BOUNDS) == HAS_BOUNDS) {
|
||||
return mFocused.dispatchGenericMotionEvent(event);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches a generic pointer event to a child, taking into account
|
||||
* transformations that apply to the child.
|
||||
*
|
||||
* @param event The event to send.
|
||||
* @param child The view to send the event to.
|
||||
* @return {@code true} if the child handled the event.
|
||||
*/
|
||||
private boolean dispatchTransformedGenericPointerEvent(MotionEvent event, View child) {
|
||||
final float offsetX = mScrollX - child.mLeft;
|
||||
final float offsetY = mScrollY - child.mTop;
|
||||
|
||||
boolean handled;
|
||||
if (!child.hasIdentityMatrix()) {
|
||||
MotionEvent transformedEvent = MotionEvent.obtain(event);
|
||||
transformedEvent.offsetLocation(offsetX, offsetY);
|
||||
transformedEvent.transform(child.getInverseMatrix());
|
||||
handled = child.dispatchGenericMotionEvent(transformedEvent);
|
||||
transformedEvent.recycle();
|
||||
} else {
|
||||
event.offsetLocation(offsetX, offsetY);
|
||||
handled = child.dispatchGenericMotionEvent(event);
|
||||
event.offsetLocation(-offsetX, -offsetY);
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@@ -1213,8 +1323,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
|
||||
final int actionMasked = action & MotionEvent.ACTION_MASK;
|
||||
|
||||
// Handle an initial down.
|
||||
if (actionMasked == MotionEvent.ACTION_DOWN
|
||||
|| actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
|
||||
if (actionMasked == MotionEvent.ACTION_DOWN) {
|
||||
// Throw away all previous state when starting a new touch gesture.
|
||||
// The framework may have dropped the up or cancel event for the previous gesture
|
||||
// due to an app switch, ANR, or some other state change.
|
||||
@@ -1268,14 +1377,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
|
||||
|
||||
for (int i = childrenCount - 1; i >= 0; i--) {
|
||||
final View child = children[i];
|
||||
if ((child.mViewFlags & VISIBILITY_MASK) != VISIBLE
|
||||
&& child.getAnimation() == null) {
|
||||
// Skip invisible child unless it is animating.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isTransformedTouchPointInView(x, y, child, null)) {
|
||||
// New pointer is out of child's bounds.
|
||||
if (!canViewReceivePointerEvents(child)
|
||||
|| !isTransformedTouchPointInView(x, y, child, null)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1475,6 +1578,15 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a child view can receive pointer events.
|
||||
* @hide
|
||||
*/
|
||||
private static boolean canViewReceivePointerEvents(View child) {
|
||||
return (child.mViewFlags & VISIBILITY_MASK) == VISIBLE
|
||||
|| child.getAnimation() != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a child view contains the specified point when transformed
|
||||
* into its coordinate space.
|
||||
@@ -3244,6 +3356,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
|
||||
mTransition.removeChild(this, view);
|
||||
}
|
||||
|
||||
if (view == mHoveredChild) {
|
||||
mHoveredChild = null;
|
||||
}
|
||||
|
||||
boolean clearChildFocus = false;
|
||||
if (view == mFocused) {
|
||||
view.clearFocusForRemoval();
|
||||
@@ -3307,6 +3423,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
|
||||
final OnHierarchyChangeListener onHierarchyChangeListener = mOnHierarchyChangeListener;
|
||||
final boolean notifyListener = onHierarchyChangeListener != null;
|
||||
final View focused = mFocused;
|
||||
final View hoveredChild = mHoveredChild;
|
||||
final boolean detach = mAttachInfo != null;
|
||||
View clearChildFocus = null;
|
||||
|
||||
@@ -3320,6 +3437,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
|
||||
mTransition.removeChild(this, view);
|
||||
}
|
||||
|
||||
if (view == hoveredChild) {
|
||||
mHoveredChild = null;
|
||||
}
|
||||
|
||||
if (view == focused) {
|
||||
view.clearFocusForRemoval();
|
||||
clearChildFocus = view;
|
||||
@@ -3377,6 +3498,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
|
||||
final OnHierarchyChangeListener listener = mOnHierarchyChangeListener;
|
||||
final boolean notify = listener != null;
|
||||
final View focused = mFocused;
|
||||
final View hoveredChild = mHoveredChild;
|
||||
final boolean detach = mAttachInfo != null;
|
||||
View clearChildFocus = null;
|
||||
|
||||
@@ -3389,6 +3511,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
|
||||
mTransition.removeChild(this, view);
|
||||
}
|
||||
|
||||
if (view == hoveredChild) {
|
||||
mHoveredChild = null;
|
||||
}
|
||||
|
||||
if (view == focused) {
|
||||
view.clearFocusForRemoval();
|
||||
clearChildFocus = view;
|
||||
|
||||
@@ -357,6 +357,12 @@ public class PointerLocationView extends View {
|
||||
case MotionEvent.ACTION_HOVER_MOVE:
|
||||
prefix = "HOVER MOVE";
|
||||
break;
|
||||
case MotionEvent.ACTION_HOVER_ENTER:
|
||||
prefix = "HOVER ENTER";
|
||||
break;
|
||||
case MotionEvent.ACTION_HOVER_EXIT:
|
||||
prefix = "HOVER EXIT";
|
||||
break;
|
||||
case MotionEvent.ACTION_SCROLL:
|
||||
prefix = "SCROLL";
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user