am f1792c42: Merge "Fix hotspot coordinate propagation in ViewGroup and AbsListView" into lmp-mr1-dev

* commit 'f1792c4219fb341a59c4b90c0ce5dd6e0e7b87f0':
  Fix hotspot coordinate propagation in ViewGroup and AbsListView
This commit is contained in:
Alan Viverette
2014-12-08 18:47:46 +00:00
committed by Android Git Automerger
5 changed files with 134 additions and 55 deletions

View File

@@ -33331,6 +33331,7 @@ package android.view {
method public void dispatchDisplayHint(int);
method public boolean dispatchDragEvent(android.view.DragEvent);
method protected void dispatchDraw(android.graphics.Canvas);
method public void dispatchDrawableHotspotChanged(float, float);
method protected boolean dispatchGenericFocusedEvent(android.view.MotionEvent);
method public boolean dispatchGenericMotionEvent(android.view.MotionEvent);
method protected boolean dispatchGenericPointerEvent(android.view.MotionEvent);

View File

@@ -16059,7 +16059,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
/**
* This function is called whenever the view hotspot changes and needs to
* be propagated to drawables managed by the view.
* be propagated to drawables or child views managed by the view.
* <p>
* Dispatching to child views is handled by
* {@link #dispatchDrawableHotspotChanged(float, float)}.
* <p>
* Be sure to call through to the superclass when overriding this function.
*
@@ -16070,6 +16073,18 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
if (mBackground != null) {
mBackground.setHotspot(x, y);
}
dispatchDrawableHotspotChanged(x, y);
}
/**
* Dispatches drawableHotspotChanged to all of this View's children.
*
* @param x hotspot x coordinate
* @param y hotspot y coordinate
* @see #drawableHotspotChanged(float, float)
*/
public void dispatchDrawableHotspotChanged(float x, float y) {
}
/**

View File

@@ -161,6 +161,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
// Used during drag dispatch
private PointF mLocalPoint;
// Lazily-created holder for point computations.
private float[] mTempPoint;
// Layout animation
private LayoutAnimationController mLayoutAnimationController;
private Animation.AnimationListener mAnimationListener;
@@ -2442,6 +2445,13 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
|| child.getAnimation() != null;
}
private float[] getTempPoint() {
if (mTempPoint == null) {
mTempPoint = new float[2];
}
return mTempPoint;
}
/**
* Returns true if a child view contains the specified point when transformed
* into its coordinate space.
@@ -2450,23 +2460,29 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
*/
protected boolean isTransformedTouchPointInView(float x, float y, View child,
PointF outLocalPoint) {
float localX = x + mScrollX - child.mLeft;
float localY = y + mScrollY - child.mTop;
if (! child.hasIdentityMatrix() && mAttachInfo != null) {
final float[] localXY = mAttachInfo.mTmpTransformLocation;
localXY[0] = localX;
localXY[1] = localY;
child.getInverseMatrix().mapPoints(localXY);
localX = localXY[0];
localY = localXY[1];
}
final boolean isInView = child.pointInView(localX, localY);
final float[] point = getTempPoint();
point[0] = x;
point[1] = y;
transformPointToViewLocal(point, child);
final boolean isInView = child.pointInView(point[0], point[1]);
if (isInView && outLocalPoint != null) {
outLocalPoint.set(localX, localY);
outLocalPoint.set(point[0], point[1]);
}
return isInView;
}
/**
* @hide
*/
public void transformPointToViewLocal(float[] point, View child) {
point[0] += mScrollX - child.mLeft;
point[1] += mScrollY - child.mTop;
if (!child.hasIdentityMatrix()) {
child.getInverseMatrix().mapPoints(point);
}
}
/**
* Transforms a motion event into the coordinate space of a particular child view,
* filters out irrelevant pointer ids, and overrides its action if necessary.
@@ -3606,6 +3622,44 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
}
}
/**
* Dispatches drawable hotspot changes to child views that meet at least
* one of the following criteria:
* <ul>
* <li>Returns {@code false} from both {@link View#isClickable()} and
* {@link View#isLongClickable()}</li>
* <li>Requests duplication of parent state via
* {@link View#setDuplicateParentStateEnabled(boolean)}</li>
* </ul>
*
* @param x hotspot x coordinate
* @param y hotspot y coordinate
* @see #drawableHotspotChanged(float, float)
*/
@Override
public void dispatchDrawableHotspotChanged(float x, float y) {
final int count = mChildrenCount;
if (count == 0) {
return;
}
final View[] children = mChildren;
for (int i = 0; i < count; i++) {
final View child = children[i];
// Children that are clickable on their own should not
// receive hotspots when their parent view does.
final boolean nonActionable = !child.isClickable() && !child.isLongClickable();
final boolean duplicatesState = (child.mViewFlags & DUPLICATE_PARENT_STATE) != 0;
if (nonActionable || duplicatesState) {
final float[] point = getTempPoint();
point[0] = x;
point[1] = y;
transformPointToViewLocal(point, child);
child.drawableHotspotChanged(point[0], point[1]);
}
}
}
@Override
void dispatchCancelPendingInputEvents() {
super.dispatchCancelPendingInputEvents();
@@ -5960,28 +6014,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
}
}
@Override
public void drawableHotspotChanged(float x, float y) {
super.drawableHotspotChanged(x, y);
if ((mGroupFlags & FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE) != 0) {
if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0) {
throw new IllegalStateException("addStateFromChildren cannot be enabled if a"
+ " child has duplicateParentState set to true");
}
final View[] children = mChildren;
final int count = mChildrenCount;
for (int i = 0; i < count; i++) {
final View child = children[i];
if ((child.mViewFlags & DUPLICATE_PARENT_STATE) != 0) {
child.drawableHotspotChanged(x, y);
}
}
}
}
@Override
protected int[] onCreateDrawableState(int extraSpace) {
if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) == 0) {

View File

@@ -20,6 +20,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.TransitionDrawable;
@@ -611,6 +612,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
private final int[] mScrollOffset = new int[2];
private final int[] mScrollConsumed = new int[2];
private final float[] mTmpPoint = new float[2];
// Used for offsetting MotionEvents that we feed to the VelocityTracker.
// In the future it would be nice to be able to give this to the VelocityTracker
// directly, or alternatively put a VT into absolute-positioning mode that only
@@ -2509,38 +2512,29 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
* Positions the selector in a way that mimics touch.
*/
void positionSelectorLikeTouch(int position, View sel, float x, float y) {
positionSelectorLikeFocus(position, sel);
if (mSelector != null && position != INVALID_POSITION) {
mSelector.setHotspot(x, y);
}
positionSelector(position, sel, true, x, y);
}
/**
* Positions the selector in a way that mimics keyboard focus.
*/
void positionSelectorLikeFocus(int position, View sel) {
// If we're changing position, update the visibility since the selector
// is technically being detached from the previous selection.
final Drawable selector = mSelector;
final boolean manageState = selector != null && mSelectorPosition != position
&& position != INVALID_POSITION;
if (manageState) {
selector.setVisible(false, false);
}
positionSelector(position, sel);
if (manageState) {
if (mSelector != null && mSelectorPosition != position && position != INVALID_POSITION) {
final Rect bounds = mSelectorRect;
final float x = bounds.exactCenterX();
final float y = bounds.exactCenterY();
selector.setVisible(getVisibility() == VISIBLE, false);
selector.setHotspot(x, y);
positionSelector(position, sel, true, x, y);
} else {
positionSelector(position, sel);
}
}
void positionSelector(int position, View sel) {
positionSelector(position, sel, false, -1, -1);
}
private void positionSelector(int position, View sel, boolean manageHotspot, float x, float y) {
final boolean positionChanged = position != mSelectorPosition;
if (position != INVALID_POSITION) {
mSelectorPosition = position;
}
@@ -2560,7 +2554,22 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
// Update the selector drawable.
final Drawable selector = mSelector;
if (selector != null) {
if (positionChanged) {
// Wipe out the current selector state so that we can start
// over in the new position with a fresh state.
selector.setVisible(false, false);
selector.setState(StateSet.NOTHING);
}
selector.setBounds(selectorRect);
if (positionChanged) {
if (getVisibility() == VISIBLE) {
selector.setVisible(true, false);
}
selector.setState(getDrawableState());
}
if (manageHotspot) {
selector.setHotspot(x, y);
}
}
final boolean isChildViewEnabled = mIsChildViewEnabled;
@@ -3198,6 +3207,12 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
// get the selector in the right state, but we don't want to press each child.
}
@Override
public void dispatchDrawableHotspotChanged(float x, float y) {
// Don't dispatch hotspot changes to children. We'll manually handle
// calling drawableHotspotChanged on the correct child.
}
/**
* Maps a point to a position in the list.
*
@@ -3256,6 +3271,11 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
mLayoutMode = LAYOUT_NORMAL;
if (!mDataChanged) {
final float[] point = mTmpPoint;
point[0] = x;
point[1] = y;
transformPointToViewLocal(point, child);
child.drawableHotspotChanged(point[0], point[1]);
child.setPressed(true);
setPressed(true);
layoutChildren();
@@ -3756,10 +3776,10 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
// Otherwise, check containment within list bounds. If we're
// outside bounds, cancel any active presses.
final View motionView = getChildAt(mMotionPosition - mFirstPosition);
final float x = ev.getX(pointerIndex);
if (!pointInView(x, y, mTouchSlop)) {
setPressed(false);
final View motionView = getChildAt(mMotionPosition - mFirstPosition);
if (motionView != null) {
motionView.setPressed(false);
}
@@ -3767,6 +3787,13 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
mPendingCheckForTap : mPendingCheckForLongPress);
mTouchMode = TOUCH_MODE_DONE_WAITING;
updateSelectorState();
} else if (motionView != null) {
// Still within bounds, update the hotspot.
final float[] point = mTmpPoint;
point[0] = x;
point[1] = y;
transformPointToViewLocal(point, motionView);
motionView.drawableHotspotChanged(point[0], point[1]);
}
break;
case TOUCH_MODE_SCROLL:
@@ -6416,6 +6443,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
// Note: We do place AdapterView.ITEM_VIEW_TYPE_IGNORE in active views.
// However, we will NOT place them into scrap views.
activeViews[i] = child;
// Remember the position so that setupChild() doesn't reset state.
lp.scrappedFromPosition = firstActivePosition + i;
}
}
}

View File

@@ -556,11 +556,13 @@ public class RippleDrawable extends LayerDrawable {
if (mRipple != null) {
mRipple.cancel();
mRipple = null;
mRippleActive = false;
}
if (mBackground != null) {
mBackground.cancel();
mBackground = null;
mBackgroundActive = false;
}
cancelExitingRipples();