diff options
Diffstat (limited to 'core/java/android/view/ViewGroup.java')
| -rw-r--r-- | core/java/android/view/ViewGroup.java | 103 |
1 files changed, 101 insertions, 2 deletions
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index a18a9775fd73..abe667211885 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -245,9 +245,14 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager protected static final int FLAG_DISALLOW_INTERCEPT = 0x80000; /** + * When set, at least one child of this ViewGroup will return true from hasOverlay. + */ + private static final int FLAG_CHILD_HAS_OVERLAY = 0x100000; + + /** * When set, this ViewGroup will split MotionEvents to multiple child Views when appropriate. */ - private static final int FLAG_SPLIT_MOTION_EVENTS = 0x100000; + private static final int FLAG_SPLIT_MOTION_EVENTS = 0x200000; /** * Indicates which types of drawing caches are to be kept in memory. @@ -904,6 +909,34 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager // who can handle it, start with the front-most child. final View[] children = mChildren; final int count = mChildrenCount; + + // Check for children with overlays first. They don't rely on hit rects to determine + // if they can accept a new touch event. + if ((mGroupFlags & FLAG_CHILD_HAS_OVERLAY) == FLAG_CHILD_HAS_OVERLAY) { + for (int i = count - 1; i >= 0; i--) { + final View child = children[i]; + // Don't let children respond to events as an overlay during an animation. + if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE + && child.getAnimation() == null + && child.isOverlayEnabled()) { + // offset the event to the view's coordinate system + final float xc = scrolledXFloat - child.mLeft; + final float yc = scrolledYFloat - child.mTop; + ev.setLocation(xc, yc); + child.mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT; + if (child.dispatchTouchEvent(ev)) { + // Event handled, we have a target now. + mMotionTarget = child; + return true; + } + // The event didn't get handled, try the next view. + // Don't reset the event's location, it's not + // necessary here. + } + } + } + + // Now check views normally. for (int i = count - 1; i >= 0; i--) { final View child = children[i]; if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE @@ -2741,6 +2774,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager if (clearChildFocus != null) { clearChildFocus(clearChildFocus); } + + mGroupFlags &= ~FLAG_CHILD_HAS_OVERLAY; } /** @@ -2989,7 +3024,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager final int left = mLeft; final int top = mTop; - if (dirty.intersect(0, 0, mRight - left, mBottom - top) || + if ((mGroupFlags & FLAG_CHILD_HAS_OVERLAY) == FLAG_CHILD_HAS_OVERLAY || + dirty.intersect(0, 0, mRight - left, mBottom - top) || (mPrivateFlags & DRAW_ANIMATION) == DRAW_ANIMATION) { mPrivateFlags &= ~DRAWING_CACHE_VALID; @@ -3977,6 +4013,69 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } /** + * Called when a child's overlay state changes between enabled/disabled. + * @param child Child view whose state has changed or null + * @hide + */ + public void childOverlayStateChanged(View child) { + boolean childHasOverlay = false; + if (child != null) { + childHasOverlay = child.isOverlayEnabled(); + } else { + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + if (childHasOverlay |= getChildAt(i).isOverlayEnabled()) { + break; + } + } + } + + final boolean hasChildWithOverlay = childHasOverlay || + (mGroupFlags & FLAG_CHILD_HAS_OVERLAY) == FLAG_CHILD_HAS_OVERLAY; + + final boolean oldValue = isOverlayEnabled(); + mGroupFlags = (mGroupFlags & ~FLAG_CHILD_HAS_OVERLAY) | + (hasChildWithOverlay ? FLAG_CHILD_HAS_OVERLAY : 0); + if (isOverlayEnabled() != oldValue) { + final ViewParent parent = getParent(); + if (parent != null) { + try { + parent.childOverlayStateChanged(this); + } catch (AbstractMethodError e) { + Log.e("ViewGroup", "Could not propagate hasOverlay state", e); + } + } + } + } + + /** + * @hide + */ + public boolean isOverlayEnabled() { + return super.isOverlayEnabled() || + ((mGroupFlags & FLAG_CHILD_HAS_OVERLAY) == FLAG_CHILD_HAS_OVERLAY); + } + + /** + * @hide + */ + @Override + public void onDrawOverlay(Canvas canvas) { + if ((mGroupFlags & FLAG_CHILD_HAS_OVERLAY) == FLAG_CHILD_HAS_OVERLAY) { + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + final View child = getChildAt(i); + if (child.isOverlayEnabled()) { + canvas.translate(child.mLeft + child.mScrollX, child.mTop + child.mScrollY); + child.onDrawOverlay(canvas); + canvas.translate(-(child.mLeft + child.mScrollX), + -(child.mTop + child.mScrollY)); + } + } + } + } + + /** * LayoutParams are used by views to tell their parents how they want to be * laid out. See * {@link android.R.styleable#ViewGroup_Layout ViewGroup Layout Attributes} |
