This source file includes following definitions.
- overScrollContainerViewBy
- scrollContainerViewTo
- scrollNativeTo
- getContainerViewScrollX
- getContainerViewScrollY
- invalidate
- computeHorizontalScrollRange
- computeMaximumHorizontalScrollOffset
- computeHorizontalScrollOffset
- computeVerticalScrollRange
- computeMaximumVerticalScrollOffset
- computeVerticalScrollOffset
- computeVerticalScrollExtent
- setMaxScrollOffset
- setContainerViewSize
- syncScrollOffsetFromOnDraw
- setProcessingTouchEvent
- scrollContainerViewTo
- isFlingActive
- overScrollBy
- scrollBy
- clampHorizontalScroll
- clampVerticalScroll
- onContainerViewOverScrolled
- onContainerViewScrollChanged
- scrollNativeTo
- onFlingCancelGesture
- onUnhandledFlingStartEvent
- flingScroll
- computeScrollAndAbsorbGlow
- computeDurationInMilliSec
- animateScrollTo
- pageUp
- pageDown
- requestChildRectangleOnScreen
package org.chromium.android_webview;
import android.graphics.Rect;
import android.widget.OverScroller;
import com.google.common.annotations.VisibleForTesting;
@VisibleForTesting
public class AwScrollOffsetManager {
private static final int PAGE_SCROLL_OVERLAP = 24;
private static final int STD_SCROLL_ANIMATION_SPEED_PIX_PER_SEC = 480;
private static final int MAX_SCROLL_ANIMATION_DURATION_MILLISEC = 750;
public interface Delegate {
void overScrollContainerViewBy(int deltaX, int deltaY, int scrollX, int scrollY,
int scrollRangeX, int scrollRangeY, boolean isTouchEvent);
void scrollContainerViewTo(int x, int y);
void scrollNativeTo(int x, int y);
int getContainerViewScrollX();
int getContainerViewScrollY();
void invalidate();
}
private final Delegate mDelegate;
private int mNativeScrollX;
private int mNativeScrollY;
private int mMaxHorizontalScrollOffset;
private int mMaxVerticalScrollOffset;
private int mContainerViewWidth;
private int mContainerViewHeight;
private boolean mProcessingTouchEvent;
private boolean mWasFlinging;
private boolean mApplyDeferredNativeScroll;
private int mDeferredNativeScrollX;
private int mDeferredNativeScrollY;
private OverScroller mScroller;
public AwScrollOffsetManager(Delegate delegate, OverScroller overScroller) {
mDelegate = delegate;
mScroller = overScroller;
}
public int computeHorizontalScrollRange() {
return mContainerViewWidth + mMaxHorizontalScrollOffset;
}
public int computeMaximumHorizontalScrollOffset() {
return mMaxHorizontalScrollOffset;
}
public int computeHorizontalScrollOffset() {
return mDelegate.getContainerViewScrollX();
}
public int computeVerticalScrollRange() {
return mContainerViewHeight + mMaxVerticalScrollOffset;
}
public int computeMaximumVerticalScrollOffset() {
return mMaxVerticalScrollOffset;
}
public int computeVerticalScrollOffset() {
return mDelegate.getContainerViewScrollY();
}
public int computeVerticalScrollExtent() {
return mContainerViewHeight;
}
public void setMaxScrollOffset(int width, int height) {
mMaxHorizontalScrollOffset = width;
mMaxVerticalScrollOffset = height;
}
public void setContainerViewSize(int width, int height) {
mContainerViewWidth = width;
mContainerViewHeight = height;
}
public void syncScrollOffsetFromOnDraw() {
onContainerViewScrollChanged(mDelegate.getContainerViewScrollX(),
mDelegate.getContainerViewScrollY());
}
public void setProcessingTouchEvent(boolean processingTouchEvent) {
assert mProcessingTouchEvent != processingTouchEvent;
mProcessingTouchEvent = processingTouchEvent;
if (!mProcessingTouchEvent && mApplyDeferredNativeScroll) {
mApplyDeferredNativeScroll = false;
scrollNativeTo(mDeferredNativeScrollX, mDeferredNativeScrollY);
}
}
public void scrollContainerViewTo(int x, int y) {
mNativeScrollX = x;
mNativeScrollY = y;
final int scrollX = mDelegate.getContainerViewScrollX();
final int scrollY = mDelegate.getContainerViewScrollY();
final int deltaX = x - scrollX;
final int deltaY = y - scrollY;
final int scrollRangeX = computeMaximumHorizontalScrollOffset();
final int scrollRangeY = computeMaximumVerticalScrollOffset();
mDelegate.overScrollContainerViewBy(deltaX, deltaY, scrollX, scrollY,
scrollRangeX, scrollRangeY, mProcessingTouchEvent);
}
public boolean isFlingActive() {
boolean flinging = mScroller.computeScrollOffset();
mWasFlinging |= flinging;
return flinging;
}
public void overScrollBy(int deltaX, int deltaY) {
scrollBy(deltaX, deltaY);
}
private void scrollBy(int deltaX, int deltaY) {
if (deltaX == 0 && deltaY == 0) return;
final int scrollX = mDelegate.getContainerViewScrollX();
final int scrollY = mDelegate.getContainerViewScrollY();
final int scrollRangeX = computeMaximumHorizontalScrollOffset();
final int scrollRangeY = computeMaximumVerticalScrollOffset();
mDelegate.overScrollContainerViewBy(deltaX, deltaY, scrollX, scrollY,
scrollRangeX, scrollRangeY, mProcessingTouchEvent);
}
private int clampHorizontalScroll(int scrollX) {
scrollX = Math.max(0, scrollX);
scrollX = Math.min(computeMaximumHorizontalScrollOffset(), scrollX);
return scrollX;
}
private int clampVerticalScroll(int scrollY) {
scrollY = Math.max(0, scrollY);
scrollY = Math.min(computeMaximumVerticalScrollOffset(), scrollY);
return scrollY;
}
public void onContainerViewOverScrolled(int scrollX, int scrollY, boolean clampedX,
boolean clampedY) {
scrollX = clampHorizontalScroll(scrollX);
scrollY = clampVerticalScroll(scrollY);
mDelegate.scrollContainerViewTo(scrollX, scrollY);
scrollNativeTo(mDelegate.getContainerViewScrollX(), mDelegate.getContainerViewScrollY());
}
public void onContainerViewScrollChanged(int x, int y) {
scrollNativeTo(x, y);
}
private void scrollNativeTo(int x, int y) {
x = clampHorizontalScroll(x);
y = clampVerticalScroll(y);
if (mProcessingTouchEvent) {
mDeferredNativeScrollX = x;
mDeferredNativeScrollY = y;
mApplyDeferredNativeScroll = true;
return;
}
if (x == mNativeScrollX && y == mNativeScrollY)
return;
mNativeScrollX = x;
mNativeScrollY = y;
mDelegate.scrollNativeTo(x, y);
}
public void onFlingCancelGesture() {
mScroller.forceFinished(true);
}
public void onUnhandledFlingStartEvent(int velocityX, int velocityY) {
flingScroll(-velocityX, -velocityY);
}
public void flingScroll(int velocityX, int velocityY) {
final int scrollX = mDelegate.getContainerViewScrollX();
final int scrollY = mDelegate.getContainerViewScrollY();
final int scrollRangeX = computeMaximumHorizontalScrollOffset();
final int scrollRangeY = computeMaximumVerticalScrollOffset();
mScroller.fling(scrollX, scrollY, velocityX, velocityY,
0, scrollRangeX, 0, scrollRangeY);
mDelegate.invalidate();
}
public void computeScrollAndAbsorbGlow(OverScrollGlow overScrollGlow) {
if (!mScroller.computeScrollOffset() && !mWasFlinging) {
return;
}
mWasFlinging = false;
final int oldX = mDelegate.getContainerViewScrollX();
final int oldY = mDelegate.getContainerViewScrollY();
int x = mScroller.getCurrX();
int y = mScroller.getCurrY();
final int scrollRangeX = computeMaximumHorizontalScrollOffset();
final int scrollRangeY = computeMaximumVerticalScrollOffset();
if (overScrollGlow != null) {
overScrollGlow.absorbGlow(x, y, oldX, oldY, scrollRangeX, scrollRangeY,
mScroller.getCurrVelocity());
}
scrollBy(x - oldX, y - oldY);
mDelegate.invalidate();
}
private static int computeDurationInMilliSec(int dx, int dy) {
int distance = Math.max(Math.abs(dx), Math.abs(dy));
int duration = distance * 1000 / STD_SCROLL_ANIMATION_SPEED_PIX_PER_SEC;
return Math.min(duration, MAX_SCROLL_ANIMATION_DURATION_MILLISEC);
}
private boolean animateScrollTo(int x, int y) {
final int scrollX = mDelegate.getContainerViewScrollX();
final int scrollY = mDelegate.getContainerViewScrollY();
x = clampHorizontalScroll(x);
y = clampVerticalScroll(y);
int dx = x - scrollX;
int dy = y - scrollY;
if (dx == 0 && dy == 0)
return false;
mScroller.startScroll(scrollX, scrollY, dx, dy, computeDurationInMilliSec(dx, dy));
mDelegate.invalidate();
return true;
}
public boolean pageUp(boolean top) {
final int scrollX = mDelegate.getContainerViewScrollX();
final int scrollY = mDelegate.getContainerViewScrollY();
if (top) {
return animateScrollTo(scrollX, 0);
}
int dy = -mContainerViewHeight / 2;
if (mContainerViewHeight > 2 * PAGE_SCROLL_OVERLAP) {
dy = -mContainerViewHeight + PAGE_SCROLL_OVERLAP;
}
return animateScrollTo(scrollX, scrollY + dy);
}
public boolean pageDown(boolean bottom) {
final int scrollX = mDelegate.getContainerViewScrollX();
final int scrollY = mDelegate.getContainerViewScrollY();
if (bottom) {
return animateScrollTo(scrollX, computeVerticalScrollRange());
}
int dy = mContainerViewHeight / 2;
if (mContainerViewHeight > 2 * PAGE_SCROLL_OVERLAP) {
dy = mContainerViewHeight - PAGE_SCROLL_OVERLAP;
}
return animateScrollTo(scrollX, scrollY + dy);
}
public boolean requestChildRectangleOnScreen(int childOffsetX, int childOffsetY, Rect rect,
boolean immediate) {
final int scrollX = mDelegate.getContainerViewScrollX();
final int scrollY = mDelegate.getContainerViewScrollY();
rect.offset(childOffsetX, childOffsetY);
int screenTop = scrollY;
int screenBottom = scrollY + mContainerViewHeight;
int scrollYDelta = 0;
if (rect.bottom > screenBottom) {
int oneThirdOfScreenHeight = mContainerViewHeight / 3;
if (rect.width() > 2 * oneThirdOfScreenHeight) {
scrollYDelta = rect.top - screenTop;
} else {
scrollYDelta = rect.top - (screenTop + oneThirdOfScreenHeight);
}
} else if (rect.top < screenTop) {
scrollYDelta = rect.top - screenTop;
}
int screenLeft = scrollX;
int screenRight = scrollX + mContainerViewWidth;
int scrollXDelta = 0;
if (rect.right > screenRight && rect.left > screenLeft) {
if (rect.width() > mContainerViewWidth) {
scrollXDelta += (rect.left - screenLeft);
} else {
scrollXDelta += (rect.right - screenRight);
}
} else if (rect.left < screenLeft) {
scrollXDelta -= (screenLeft - rect.left);
}
if (scrollYDelta == 0 && scrollXDelta == 0) {
return false;
}
if (immediate) {
scrollBy(scrollXDelta, scrollYDelta);
return true;
} else {
return animateScrollTo(scrollX + scrollXDelta, scrollY + scrollYDelta);
}
}
}