Loading api/current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -48377,6 +48377,7 @@ package android.view { ctor public TouchDelegate(android.graphics.Rect, android.view.View); method public android.view.accessibility.AccessibilityNodeInfo.TouchDelegateInfo getTouchDelegateInfo(); method public boolean onTouchEvent(android.view.MotionEvent); method public boolean onTouchExplorationHoverEvent(android.view.MotionEvent); field public static final int ABOVE = 1; // 0x1 field public static final int BELOW = 2; // 0x2 field public static final int TO_LEFT = 4; // 0x4 core/java/android/view/TouchDelegate.java +54 −7 Original line number Diff line number Diff line Loading @@ -103,13 +103,13 @@ public class TouchDelegate { } /** * Will forward touch events to the delegate view if the event is within the bounds * Forward touch events to the delegate view if the event is within the bounds * specified in the constructor. * * @param event The touch event to forward * @return True if the event was forwarded to the delegate, false otherwise. * @return True if the event was consumed by the delegate, false otherwise. */ public boolean onTouchEvent(MotionEvent event) { public boolean onTouchEvent(@NonNull MotionEvent event) { int x = (int)event.getX(); int y = (int)event.getY(); boolean sendToDelegate = false; Loading Loading @@ -139,18 +139,65 @@ public class TouchDelegate { break; } if (sendToDelegate) { final View delegateView = mDelegateView; if (hit) { // Offset event coordinates to be inside the target view event.setLocation(delegateView.getWidth() / 2, delegateView.getHeight() / 2); event.setLocation(mDelegateView.getWidth() / 2, mDelegateView.getHeight() / 2); } else { // Offset event coordinates to be outside the target view (in case it does // something like tracking pressed state) int slop = mSlop; event.setLocation(-(slop * 2), -(slop * 2)); } handled = delegateView.dispatchTouchEvent(event); handled = mDelegateView.dispatchTouchEvent(event); } return handled; } /** * Forward hover events to the delegate view if the event is within the bounds * specified in the constructor and touch exploration is enabled. * * @param event The hover event to forward * @return True if the event was consumed by the delegate, false otherwise. * * @see android.view.accessibility.AccessibilityManager#isTouchExplorationEnabled */ public boolean onTouchExplorationHoverEvent(@NonNull MotionEvent event) { if (mBounds == null) { return false; } final int x = (int) event.getX(); final int y = (int) event.getY(); boolean hit = true; boolean handled = false; final boolean isInbound = mBounds.contains(x, y); switch (event.getActionMasked()) { case MotionEvent.ACTION_HOVER_ENTER: mDelegateTargeted = isInbound; break; case MotionEvent.ACTION_HOVER_MOVE: if (isInbound) { mDelegateTargeted = true; } else { // delegated previously if (mDelegateTargeted && !mSlopBounds.contains(x, y)) { hit = false; } } break; case MotionEvent.ACTION_HOVER_EXIT: mDelegateTargeted = true; break; } if (mDelegateTargeted) { if (hit) { event.setLocation(mDelegateView.getWidth() / 2, mDelegateView.getHeight() / 2); } else { mDelegateTargeted = false; } handled = mDelegateView.dispatchHoverEvent(event); } return handled; } Loading core/java/android/view/View.java +21 −1 Original line number Diff line number Diff line Loading @@ -12829,6 +12829,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback, return false; } /** * Returns true if the given point, in local coordinates, is inside the hovered child. * * @hide */ protected boolean pointInHoveredChild(MotionEvent event) { return false; } /** * Dispatch a generic motion event to the view under the first pointer. * <p> Loading Loading @@ -13584,6 +13593,17 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @see #onHoverChanged */ public boolean onHoverEvent(MotionEvent event) { // Explore by touch should dispatch events to children under pointer first if any before // dispatching to TouchDelegate. For children non-hoverable that will not consume events, // it should also not delegate when they got the pointer hovered. if (mTouchDelegate != null && !pointInHoveredChild(event)) { final AccessibilityManager manager = AccessibilityManager.getInstance(mContext); if (manager.isEnabled() && manager.isTouchExplorationEnabled() && mTouchDelegate.onTouchExplorationHoverEvent(event)) { return true; } } // The root view may receive hover (or touch) events that are outside the bounds of // the window. This code ensures that we only send accessibility events for // hovers that are actually within the bounds of the root view. Loading @@ -13598,7 +13618,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } } else { if (action == MotionEvent.ACTION_HOVER_EXIT || (action == MotionEvent.ACTION_MOVE || (action == MotionEvent.ACTION_HOVER_MOVE && !pointInView(event.getX(), event.getY()))) { mSendingHoverAccessibilityEvents = false; sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT); core/java/android/view/ViewGroup.java +10 −0 Original line number Diff line number Diff line Loading @@ -2383,6 +2383,16 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager return mFirstHoverTarget != null; } /** @hide */ @Override protected boolean pointInHoveredChild(MotionEvent event) { if (mFirstHoverTarget != null) { return isTransformedTouchPointInView(event.getX(), event.getY(), mFirstHoverTarget.child, null); } return false; } @Override public void addChildrenForAccessibility(ArrayList<View> outChildren) { if (getAccessibilityNodeProvider() != null) { Loading Loading
api/current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -48377,6 +48377,7 @@ package android.view { ctor public TouchDelegate(android.graphics.Rect, android.view.View); method public android.view.accessibility.AccessibilityNodeInfo.TouchDelegateInfo getTouchDelegateInfo(); method public boolean onTouchEvent(android.view.MotionEvent); method public boolean onTouchExplorationHoverEvent(android.view.MotionEvent); field public static final int ABOVE = 1; // 0x1 field public static final int BELOW = 2; // 0x2 field public static final int TO_LEFT = 4; // 0x4
core/java/android/view/TouchDelegate.java +54 −7 Original line number Diff line number Diff line Loading @@ -103,13 +103,13 @@ public class TouchDelegate { } /** * Will forward touch events to the delegate view if the event is within the bounds * Forward touch events to the delegate view if the event is within the bounds * specified in the constructor. * * @param event The touch event to forward * @return True if the event was forwarded to the delegate, false otherwise. * @return True if the event was consumed by the delegate, false otherwise. */ public boolean onTouchEvent(MotionEvent event) { public boolean onTouchEvent(@NonNull MotionEvent event) { int x = (int)event.getX(); int y = (int)event.getY(); boolean sendToDelegate = false; Loading Loading @@ -139,18 +139,65 @@ public class TouchDelegate { break; } if (sendToDelegate) { final View delegateView = mDelegateView; if (hit) { // Offset event coordinates to be inside the target view event.setLocation(delegateView.getWidth() / 2, delegateView.getHeight() / 2); event.setLocation(mDelegateView.getWidth() / 2, mDelegateView.getHeight() / 2); } else { // Offset event coordinates to be outside the target view (in case it does // something like tracking pressed state) int slop = mSlop; event.setLocation(-(slop * 2), -(slop * 2)); } handled = delegateView.dispatchTouchEvent(event); handled = mDelegateView.dispatchTouchEvent(event); } return handled; } /** * Forward hover events to the delegate view if the event is within the bounds * specified in the constructor and touch exploration is enabled. * * @param event The hover event to forward * @return True if the event was consumed by the delegate, false otherwise. * * @see android.view.accessibility.AccessibilityManager#isTouchExplorationEnabled */ public boolean onTouchExplorationHoverEvent(@NonNull MotionEvent event) { if (mBounds == null) { return false; } final int x = (int) event.getX(); final int y = (int) event.getY(); boolean hit = true; boolean handled = false; final boolean isInbound = mBounds.contains(x, y); switch (event.getActionMasked()) { case MotionEvent.ACTION_HOVER_ENTER: mDelegateTargeted = isInbound; break; case MotionEvent.ACTION_HOVER_MOVE: if (isInbound) { mDelegateTargeted = true; } else { // delegated previously if (mDelegateTargeted && !mSlopBounds.contains(x, y)) { hit = false; } } break; case MotionEvent.ACTION_HOVER_EXIT: mDelegateTargeted = true; break; } if (mDelegateTargeted) { if (hit) { event.setLocation(mDelegateView.getWidth() / 2, mDelegateView.getHeight() / 2); } else { mDelegateTargeted = false; } handled = mDelegateView.dispatchHoverEvent(event); } return handled; } Loading
core/java/android/view/View.java +21 −1 Original line number Diff line number Diff line Loading @@ -12829,6 +12829,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback, return false; } /** * Returns true if the given point, in local coordinates, is inside the hovered child. * * @hide */ protected boolean pointInHoveredChild(MotionEvent event) { return false; } /** * Dispatch a generic motion event to the view under the first pointer. * <p> Loading Loading @@ -13584,6 +13593,17 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @see #onHoverChanged */ public boolean onHoverEvent(MotionEvent event) { // Explore by touch should dispatch events to children under pointer first if any before // dispatching to TouchDelegate. For children non-hoverable that will not consume events, // it should also not delegate when they got the pointer hovered. if (mTouchDelegate != null && !pointInHoveredChild(event)) { final AccessibilityManager manager = AccessibilityManager.getInstance(mContext); if (manager.isEnabled() && manager.isTouchExplorationEnabled() && mTouchDelegate.onTouchExplorationHoverEvent(event)) { return true; } } // The root view may receive hover (or touch) events that are outside the bounds of // the window. This code ensures that we only send accessibility events for // hovers that are actually within the bounds of the root view. Loading @@ -13598,7 +13618,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } } else { if (action == MotionEvent.ACTION_HOVER_EXIT || (action == MotionEvent.ACTION_MOVE || (action == MotionEvent.ACTION_HOVER_MOVE && !pointInView(event.getX(), event.getY()))) { mSendingHoverAccessibilityEvents = false; sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT);
core/java/android/view/ViewGroup.java +10 −0 Original line number Diff line number Diff line Loading @@ -2383,6 +2383,16 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager return mFirstHoverTarget != null; } /** @hide */ @Override protected boolean pointInHoveredChild(MotionEvent event) { if (mFirstHoverTarget != null) { return isTransformedTouchPointInView(event.getX(), event.getY(), mFirstHoverTarget.child, null); } return false; } @Override public void addChildrenForAccessibility(ArrayList<View> outChildren) { if (getAccessibilityNodeProvider() != null) { Loading