Merge change 6813 into donut
* changes: Fixes #1972421. Prevents crash in ScrollView/HorizontalScrollView.
This commit is contained in:
@@ -31,6 +31,7 @@ import java.io.DataInputStream;
|
|||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A gesture can have a single or multiple strokes
|
* A gesture can have a single or multiple strokes
|
||||||
@@ -44,7 +45,7 @@ public class Gesture implements Parcelable {
|
|||||||
private static final boolean BITMAP_RENDERING_ANTIALIAS = true;
|
private static final boolean BITMAP_RENDERING_ANTIALIAS = true;
|
||||||
private static final boolean BITMAP_RENDERING_DITHER = true;
|
private static final boolean BITMAP_RENDERING_DITHER = true;
|
||||||
|
|
||||||
private static int sGestureCount = 0;
|
private static final AtomicInteger sGestureCount = new AtomicInteger(0);
|
||||||
|
|
||||||
private final RectF mBoundingBox = new RectF();
|
private final RectF mBoundingBox = new RectF();
|
||||||
|
|
||||||
@@ -54,7 +55,7 @@ public class Gesture implements Parcelable {
|
|||||||
private final ArrayList<GestureStroke> mStrokes = new ArrayList<GestureStroke>();
|
private final ArrayList<GestureStroke> mStrokes = new ArrayList<GestureStroke>();
|
||||||
|
|
||||||
public Gesture() {
|
public Gesture() {
|
||||||
mGestureID = GESTURE_ID_BASE + sGestureCount++;
|
mGestureID = GESTURE_ID_BASE + sGestureCount.incrementAndGet();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -286,18 +286,20 @@ public class HorizontalScrollView extends FrameLayout {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final View child = getChildAt(0);
|
if (getChildCount() > 0) {
|
||||||
int width = getMeasuredWidth();
|
final View child = getChildAt(0);
|
||||||
if (child.getMeasuredWidth() < width) {
|
int width = getMeasuredWidth();
|
||||||
final FrameLayout.LayoutParams lp = (LayoutParams) child.getLayoutParams();
|
if (child.getMeasuredWidth() < width) {
|
||||||
|
final FrameLayout.LayoutParams lp = (LayoutParams) child.getLayoutParams();
|
||||||
int childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec, mPaddingTop
|
|
||||||
+ mPaddingBottom, lp.height);
|
int childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec, mPaddingTop
|
||||||
width -= mPaddingLeft;
|
+ mPaddingBottom, lp.height);
|
||||||
width -= mPaddingRight;
|
width -= mPaddingLeft;
|
||||||
int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
|
width -= mPaddingRight;
|
||||||
|
int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
|
||||||
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
|
|
||||||
|
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -636,7 +638,7 @@ public class HorizontalScrollView extends FrameLayout {
|
|||||||
mTempRect.left = getScrollX() + width;
|
mTempRect.left = getScrollX() + width;
|
||||||
int count = getChildCount();
|
int count = getChildCount();
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
View view = getChildAt(count - 1);
|
View view = getChildAt(0);
|
||||||
if (mTempRect.left + width > view.getRight()) {
|
if (mTempRect.left + width > view.getRight()) {
|
||||||
mTempRect.left = view.getRight() - width;
|
mTempRect.left = view.getRight() - width;
|
||||||
}
|
}
|
||||||
@@ -674,7 +676,7 @@ public class HorizontalScrollView extends FrameLayout {
|
|||||||
if (right) {
|
if (right) {
|
||||||
int count = getChildCount();
|
int count = getChildCount();
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
View view = getChildAt(count - 1);
|
View view = getChildAt(0);
|
||||||
mTempRect.right = view.getRight();
|
mTempRect.right = view.getRight();
|
||||||
mTempRect.left = mTempRect.right - width;
|
mTempRect.left = mTempRect.right - width;
|
||||||
}
|
}
|
||||||
@@ -751,9 +753,9 @@ public class HorizontalScrollView extends FrameLayout {
|
|||||||
|
|
||||||
if (direction == View.FOCUS_LEFT && getScrollX() < scrollDelta) {
|
if (direction == View.FOCUS_LEFT && getScrollX() < scrollDelta) {
|
||||||
scrollDelta = getScrollX();
|
scrollDelta = getScrollX();
|
||||||
} else if (direction == View.FOCUS_RIGHT) {
|
} else if (direction == View.FOCUS_RIGHT && getChildCount() > 0) {
|
||||||
|
|
||||||
int daRight = getChildAt(getChildCount() - 1).getRight();
|
int daRight = getChildAt(0).getRight();
|
||||||
|
|
||||||
int screenRight = getScrollX() + getWidth();
|
int screenRight = getScrollX() + getWidth();
|
||||||
|
|
||||||
@@ -975,6 +977,7 @@ public class HorizontalScrollView extends FrameLayout {
|
|||||||
* @return The scroll delta.
|
* @return The scroll delta.
|
||||||
*/
|
*/
|
||||||
protected int computeScrollDeltaToGetChildRectOnScreen(Rect rect) {
|
protected int computeScrollDeltaToGetChildRectOnScreen(Rect rect) {
|
||||||
|
if (getChildCount() == 0) return 0;
|
||||||
|
|
||||||
int width = getWidth();
|
int width = getWidth();
|
||||||
int screenLeft = getScrollX();
|
int screenLeft = getScrollX();
|
||||||
@@ -1008,7 +1011,7 @@ public class HorizontalScrollView extends FrameLayout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// make sure we aren't scrolling beyond the end of our content
|
// make sure we aren't scrolling beyond the end of our content
|
||||||
int right = getChildAt(getChildCount() - 1).getRight();
|
int right = getChildAt(0).getRight();
|
||||||
int distanceToRight = right - screenRight;
|
int distanceToRight = right - screenRight;
|
||||||
scrollXDelta = Math.min(scrollXDelta, distanceToRight);
|
scrollXDelta = Math.min(scrollXDelta, distanceToRight);
|
||||||
|
|
||||||
@@ -1148,27 +1151,29 @@ public class HorizontalScrollView extends FrameLayout {
|
|||||||
* which means we want to scroll towards the left.
|
* which means we want to scroll towards the left.
|
||||||
*/
|
*/
|
||||||
public void fling(int velocityX) {
|
public void fling(int velocityX) {
|
||||||
int width = getWidth() - mPaddingRight - mPaddingLeft;
|
if (getChildCount() > 0) {
|
||||||
int right = getChildAt(0).getWidth();
|
int width = getWidth() - mPaddingRight - mPaddingLeft;
|
||||||
|
int right = getChildAt(0).getWidth();
|
||||||
mScroller.fling(mScrollX, mScrollY, velocityX, 0, 0, right - width, 0, 0);
|
|
||||||
|
mScroller.fling(mScrollX, mScrollY, velocityX, 0, 0, right - width, 0, 0);
|
||||||
final boolean movingRight = velocityX > 0;
|
|
||||||
|
final boolean movingRight = velocityX > 0;
|
||||||
View newFocused = findFocusableViewInMyBounds(movingRight,
|
|
||||||
mScroller.getFinalX(), findFocus());
|
View newFocused = findFocusableViewInMyBounds(movingRight,
|
||||||
|
mScroller.getFinalX(), findFocus());
|
||||||
if (newFocused == null) {
|
|
||||||
newFocused = this;
|
if (newFocused == null) {
|
||||||
|
newFocused = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newFocused != findFocus()
|
||||||
|
&& newFocused.requestFocus(movingRight ? View.FOCUS_RIGHT : View.FOCUS_LEFT)) {
|
||||||
|
mScrollViewMovedFocus = true;
|
||||||
|
mScrollViewMovedFocus = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newFocused != findFocus()
|
|
||||||
&& newFocused.requestFocus(movingRight ? View.FOCUS_RIGHT : View.FOCUS_LEFT)) {
|
|
||||||
mScrollViewMovedFocus = true;
|
|
||||||
mScrollViewMovedFocus = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
invalidate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -20,8 +20,6 @@ import android.content.Context;
|
|||||||
import android.content.res.TypedArray;
|
import android.content.res.TypedArray;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.util.Config;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.view.FocusFinder;
|
import android.view.FocusFinder;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
@@ -54,7 +52,6 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public class ScrollView extends FrameLayout {
|
public class ScrollView extends FrameLayout {
|
||||||
static final String TAG = "ScrollView";
|
static final String TAG = "ScrollView";
|
||||||
static final boolean localLOGV = false || Config.LOGV;
|
|
||||||
|
|
||||||
static final int ANIMATED_SCROLL_GAP = 250;
|
static final int ANIMATED_SCROLL_GAP = 250;
|
||||||
|
|
||||||
@@ -287,18 +284,21 @@ public class ScrollView extends FrameLayout {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final View child = getChildAt(0);
|
if (getChildCount() > 0) {
|
||||||
int height = getMeasuredHeight();
|
final View child = getChildAt(0);
|
||||||
if (child.getMeasuredHeight() < height) {
|
int height = getMeasuredHeight();
|
||||||
final FrameLayout.LayoutParams lp = (LayoutParams) child.getLayoutParams();
|
if (child.getMeasuredHeight() < height) {
|
||||||
|
final FrameLayout.LayoutParams lp = (LayoutParams) child.getLayoutParams();
|
||||||
int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec, mPaddingLeft
|
|
||||||
+ mPaddingRight, lp.width);
|
int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec, mPaddingLeft
|
||||||
height -= mPaddingTop;
|
+ mPaddingRight, lp.width);
|
||||||
height -= mPaddingBottom;
|
height -= mPaddingTop;
|
||||||
int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
|
height -= mPaddingBottom;
|
||||||
|
int childHeightMeasureSpec =
|
||||||
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
|
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
|
||||||
|
|
||||||
|
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -756,13 +756,14 @@ public class ScrollView extends FrameLayout {
|
|||||||
if (direction == View.FOCUS_UP && getScrollY() < scrollDelta) {
|
if (direction == View.FOCUS_UP && getScrollY() < scrollDelta) {
|
||||||
scrollDelta = getScrollY();
|
scrollDelta = getScrollY();
|
||||||
} else if (direction == View.FOCUS_DOWN) {
|
} else if (direction == View.FOCUS_DOWN) {
|
||||||
|
if (getChildCount() > 0) {
|
||||||
int daBottom = getChildAt(getChildCount() - 1).getBottom();
|
int daBottom = getChildAt(0).getBottom();
|
||||||
|
|
||||||
int screenBottom = getScrollY() + getHeight();
|
int screenBottom = getScrollY() + getHeight();
|
||||||
|
|
||||||
if (daBottom - screenBottom < maxJump) {
|
if (daBottom - screenBottom < maxJump) {
|
||||||
scrollDelta = daBottom - screenBottom;
|
scrollDelta = daBottom - screenBottom;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (scrollDelta == 0) {
|
if (scrollDelta == 0) {
|
||||||
@@ -830,16 +831,12 @@ public class ScrollView extends FrameLayout {
|
|||||||
public final void smoothScrollBy(int dx, int dy) {
|
public final void smoothScrollBy(int dx, int dy) {
|
||||||
long duration = AnimationUtils.currentAnimationTimeMillis() - mLastScroll;
|
long duration = AnimationUtils.currentAnimationTimeMillis() - mLastScroll;
|
||||||
if (duration > ANIMATED_SCROLL_GAP) {
|
if (duration > ANIMATED_SCROLL_GAP) {
|
||||||
if (localLOGV) Log.v(TAG, "Smooth scroll: mScrollY=" + mScrollY
|
|
||||||
+ " dy=" + dy);
|
|
||||||
mScroller.startScroll(mScrollX, mScrollY, dx, dy);
|
mScroller.startScroll(mScrollX, mScrollY, dx, dy);
|
||||||
invalidate();
|
invalidate();
|
||||||
} else {
|
} else {
|
||||||
if (!mScroller.isFinished()) {
|
if (!mScroller.isFinished()) {
|
||||||
mScroller.abortAnimation();
|
mScroller.abortAnimation();
|
||||||
}
|
}
|
||||||
if (localLOGV) Log.v(TAG, "Immediate scroll: mScrollY=" + mScrollY
|
|
||||||
+ " dy=" + dy);
|
|
||||||
scrollBy(dx, dy);
|
scrollBy(dx, dy);
|
||||||
}
|
}
|
||||||
mLastScroll = AnimationUtils.currentAnimationTimeMillis();
|
mLastScroll = AnimationUtils.currentAnimationTimeMillis();
|
||||||
@@ -922,9 +919,6 @@ public class ScrollView extends FrameLayout {
|
|||||||
View child = getChildAt(0);
|
View child = getChildAt(0);
|
||||||
mScrollX = clamp(x, getWidth() - mPaddingRight - mPaddingLeft, child.getWidth());
|
mScrollX = clamp(x, getWidth() - mPaddingRight - mPaddingLeft, child.getWidth());
|
||||||
mScrollY = clamp(y, getHeight() - mPaddingBottom - mPaddingTop, child.getHeight());
|
mScrollY = clamp(y, getHeight() - mPaddingBottom - mPaddingTop, child.getHeight());
|
||||||
if (localLOGV) Log.v(TAG, "mScrollY=" + mScrollY + " y=" + y
|
|
||||||
+ " height=" + this.getHeight()
|
|
||||||
+ " child height=" + child.getHeight());
|
|
||||||
} else {
|
} else {
|
||||||
mScrollX = x;
|
mScrollX = x;
|
||||||
mScrollY = y;
|
mScrollY = y;
|
||||||
@@ -986,6 +980,7 @@ public class ScrollView extends FrameLayout {
|
|||||||
* @return The scroll delta.
|
* @return The scroll delta.
|
||||||
*/
|
*/
|
||||||
protected int computeScrollDeltaToGetChildRectOnScreen(Rect rect) {
|
protected int computeScrollDeltaToGetChildRectOnScreen(Rect rect) {
|
||||||
|
if (getChildCount() == 0) return 0;
|
||||||
|
|
||||||
int height = getHeight();
|
int height = getHeight();
|
||||||
int screenTop = getScrollY();
|
int screenTop = getScrollY();
|
||||||
@@ -1005,9 +1000,6 @@ public class ScrollView extends FrameLayout {
|
|||||||
|
|
||||||
int scrollYDelta = 0;
|
int scrollYDelta = 0;
|
||||||
|
|
||||||
if (localLOGV) Log.v(TAG, "child=" + rect.toShortString()
|
|
||||||
+ " screenTop=" + screenTop + " screenBottom=" + screenBottom
|
|
||||||
+ " height=" + height);
|
|
||||||
if (rect.bottom > screenBottom && rect.top > screenTop) {
|
if (rect.bottom > screenBottom && rect.top > screenTop) {
|
||||||
// need to move down to get it in view: move down just enough so
|
// need to move down to get it in view: move down just enough so
|
||||||
// that the entire rectangle is in view (or at least the first
|
// that the entire rectangle is in view (or at least the first
|
||||||
@@ -1022,10 +1014,8 @@ public class ScrollView extends FrameLayout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// make sure we aren't scrolling beyond the end of our content
|
// make sure we aren't scrolling beyond the end of our content
|
||||||
int bottom = getChildAt(getChildCount() - 1).getBottom();
|
int bottom = getChildAt(0).getBottom();
|
||||||
int distanceToBottom = bottom - screenBottom;
|
int distanceToBottom = bottom - screenBottom;
|
||||||
if (localLOGV) Log.v(TAG, "scrollYDelta=" + scrollYDelta
|
|
||||||
+ " distanceToBottom=" + distanceToBottom);
|
|
||||||
scrollYDelta = Math.min(scrollYDelta, distanceToBottom);
|
scrollYDelta = Math.min(scrollYDelta, distanceToBottom);
|
||||||
|
|
||||||
} else if (rect.top < screenTop && rect.bottom < screenBottom) {
|
} else if (rect.top < screenTop && rect.bottom < screenBottom) {
|
||||||
@@ -1164,26 +1154,28 @@ public class ScrollView extends FrameLayout {
|
|||||||
* which means we want to scroll towards the top.
|
* which means we want to scroll towards the top.
|
||||||
*/
|
*/
|
||||||
public void fling(int velocityY) {
|
public void fling(int velocityY) {
|
||||||
int height = getHeight() - mPaddingBottom - mPaddingTop;
|
if (getChildCount() > 0) {
|
||||||
int bottom = getChildAt(0).getHeight();
|
int height = getHeight() - mPaddingBottom - mPaddingTop;
|
||||||
|
int bottom = getChildAt(0).getHeight();
|
||||||
mScroller.fling(mScrollX, mScrollY, 0, velocityY, 0, 0, 0, bottom - height);
|
|
||||||
|
mScroller.fling(mScrollX, mScrollY, 0, velocityY, 0, 0, 0, bottom - height);
|
||||||
final boolean movingDown = velocityY > 0;
|
|
||||||
|
final boolean movingDown = velocityY > 0;
|
||||||
View newFocused =
|
|
||||||
findFocusableViewInMyBounds(movingDown, mScroller.getFinalY(), findFocus());
|
View newFocused =
|
||||||
if (newFocused == null) {
|
findFocusableViewInMyBounds(movingDown, mScroller.getFinalY(), findFocus());
|
||||||
newFocused = this;
|
if (newFocused == null) {
|
||||||
|
newFocused = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newFocused != findFocus()
|
||||||
|
&& newFocused.requestFocus(movingDown ? View.FOCUS_DOWN : View.FOCUS_UP)) {
|
||||||
|
mScrollViewMovedFocus = true;
|
||||||
|
mScrollViewMovedFocus = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newFocused != findFocus()
|
|
||||||
&& newFocused.requestFocus(movingDown ? View.FOCUS_DOWN : View.FOCUS_UP)) {
|
|
||||||
mScrollViewMovedFocus = true;
|
|
||||||
mScrollViewMovedFocus = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
invalidate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user