summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorAdam Cohen <adamcohen@google.com>2010-08-19 16:49:52 -0700
committerAdam Cohen <adamcohen@google.com>2010-08-25 13:16:14 -0700
commit9b073948cfb84c0dd04f8a94ee1f7f263f027c83 (patch)
tree40a111e61be846c7eee74b9843f8a5f8b183a6bc /core
parent3c1fbf7ad2766a2942c326abd6692286949aee2f (diff)
downloadframeworks_base-9b073948cfb84c0dd04f8a94ee1f7f263f027c83.zip
frameworks_base-9b073948cfb84c0dd04f8a94ee1f7f263f027c83.tar.gz
frameworks_base-9b073948cfb84c0dd04f8a94ee1f7f263f027c83.tar.bz2
Cleanup and bug fixes in StackView
-> pushed functionality from AdapterViewAnimator to StackView -> only modifying clipping flags as far up the view hierarchy as needed -> still need framework level solution for drawing outside bounds ViewGroup touch dispatch temp fix -> Touch event was being modified and not reset in some code paths. Change-Id: I8135b62e2d73f239b9df407b0fa93bc434796989
Diffstat (limited to 'core')
-rw-r--r--core/java/android/view/ViewGroup.java14
-rw-r--r--core/java/android/widget/AdapterViewAnimator.java112
-rw-r--r--core/java/android/widget/StackView.java297
3 files changed, 238 insertions, 185 deletions
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 3678684..9770313 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -970,7 +970,12 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
mMotionTarget = null;
}
- return target.dispatchTouchEvent(ev);
+ if (target.dispatchTouchEvent(ev)) {
+ return true;
+ } else {
+ ev.setLocation(xf, yf);
+ }
+ return false;
}
/**
@@ -1006,7 +1011,12 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
// There are many subtle interactions in touch event dispatch; change at your own risk.
child.mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;
ev.offsetLocation(localX - x, localY - y);
- return child.dispatchTouchEvent(ev);
+ if (child.dispatchTouchEvent(ev)) {
+ return true;
+ } else {
+ ev.offsetLocation(x - localX, y - localY);
+ return false;
+ }
}
return false;
}
diff --git a/core/java/android/widget/AdapterViewAnimator.java b/core/java/android/widget/AdapterViewAnimator.java
index b6c8e47..e78c8b7 100644
--- a/core/java/android/widget/AdapterViewAnimator.java
+++ b/core/java/android/widget/AdapterViewAnimator.java
@@ -23,6 +23,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.res.TypedArray;
import android.graphics.Rect;
+import android.graphics.RectF;
import android.os.Handler;
import android.os.Looper;
import android.os.Parcel;
@@ -323,15 +324,13 @@ public abstract class AdapterViewAnimator extends AdapterView<Adapter>
return null;
}
- private LayoutParams createOrReuseLayoutParams(View v) {
+ LayoutParams createOrReuseLayoutParams(View v) {
final ViewGroup.LayoutParams currentLp = v.getLayoutParams();
- if (currentLp instanceof LayoutParams) {
+ if (currentLp instanceof ViewGroup.LayoutParams) {
LayoutParams lp = (LayoutParams) currentLp;
- lp.setHorizontalOffset(0);
- lp.setVerticalOffset(0);
return lp;
}
- return new LayoutParams(v);
+ return new ViewGroup.LayoutParams(0, 0);
}
void showOnly(int childIndex, boolean animate, boolean onLayout) {
@@ -472,10 +471,9 @@ public abstract class AdapterViewAnimator extends AdapterView<Adapter>
int childRight = mPaddingLeft + child.getMeasuredWidth();
int childBottom = mPaddingTop + child.getMeasuredHeight();
- LayoutParams lp = (LayoutParams) child.getLayoutParams();
- child.layout(mPaddingLeft + lp.horizontalOffset, mPaddingTop + lp.verticalOffset,
- childRight + lp.horizontalOffset, childBottom + lp.verticalOffset);
+ child.layout(mPaddingLeft, mPaddingTop,
+ childRight, childBottom);
}
mDataChanged = false;
}
@@ -738,102 +736,4 @@ public abstract class AdapterViewAnimator extends AdapterView<Adapter>
setAdapter(mRemoteViewsAdapter);
}
}
-
- private final Rect dirtyRect = new Rect();
- @Override
- public void removeViewInLayout(View view) {
- // TODO: need to investigate this block a bit more
- // and perhaps fix some other invalidations issues.
- View parent = null;
- view.setVisibility(INVISIBLE);
- if (view.getLayoutParams() instanceof LayoutParams) {
- LayoutParams lp = (LayoutParams) view.getLayoutParams();
- parent = lp.getParentAndDirtyRegion(dirtyRect);
- }
-
- super.removeViewInLayout(view);
-
- if (parent != null)
- parent.invalidate(dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom);
- }
-
- static class LayoutParams extends ViewGroup.LayoutParams {
- int horizontalOffset;
- int verticalOffset;
- View mView;
-
- LayoutParams(View view) {
- super(0, 0);
- horizontalOffset = 0;
- verticalOffset = 0;
- mView = view;
- }
-
- LayoutParams(Context c, AttributeSet attrs) {
- super(c, attrs);
- horizontalOffset = 0;
- verticalOffset = 0;
- }
-
- private Rect parentRect = new Rect();
- void invalidateGlobalRegion(View v, Rect r) {
- View p = v;
- boolean firstPass = true;
- parentRect.set(0, 0, 0, 0);
- while (p.getParent() != null && p.getParent() instanceof View
- && !parentRect.contains(r)) {
- if (!firstPass) r.offset(p.getLeft() - p.getScrollX(), p.getTop() - p.getScrollY());
- firstPass = false;
- p = (View) p.getParent();
- parentRect.set(p.getLeft() - p.getScrollX(), p.getTop() - p.getScrollY(),
- p.getRight() - p.getScrollX(), p.getBottom() - p.getScrollY());
- }
- p.invalidate(r.left, r.top, r.right, r.bottom);
- }
-
- public View getParentAndDirtyRegion(Rect globalRect) {
- globalRect.set(mView.getLeft(), mView.getTop(), mView.getRight(), mView.getBottom());
- View p = mView;
- boolean firstPass = true;
- parentRect.set(0, 0, 0, 0);
- while (p.getParent() != null && p.getParent() instanceof View
- && !parentRect.contains(globalRect)) {
- if (!firstPass) {
- globalRect.offset(p.getLeft() - p.getScrollX(), p.getTop() - p.getScrollY());
- }
-
- firstPass = false;
- p = (View) p.getParent();
- parentRect.set(p.getLeft() - p.getScrollX(), p.getTop() - p.getScrollY(),
- p.getRight() - p.getScrollX(), p.getBottom() - p.getScrollY());
- }
- return p;
- }
-
- private Rect invalidateRect = new Rect();
- // This is public so that PropertyAnimator can access it
- public void setVerticalOffset(int newVerticalOffset) {
- int offsetDelta = newVerticalOffset - verticalOffset;
- verticalOffset = newVerticalOffset;
- if (mView != null) {
- mView.requestLayout();
- int top = Math.min(mView.getTop() + offsetDelta, mView.getTop());
- int bottom = Math.max(mView.getBottom() + offsetDelta, mView.getBottom());
- invalidateRect.set(mView.getLeft(), top, mView.getRight(), bottom);
- invalidateGlobalRegion(mView, invalidateRect);
- }
- }
-
- public void setHorizontalOffset(int newHorizontalOffset) {
- int offsetDelta = newHorizontalOffset - horizontalOffset;
- horizontalOffset = newHorizontalOffset;
- if (mView != null) {
- mView.requestLayout();
- int left = Math.min(mView.getLeft() + offsetDelta, mView.getLeft());
- int right = Math.max(mView.getRight() + offsetDelta, mView.getRight());
- invalidateRect.set(left, mView.getTop(), right, mView.getBottom());
- invalidateGlobalRegion(mView, invalidateRect);
- }
- }
- }
}
diff --git a/core/java/android/widget/StackView.java b/core/java/android/widget/StackView.java
index c3e8838..b460adb 100644
--- a/core/java/android/widget/StackView.java
+++ b/core/java/android/widget/StackView.java
@@ -27,6 +27,7 @@ import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
+import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
@@ -66,8 +67,6 @@ public class StackView extends AdapterViewAnimator {
private static final float SLIDE_UP_RATIO = 0.7f;
private final WeakHashMap<View, Float> mRotations = new WeakHashMap<View, Float>();
- private final WeakHashMap<View, Integer>
- mChildrenToApplyTransformsTo = new WeakHashMap<View, Integer>();
/**
* Sentinel value for no current active pointer.
@@ -90,9 +89,12 @@ public class StackView extends AdapterViewAnimator {
private int mMaximumVelocity;
private VelocityTracker mVelocityTracker;
+ private static HolographicHelper sHolographicHelper;
private ImageView mHighlight;
private StackSlider mStackSlider;
private boolean mFirstLayoutHappened = false;
+ private ViewGroup mAncestorContainingAllChildren = null;
+ private int mAncestorHeight = 0;
public StackView(Context context) {
super(context);
@@ -117,9 +119,11 @@ public class StackView extends AdapterViewAnimator {
addViewInLayout(mHighlight, -1, new LayoutParams(mHighlight));
mStackSlider = new StackSlider();
- if (!sPaintsInitialized) {
- initializePaints();
+ if (sHolographicHelper == null) {
+ sHolographicHelper = new HolographicHelper();
}
+ setClipChildren(false);
+ setClipToPadding(false);
}
/**
@@ -205,6 +209,7 @@ public class StackView extends AdapterViewAnimator {
if (!mRotations.containsKey(child)) {
float rotation = (float) (Math.random()*26 - 13);
mRotations.put(child, rotation);
+ child.setRotation(rotation);
}
// Child has been removed
@@ -212,47 +217,36 @@ public class StackView extends AdapterViewAnimator {
if (mRotations.containsKey(child)) {
mRotations.remove(child);
}
- if (mChildrenToApplyTransformsTo.containsKey(child)) {
- mChildrenToApplyTransformsTo.remove(child);
- }
}
-
- // if this view is already in the layout, we need to
- // wait until layout has finished in order to set the
- // pivot point of the rotation (requiring getMeasuredWidth/Height())
- mChildrenToApplyTransformsTo.put(child, relativeIndex);
}
@Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- super.onLayout(changed, left, top, right, bottom);
-
- if (!mChildrenToApplyTransformsTo.isEmpty()) {
- for (View child: mChildrenToApplyTransformsTo.keySet()) {
- if (mRotations.containsKey(child)) {
- child.setPivotX(child.getMeasuredWidth()/2);
- child.setPivotY(child.getMeasuredHeight()/2);
- child.setRotation(mRotations.get(child));
- }
+ protected void dispatchDraw(Canvas canvas) {
+ super.dispatchDraw(canvas);
+ }
+
+ // TODO: right now, this code walks up the hierarchy as far as needed and disables clipping
+ // so that the stack's children can draw outside of the stack's bounds. This is fine within
+ // the context of widgets in the launcher, but is destructive in general, as the clipping
+ // values are not being reset. For this to be a full framework level widget, we will need
+ // framework level support for drawing outside of a parent's bounds.
+ private void disableParentalClipping() {
+ if (mAncestorContainingAllChildren != null) {
+ Log.v(TAG, "Disabling parental clipping.");
+ ViewGroup vg = this;
+ while (vg.getParent() != null && vg.getParent() instanceof ViewGroup) {
+ if (vg == mAncestorContainingAllChildren) break;
+ vg = (ViewGroup) vg.getParent();
+ vg.setClipChildren(false);
+ vg.setClipToPadding(false);
}
- mChildrenToApplyTransformsTo.clear();
}
+ }
+ private void onLayout() {
if (!mFirstLayoutHappened) {
mViewHeight = Math.round(SLIDE_UP_RATIO*getMeasuredHeight());
mSwipeThreshold = Math.round(SWIPE_THRESHOLD_RATIO*mViewHeight);
-
- // TODO: Right now this walks all the way up the view hierarchy and disables
- // ClipChildren and ClipToPadding. We're probably going to want to reset
- // these flags as well.
- setClipChildren(false);
- setClipToPadding(false);
- ViewGroup view = this;
- while (view.getParent() != null && view.getParent() instanceof ViewGroup) {
- view = (ViewGroup) view.getParent();
- view.setClipChildren(false);
- view.setClipToPadding(false);
- }
mFirstLayoutHappened = true;
}
}
@@ -261,7 +255,6 @@ public class StackView extends AdapterViewAnimator {
public boolean onInterceptTouchEvent(MotionEvent ev) {
int action = ev.getAction();
switch(action & MotionEvent.ACTION_MASK) {
-
case MotionEvent.ACTION_DOWN: {
if (mActivePointerId == INVALID_POINTER) {
mInitialX = ev.getX();
@@ -320,7 +313,7 @@ public class StackView extends AdapterViewAnimator {
View v = getViewAtRelativeIndex(activeIndex);
if (v == null) return;
- mHighlight.setImageBitmap(createOutline(v));
+ mHighlight.setImageBitmap(sHolographicHelper.createOutline(v));
mHighlight.bringToFront();
v.bringToFront();
mStackSlider.setView(v);
@@ -640,7 +633,6 @@ public class StackView extends AdapterViewAnimator {
float getXProgress() {
return mXProgress;
}
-
}
@Override
@@ -649,55 +641,206 @@ public class StackView extends AdapterViewAnimator {
setDisplayedChild(mWhichChild);
}
- private static final Paint sHolographicPaint = new Paint();
- private static final Paint sErasePaint = new Paint();
- private static boolean sPaintsInitialized = false;
- private static final float STROKE_WIDTH = 3.0f;
-
- static void initializePaints() {
- sHolographicPaint.setColor(0xff6699ff);
- sHolographicPaint.setFilterBitmap(true);
- sErasePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
- sErasePaint.setFilterBitmap(true);
- sPaintsInitialized = true;
+ LayoutParams createOrReuseLayoutParams(View v) {
+ final ViewGroup.LayoutParams currentLp = v.getLayoutParams();
+ if (currentLp instanceof LayoutParams) {
+ LayoutParams lp = (LayoutParams) currentLp;
+ lp.setHorizontalOffset(0);
+ lp.setVerticalOffset(0);
+ return lp;
+ }
+ return new LayoutParams(v);
}
- static Bitmap createOutline(View v) {
- if (v.getMeasuredWidth() == 0 || v.getMeasuredHeight() == 0) {
- return null;
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ boolean dataChanged = mDataChanged;
+ if (dataChanged) {
+ handleDataChanged();
+
+ // if the data changes, mWhichChild might be out of the bounds of the adapter
+ // in this case, we reset mWhichChild to the beginning
+ if (mWhichChild >= mAdapter.getCount())
+ mWhichChild = 0;
+
+ showOnly(mWhichChild, true, true);
+ }
+
+ final int childCount = getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ final View child = getChildAt(i);
+
+ int childRight = mPaddingLeft + child.getMeasuredWidth();
+ int childBottom = mPaddingTop + child.getMeasuredHeight();
+ LayoutParams lp = (LayoutParams) child.getLayoutParams();
+
+ child.layout(mPaddingLeft + lp.horizontalOffset, mPaddingTop + lp.verticalOffset,
+ childRight + lp.horizontalOffset, childBottom + lp.verticalOffset);
+
+ //TODO: temp until fix in View
+ child.setPivotX(child.getMeasuredWidth()/2);
+ child.setPivotY(child.getMeasuredHeight()/2);
+ }
+
+ mDataChanged = false;
+ onLayout();
+ }
+
+ class LayoutParams extends ViewGroup.LayoutParams {
+ int horizontalOffset;
+ int verticalOffset;
+ View mView;
+
+ LayoutParams(View view) {
+ super(0, 0);
+ horizontalOffset = 0;
+ verticalOffset = 0;
+ mView = view;
+ }
+
+ LayoutParams(Context c, AttributeSet attrs) {
+ super(c, attrs);
+ horizontalOffset = 0;
+ verticalOffset = 0;
}
- Bitmap bitmap = Bitmap.createBitmap(v.getMeasuredWidth(), v.getMeasuredHeight(),
- Bitmap.Config.ARGB_8888);
- Canvas canvas = new Canvas(bitmap);
+ private Rect parentRect = new Rect();
+ void invalidateGlobalRegion(View v, Rect r) {
+ View p = v;
+ if (!(v.getParent() != null && v.getParent() instanceof View)) return;
+
+ View gp = (View) v.getParent();
+ boolean firstPass = true;
+ parentRect.set(0, 0, 0, 0);
+ int depth = 0;
+ while (gp.getParent() != null && gp.getParent() instanceof View
+ && !parentRect.contains(r)) {
+ if (!firstPass) {
+ r.offset(p.getLeft() - gp.getScrollX(), p.getTop() - gp.getScrollY());
+ depth++;
+ }
+ firstPass = false;
+ p = (View) p.getParent();
+ gp = (View) p.getParent();
+ parentRect.set(p.getLeft() - gp.getScrollX(), p.getTop() - gp.getScrollY(),
+ p.getRight() - gp.getScrollX(), p.getBottom() - gp.getScrollY());
+ }
+
+ if (depth > mAncestorHeight) {
+ mAncestorContainingAllChildren = (ViewGroup) p;
+ mAncestorHeight = depth;
+ disableParentalClipping();
+ }
+
+ p.invalidate(r.left, r.top, r.right, r.bottom);
+ }
- float rotationX = v.getRotationX();
- v.setRotationX(0);
- canvas.concat(v.getMatrix());
- v.draw(canvas);
- v.setRotationX(rotationX);
+ private Rect invalidateRect = new Rect();
+ private RectF invalidateRectf = new RectF();
+ // This is public so that PropertyAnimator can access it
+ public void setVerticalOffset(int newVerticalOffset) {
+ int offsetDelta = newVerticalOffset - verticalOffset;
+ verticalOffset = newVerticalOffset;
- Bitmap outlineBitmap = Bitmap.createBitmap(v.getMeasuredWidth(), v.getMeasuredHeight(),
- Bitmap.Config.ARGB_8888);
- Canvas outlineCanvas = new Canvas(outlineBitmap);
- drawOutline(outlineCanvas, bitmap);
- bitmap.recycle();
- return outlineBitmap;
+ if (mView != null) {
+ mView.requestLayout();
+ int top = Math.min(mView.getTop() + offsetDelta, mView.getTop());
+ int bottom = Math.max(mView.getBottom() + offsetDelta, mView.getBottom());
+
+ invalidateRectf.set(mView.getLeft(), top, mView.getRight(), bottom);
+
+ float xoffset = -invalidateRectf.left;
+ float yoffset = -invalidateRectf.top;
+ invalidateRectf.offset(xoffset, yoffset);
+ mView.getMatrix().mapRect(invalidateRectf);
+ invalidateRectf.offset(-xoffset, -yoffset);
+ invalidateRect.set((int) Math.floor(invalidateRectf.left),
+ (int) Math.floor(invalidateRectf.top),
+ (int) Math.ceil(invalidateRectf.right),
+ (int) Math.ceil(invalidateRectf.bottom));
+
+ invalidateGlobalRegion(mView, invalidateRect);
+ }
+ }
+
+ public void setHorizontalOffset(int newHorizontalOffset) {
+ int offsetDelta = newHorizontalOffset - horizontalOffset;
+ horizontalOffset = newHorizontalOffset;
+
+ if (mView != null) {
+ mView.requestLayout();
+ int left = Math.min(mView.getLeft() + offsetDelta, mView.getLeft());
+ int right = Math.max(mView.getRight() + offsetDelta, mView.getRight());
+ invalidateRectf.set(left, mView.getTop(), right, mView.getBottom());
+
+ float xoffset = -invalidateRectf.left;
+ float yoffset = -invalidateRectf.top;
+ invalidateRectf.offset(xoffset, yoffset);
+ mView.getMatrix().mapRect(invalidateRectf);
+ invalidateRectf.offset(-xoffset, -yoffset);
+
+ invalidateRect.set((int) Math.floor(invalidateRectf.left),
+ (int) Math.floor(invalidateRectf.top),
+ (int) Math.ceil(invalidateRectf.right),
+ (int) Math.ceil(invalidateRectf.bottom));
+
+ invalidateGlobalRegion(mView, invalidateRect);
+ }
+ }
}
- static void drawOutline(Canvas dest, Bitmap src) {
- dest.drawColor(0, PorterDuff.Mode.CLEAR);
+ private static class HolographicHelper {
+ private final Paint mHolographicPaint = new Paint();
+ private final Paint mErasePaint = new Paint();
+ private final float STROKE_WIDTH = 3.0f;
- Bitmap mask = src.extractAlpha();
- Matrix id = new Matrix();
+ HolographicHelper() {
+ initializePaints();
+ }
+
+ void initializePaints() {
+ mHolographicPaint.setColor(0xff6699ff);
+ mHolographicPaint.setFilterBitmap(true);
+ mErasePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
+ mErasePaint.setFilterBitmap(true);
+ }
+
+ Bitmap createOutline(View v) {
+ if (v.getMeasuredWidth() == 0 || v.getMeasuredHeight() == 0) {
+ return null;
+ }
+
+ Bitmap bitmap = Bitmap.createBitmap(v.getMeasuredWidth(), v.getMeasuredHeight(),
+ Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(bitmap);
- Matrix m = new Matrix();
- float xScale = STROKE_WIDTH*2/(src.getWidth());
- float yScale = STROKE_WIDTH*2/(src.getHeight());
- m.preScale(1+xScale, 1+yScale, src.getWidth()/2, src.getHeight()/2);
- dest.drawBitmap(mask, m, sHolographicPaint);
+ float rotationX = v.getRotationX();
+ v.setRotationX(0);
+ canvas.concat(v.getMatrix());
+ v.draw(canvas);
- dest.drawBitmap(src, id, sErasePaint);
- mask.recycle();
+ v.setRotationX(rotationX);
+
+ drawOutline(canvas, bitmap);
+ return bitmap;
+ }
+
+ final Matrix id = new Matrix();
+ final Matrix scaleMatrix = new Matrix();
+ void drawOutline(Canvas dest, Bitmap src) {
+ Bitmap mask = src.extractAlpha();
+
+ dest.drawColor(0, PorterDuff.Mode.CLEAR);
+
+ float xScale = STROKE_WIDTH*2/(dest.getWidth());
+ float yScale = STROKE_WIDTH*2/(dest.getHeight());
+
+ scaleMatrix.reset();
+ scaleMatrix.preScale(1+xScale, 1+yScale, dest.getWidth()/2, dest.getHeight()/2);
+ dest.setMatrix(id);
+ dest.drawBitmap(mask, scaleMatrix, mHolographicPaint);
+ dest.drawBitmap(mask, id, mErasePaint);
+ mask.recycle();
+ }
}
}