Methods Summary |
---|
protected void | acceleratedOverScroll(float amount)
int screenSize = getViewportWidth();
// We want to reach the max over scroll effect when the user has
// over scrolled half the size of the screen
float f = OVERSCROLL_ACCELERATE_FACTOR * (amount / screenSize);
if (f == 0) return;
// Clamp this factor, f, to -1 < f < 1
if (Math.abs(f) >= 1) {
f /= Math.abs(f);
}
int overScrollAmount = (int) Math.round(f * screenSize);
if (amount < 0) {
mOverScrollX = overScrollAmount;
super.scrollTo(0, getScrollY());
} else {
mOverScrollX = mMaxScrollX + overScrollAmount;
super.scrollTo(mMaxScrollX, getScrollY());
}
invalidate();
|
private void | acquireVelocityTrackerAndAddMovement(MotionEvent ev)
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
}
mVelocityTracker.addMovement(ev);
|
public void | addFocusables(java.util.ArrayList views, int direction, int focusableMode)
if (mCurrentPage >= 0 && mCurrentPage < getPageCount()) {
getPageAt(mCurrentPage).addFocusables(views, direction, focusableMode);
}
if (direction == View.FOCUS_LEFT) {
if (mCurrentPage > 0) {
getPageAt(mCurrentPage - 1).addFocusables(views, direction, focusableMode);
}
} else if (direction == View.FOCUS_RIGHT){
if (mCurrentPage < getPageCount() - 1) {
getPageAt(mCurrentPage + 1).addFocusables(views, direction, focusableMode);
}
}
|
void | animateDragViewToOriginalPosition()
if (mDragView != null) {
AnimatorSet anim = new AnimatorSet();
anim.setDuration(REORDERING_DROP_REPOSITION_DURATION);
anim.playTogether(
ObjectAnimator.ofFloat(mDragView, "translationX", 0f),
ObjectAnimator.ofFloat(mDragView, "translationY", 0f));
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
onPostReorderingAnimationCompleted();
}
});
anim.start();
}
|
private void | animateWarpPageOffScreen(java.lang.String reason, boolean animate)
if (DEBUG_WARP) Log.v(TAG, "animateWarpPageOffScreen(" + reason + " anim:" + animate + ")");
if (mWarpPageExposed) {
dispatchOnPageEndWarp();
KeyguardWidgetFrame v = (KeyguardWidgetFrame) getPageAt(getPageWarpIndex());
if (DEBUG_WARP) Log.v(TAG, "moving page off screen: Tx=" + v.getTranslationX());
AccelerateInterpolator interp = new AccelerateInterpolator(1.5f);
int totalOffset = getCurrentWarpOffset();
v.animate().translationX(totalOffset)
.setInterpolator(interp)
.setDuration(animate ? WARP_PEEK_ANIMATION_DURATION : 0)
.setListener(mOffScreenAnimationListener);
} else {
if (DEBUG_WARP) Log.e(TAG, "animateWarpPageOffScreen(): not warping", new Exception());
}
|
private void | animateWarpPageOnScreen(java.lang.String reason)
if (DEBUG_WARP) Log.v(TAG, "animateWarpPageOnScreen(" + reason + ")");
if (!mWarpPageExposed) {
mWarpPageExposed = true;
dispatchOnPageBeginWarp();
KeyguardWidgetFrame v = (KeyguardWidgetFrame) getPageAt(getPageWarpIndex());
if (DEBUG_WARP) Log.v(TAG, "moving page on screen: Tx=" + v.getTranslationX());
DecelerateInterpolator interp = new DecelerateInterpolator(1.5f);
int totalOffset = getCurrentWarpOffset();
v.setTranslationX(totalOffset);
mWarpAnimation = v.animate();
mWarpAnimation.translationX(mWarpPeekAmount+totalOffset)
.setInterpolator(interp)
.setDuration(WARP_PEEK_ANIMATION_DURATION)
.setListener(mOnScreenAnimationListener);
}
|
void | beginCameraEvent()
mIsCameraEvent = true;
|
void | boundByReorderablePages(boolean isReordering, int[] range)
// Do nothing
|
protected void | cancelScrollingIndicatorAnimations()
if (mScrollIndicatorAnimator != null) {
mScrollIndicatorAnimator.cancel();
}
|
private void | cancelWarpAnimation(java.lang.String msg, boolean abortAnimation)
if (DEBUG_WARP) Log.v(TAG, "cancelWarpAnimation(" + msg + ",abort=" + abortAnimation + ")");
if (abortAnimation) {
// We're done with the animation and moving to a new page. Let the scroller
// take over the animation.
KeyguardWidgetFrame v = (KeyguardWidgetFrame) getPageAt(getPageWarpIndex());
v.animate().cancel();
// Make the scroll amount match the current warp position.
scrollBy(Math.round(-v.getTranslationX()), 0);
v.setTranslationX(0);
} else {
animateWarpPageOffScreen("canceled", true);
}
|
public void | computeScroll()
computeScrollHelper();
|
protected boolean | computeScrollHelper()
if (mScroller.computeScrollOffset()) {
// Don't bother scrolling if the page does not need to be moved
if (getScrollX() != mScroller.getCurrX()
|| getScrollY() != mScroller.getCurrY()
|| mOverScrollX != mScroller.getCurrX()) {
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
}
invalidate();
return true;
} else if (mNextPage != INVALID_PAGE) {
mCurrentPage = Math.max(0, Math.min(mNextPage, getPageCount() - 1));
mNextPage = INVALID_PAGE;
notifyPageSwitched();
// We don't want to trigger a page end moving unless the page has settled
// and the user has stopped scrolling
if (mTouchState == TOUCH_STATE_REST) {
pageEndMoving();
}
onPostReorderingAnimationCompleted();
return true;
}
return false;
|
private java.lang.Runnable | createPostDeleteAnimationRunnable(View dragView)
return new Runnable() {
@Override
public void run() {
int dragViewIndex = indexOfChild(dragView);
// For each of the pages around the drag view, animate them from the previous
// position to the new position in the layout (as a result of the drag view moving
// in the layout)
// NOTE: We can make an assumption here because we have side-bound pages that we
// will always have pages to animate in from the left
getVisiblePages(mTempVisiblePagesRange);
boundByReorderablePages(true, mTempVisiblePagesRange);
boolean isLastWidgetPage = (mTempVisiblePagesRange[0] == mTempVisiblePagesRange[1]);
boolean slideFromLeft = (isLastWidgetPage ||
dragViewIndex > mTempVisiblePagesRange[0]);
// Setup the scroll to the correct page before we swap the views
if (slideFromLeft) {
snapToPageImmediately(dragViewIndex - 1);
}
int firstIndex = (isLastWidgetPage ? 0 : mTempVisiblePagesRange[0]);
int lastIndex = Math.min(mTempVisiblePagesRange[1], getPageCount() - 1);
int lowerIndex = (slideFromLeft ? firstIndex : dragViewIndex + 1 );
int upperIndex = (slideFromLeft ? dragViewIndex - 1 : lastIndex);
ArrayList<Animator> animations = new ArrayList<Animator>();
for (int i = lowerIndex; i <= upperIndex; ++i) {
View v = getChildAt(i);
// dragViewIndex < pageUnderPointIndex, so after we remove the
// drag view all subsequent views to pageUnderPointIndex will
// shift down.
int oldX = 0;
int newX = 0;
if (slideFromLeft) {
if (i == 0) {
// Simulate the page being offscreen with the page spacing
oldX = getViewportOffsetX() + getChildOffset(i) - getChildWidth(i)
- mPageSpacing;
} else {
oldX = getViewportOffsetX() + getChildOffset(i - 1);
}
newX = getViewportOffsetX() + getChildOffset(i);
} else {
oldX = getChildOffset(i) - getChildOffset(i - 1);
newX = 0;
}
// Animate the view translation from its old position to its new
// position
AnimatorSet anim = (AnimatorSet) v.getTag();
if (anim != null) {
anim.cancel();
}
// Note: Hacky, but we want to skip any optimizations to not draw completely
// hidden views
v.setAlpha(Math.max(v.getAlpha(), 0.01f));
v.setTranslationX(oldX - newX);
anim = new AnimatorSet();
anim.playTogether(
ObjectAnimator.ofFloat(v, "translationX", 0f),
ObjectAnimator.ofFloat(v, "alpha", 1f));
animations.add(anim);
v.setTag(anim);
}
AnimatorSet slideAnimations = new AnimatorSet();
slideAnimations.playTogether(animations);
slideAnimations.setDuration(DELETE_SLIDE_IN_SIDE_PAGE_DURATION);
slideAnimations.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
final Runnable onCompleteRunnable = new Runnable() {
@Override
public void run() {
mDeferringForDelete = false;
onEndReordering();
onRemoveViewAnimationCompleted();
}
};
zoomIn(onCompleteRunnable);
}
});
slideAnimations.start();
removeView(dragView);
onRemoveView(dragView, true);
}
};
|
protected void | dampedOverScroll(float amount)
int screenSize = getViewportWidth();
float f = (amount / screenSize);
if (f == 0) return;
f = f / (Math.abs(f)) * (overScrollInfluenceCurve(Math.abs(f)));
// Clamp this factor, f, to -1 < f < 1
if (Math.abs(f) >= 1) {
f /= Math.abs(f);
}
int overScrollAmount = (int) Math.round(OVERSCROLL_DAMP_FACTOR * f * screenSize);
if (amount < 0) {
mOverScrollX = overScrollAmount;
super.scrollTo(0, getScrollY());
} else {
mOverScrollX = mMaxScrollX + overScrollAmount;
super.scrollTo(mMaxScrollX, getScrollY());
}
invalidate();
|
protected boolean | determineScrollingStart(MotionEvent ev)
// Disallow scrolling if we don't have a valid pointer index
final int pointerIndex = ev.findPointerIndex(mActivePointerId);
if (pointerIndex == -1) return false;
// Disallow scrolling if we started the gesture from outside the viewport
final float x = ev.getX(pointerIndex);
final float y = ev.getY(pointerIndex);
if (!isTouchPointInViewportWithBuffer((int) x, (int) y)) return false;
// If we're only allowing edge swipes, we break out early if the down event wasn't
// at the edge.
if (mOnlyAllowEdgeSwipes && !mDownEventOnEdge) return false;
final int xDiff = (int) Math.abs(x - mLastMotionX);
final int touchSlop = Math.round(TOUCH_SLOP_SCALE * mTouchSlop);
boolean xPaged = xDiff > mPagingTouchSlop;
boolean xMoved = xDiff > touchSlop;
return mUsePagingTouchSlop ? xPaged : xMoved;
|
protected void | dispatchDraw(android.graphics.Canvas canvas)
int halfScreenSize = getViewportWidth() / 2;
// mOverScrollX is equal to getScrollX() when we're within the normal scroll range.
// Otherwise it is equal to the scaled overscroll position.
int screenCenter = mOverScrollX + halfScreenSize;
if (screenCenter != mLastScreenCenter || mForceScreenScrolled) {
// set mForceScreenScrolled before calling screenScrolled so that screenScrolled can
// set it for the next frame
mForceScreenScrolled = false;
screenScrolled(screenCenter);
mLastScreenCenter = screenCenter;
}
// Find out which screens are visible; as an optimization we only call draw on them
final int pageCount = getChildCount();
if (pageCount > 0) {
getVisiblePages(mTempVisiblePagesRange);
final int leftScreen = mTempVisiblePagesRange[0];
final int rightScreen = mTempVisiblePagesRange[1];
if (leftScreen != -1 && rightScreen != -1) {
final long drawingTime = getDrawingTime();
// Clip to the bounds
canvas.save();
canvas.clipRect(getScrollX(), getScrollY(), getScrollX() + getRight() - getLeft(),
getScrollY() + getBottom() - getTop());
// Draw all the children, leaving the drag view for last
for (int i = pageCount - 1; i >= 0; i--) {
final View v = getPageAt(i);
if (v == mDragView) continue;
if (mForceDrawAllChildrenNextFrame ||
(leftScreen <= i && i <= rightScreen && shouldDrawChild(v))) {
drawChild(canvas, v, drawingTime);
}
}
// Draw the drag view on top (if there is one)
if (mDragView != null) {
drawChild(canvas, mDragView, drawingTime);
}
mForceDrawAllChildrenNextFrame = false;
canvas.restore();
}
}
|
private void | dispatchOnPageBeginWarp()
if (!mOnPageBeginWarpCalled) {
onPageBeginWarp();
mOnPageBeginWarpCalled = true;
}
mOnPageEndWarpCalled = false;
|
private void | dispatchOnPageEndWarp()
if (!mOnPageEndWarpCalled) {
onPageEndWarp();
mOnPageEndWarpCalled = true;
}
mOnPageBeginWarpCalled = false;
|
public boolean | dispatchUnhandledMove(View focused, int direction)
if (direction == View.FOCUS_LEFT) {
if (getCurrentPage() > 0) {
snapToPage(getCurrentPage() - 1);
return true;
}
} else if (direction == View.FOCUS_RIGHT) {
if (getCurrentPage() < getPageCount() - 1) {
snapToPage(getCurrentPage() + 1);
return true;
}
}
return super.dispatchUnhandledMove(focused, direction);
|
float | distanceInfluenceForSnapDuration(float f)
f -= 0.5f; // center the values about 0.
f *= 0.3f * Math.PI / 2.0f;
return (float) Math.sin(f);
|
void | endCameraEvent()
mIsCameraEvent = false;
|
void | endReordering()
// For simplicity, we call endReordering sometimes even if reordering was never started.
// In that case, we don't want to do anything.
if (!mReorderingStarted) return;
mReorderingStarted = false;
// If we haven't flung-to-delete the current child, then we just animate the drag view
// back into position
final Runnable onCompleteRunnable = new Runnable() {
@Override
public void run() {
onEndReordering();
}
};
if (!mDeferringForDelete) {
mPostReorderingPreZoomInRunnable = new Runnable() {
public void run() {
zoomIn(onCompleteRunnable);
};
};
mPostReorderingPreZoomInRemainingAnimationCount =
NUM_ANIMATIONS_RUNNING_BEFORE_ZOOM_OUT;
// Snap to the current page
snapToPage(indexOfChild(mDragView), 0);
// Animate the drag view back to the front position
animateDragViewToOriginalPosition();
} else {
// Handled in post-delete-animation-callbacks
}
|
protected void | flashScrollingIndicator(boolean animated)
removeCallbacks(hideScrollingIndicatorRunnable);
showScrollingIndicator(!animated);
postDelayed(hideScrollingIndicatorRunnable, sScrollIndicatorFlashDuration);
|
public void | focusableViewAvailable(View focused)If one of our descendant views decides that it could be focused now, only
pass that along if it's on the current page.
This happens when live folders requery, and if they're off page, they
end up calling requestFocus, which pulls it on page.
View current = getPageAt(mCurrentPage);
View v = focused;
while (true) {
if (v == current) {
super.focusableViewAvailable(focused);
return;
}
if (v == this) {
return;
}
ViewParent parent = v.getParent();
if (parent instanceof View) {
v = (View)v.getParent();
} else {
return;
}
}
|
protected float | getBoundedScrollProgress(int screenCenter, View v, int page)
final int halfScreenSize = getViewportWidth() / 2;
screenCenter = Math.min(mScrollX + halfScreenSize, screenCenter);
screenCenter = Math.max(halfScreenSize, screenCenter);
return getScrollProgress(screenCenter, v, page);
|
protected int | getChildIndexForRelativeOffset(int relativeOffset)
final int childCount = getChildCount();
int left;
int right;
for (int i = 0; i < childCount; ++i) {
left = getRelativeChildOffset(i);
right = (left + getScaledMeasuredWidth(getPageAt(i)));
if (left <= relativeOffset && relativeOffset <= right) {
return i;
}
}
return -1;
|
protected int | getChildOffset(int index)
if (index < 0 || index > getChildCount() - 1) return 0;
int[] childOffsets = Float.compare(mLayoutScale, 1f) == 0 ?
mChildOffsets : mChildOffsetsWithLayoutScale;
if (childOffsets != null && childOffsets[index] != -1) {
return childOffsets[index];
} else {
if (getChildCount() == 0)
return 0;
int offset = getRelativeChildOffset(0);
for (int i = 0; i < index; ++i) {
offset += getScaledMeasuredWidth(getPageAt(i)) + mPageSpacing;
}
if (childOffsets != null) {
childOffsets[index] = offset;
}
return offset;
}
|
protected int | getChildWidth(int index)
// This functions are called enough times that it actually makes a difference in the
// profiler -- so just inline the max() here
final int measuredWidth = getPageAt(index).getMeasuredWidth();
final int minWidth = mMinimumWidth;
return (minWidth > measuredWidth) ? minWidth : measuredWidth;
|
int | getCurrentPage()Returns the index of the currently displayed page.
return mCurrentPage;
|
private int | getCurrentWarpOffset()
if (mCurrentPage == getPageWarpIndex()) {
return 0;
}
View viewRight = getPageAt(mCurrentPage + 1);
View warpView = getPageAt(getPageWarpIndex());
if (viewRight != warpView && viewRight != null && warpView != null) {
return viewRight.getLeft() - warpView.getLeft();
}
return 0;
|
protected float | getMaxScrollProgress()
return 1.0f;
|
int | getNextPage()
return (mNextPage != INVALID_PAGE) ? mNextPage : mCurrentPage;
|
View | getPageAt(int index)
return getChildAt(index);
|
int | getPageCount()
return getChildCount();
|
public int | getPageForView(View v)
int result = -1;
if (v != null) {
ViewParent vp = v.getParent();
int count = getChildCount();
for (int i = 0; i < count; i++) {
if (vp == getPageAt(i)) {
return i;
}
}
}
return result;
|
int | getPageNearestToCenterOfScreen()
int minDistanceFromScreenCenter = Integer.MAX_VALUE;
int minDistanceFromScreenCenterIndex = -1;
int screenCenter = getViewportOffsetX() + getScrollX() + (getViewportWidth() / 2);
final int childCount = getChildCount();
for (int i = 0; i < childCount; ++i) {
View layout = (View) getPageAt(i);
int childWidth = getScaledMeasuredWidth(layout);
int halfChildWidth = (childWidth / 2);
int childCenter = getViewportOffsetX() + getChildOffset(i) + halfChildWidth;
int distanceFromScreenCenter = Math.abs(childCenter - screenCenter);
if (distanceFromScreenCenter < minDistanceFromScreenCenter) {
minDistanceFromScreenCenter = distanceFromScreenCenter;
minDistanceFromScreenCenterIndex = i;
}
}
return minDistanceFromScreenCenterIndex;
|
int | getPageNearestToPoint(float x)
int index = 0;
for (int i = 0; i < getChildCount(); ++i) {
if (x < getChildAt(i).getRight() - getScrollX()) {
return index;
} else {
index++;
}
}
return Math.min(index, getChildCount() - 1);
|
private int | getPageSnapDuration()
return isWarping() ? WARP_SNAP_DURATION : PAGE_SNAP_ANIMATION_DURATION;
|
protected int | getPageWarpIndex()
return getPageCount() - 1;
|
protected int | getRelativeChildOffset(int index)
if (index < 0 || index > getChildCount() - 1) return 0;
if (mChildRelativeOffsets != null && mChildRelativeOffsets[index] != -1) {
return mChildRelativeOffsets[index];
} else {
final int padding = getPaddingLeft() + getPaddingRight();
final int offset = getPaddingLeft() +
(getViewportWidth() - padding - getChildWidth(index)) / 2;
if (mChildRelativeOffsets != null) {
mChildRelativeOffsets[index] = offset;
}
return offset;
}
|
protected int | getScaledMeasuredWidth(View child)
// This functions are called enough times that it actually makes a difference in the
// profiler -- so just inline the max() here
final int measuredWidth = child.getMeasuredWidth();
final int minWidth = mMinimumWidth;
final int maxWidth = (minWidth > measuredWidth) ? minWidth : measuredWidth;
return (int) (maxWidth * mLayoutScale + 0.5f);
|
protected float | getScrollProgress(int screenCenter, View v, int page)
final int halfScreenSize = getViewportWidth() / 2;
int totalDistance = getScaledMeasuredWidth(v) + mPageSpacing;
int delta = screenCenter - (getChildOffset(page) -
getRelativeChildOffset(page) + halfScreenSize);
float scrollProgress = delta / (totalDistance * 1.0f);
scrollProgress = Math.min(scrollProgress, getMaxScrollProgress());
scrollProgress = Math.max(scrollProgress, - getMaxScrollProgress());
return scrollProgress;
|
protected View | getScrollingIndicator()
return null;
|
int | getViewportHeight()
return mViewport.height();
|
int | getViewportOffsetX()
return (getMeasuredWidth() - getViewportWidth()) / 2;
|
int | getViewportOffsetY()
return (getMeasuredHeight() - getViewportHeight()) / 2;
|
int | getViewportWidth()
return mViewport.width();
|
protected void | getVisiblePages(int[] range)
range[0] = 0;
range[1] = getPageCount() - 1;
/*
final int pageCount = getChildCount();
if (pageCount > 0) {
final int screenWidth = getViewportWidth();
int leftScreen = 0;
int rightScreen = 0;
int offsetX = getViewportOffsetX() + getScrollX();
View currPage = getPageAt(leftScreen);
while (leftScreen < pageCount - 1 &&
currPage.getX() + currPage.getWidth() -
currPage.getPaddingRight() < offsetX) {
leftScreen++;
currPage = getPageAt(leftScreen);
}
rightScreen = leftScreen;
currPage = getPageAt(rightScreen + 1);
while (rightScreen < pageCount - 1 &&
currPage.getX() - currPage.getPaddingLeft() < offsetX + screenWidth) {
rightScreen++;
currPage = getPageAt(rightScreen + 1);
}
// TEMP: this is a hacky way to ensure that animations to new pages are not clipped
// because we don't draw them while scrolling?
range[0] = Math.max(0, leftScreen - 1);
range[1] = Math.min(rightScreen + 1, getChildCount() - 1);
} else {
range[0] = -1;
range[1] = -1;
}
*/
|
protected boolean | hasElasticScrollIndicator()To be overridden by subclasses to determine whether the scroll indicator should stretch to
fill its space on the track or not.
return true;
|
protected void | hideScrollingIndicator(boolean immediately)
if (getChildCount() <= 1) return;
if (!isScrollingIndicatorEnabled()) return;
getScrollingIndicator();
if (mScrollIndicator != null) {
// Fade the indicator out
updateScrollingIndicatorPosition();
cancelScrollingIndicatorAnimations();
if (immediately) {
mScrollIndicator.setVisibility(View.INVISIBLE);
mScrollIndicator.setAlpha(0f);
} else {
mScrollIndicatorAnimator = ObjectAnimator.ofFloat(mScrollIndicator, "alpha", 0f);
mScrollIndicatorAnimator.setDuration(sScrollIndicatorFadeOutDuration);
mScrollIndicatorAnimator.addListener(new AnimatorListenerAdapter() {
private boolean cancelled = false;
@Override
public void onAnimationCancel(android.animation.Animator animation) {
cancelled = true;
}
@Override
public void onAnimationEnd(Animator animation) {
if (!cancelled) {
mScrollIndicator.setVisibility(View.INVISIBLE);
}
}
});
mScrollIndicatorAnimator.start();
}
}
|
protected boolean | hitsNextPage(float x, float y)Return true if a tap at (x, y) should trigger a flip to the next page.
return (x > (getViewportOffsetX() + getViewportWidth() - getRelativeChildOffset(mCurrentPage) + mPageSpacing));
|
protected boolean | hitsPreviousPage(float x, float y)Return true if a tap at (x, y) should trigger a flip to the previous page.
return (x < getViewportOffsetX() + getRelativeChildOffset(mCurrentPage) - mPageSpacing);
|
protected int | indexToPage(int index)
return index;
|
protected void | init()Initializes various states for this workspace.
mDirtyPageContent = new ArrayList<Boolean>();
mDirtyPageContent.ensureCapacity(32);
mScroller = new Scroller(getContext(), new ScrollInterpolator());
mCurrentPage = 0;
final ViewConfiguration configuration = ViewConfiguration.get(getContext());
mTouchSlop = configuration.getScaledTouchSlop();
mPagingTouchSlop = configuration.getScaledPagingTouchSlop();
mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
mDensity = getResources().getDisplayMetrics().density;
mWarpPeekAmount = mDensity * WARP_ANIMATE_AMOUNT;
// Scale the fling-to-delete threshold by the density
mFlingToDeleteThresholdVelocity = (int) (mFlingToDeleteThresholdVelocity * mDensity);
mFlingThresholdVelocity = (int) (FLING_THRESHOLD_VELOCITY * mDensity);
mMinFlingVelocity = (int) (MIN_FLING_VELOCITY * mDensity);
mMinSnapVelocity = (int) (MIN_SNAP_VELOCITY * mDensity);
setOnHierarchyChangeListener(this);
|
protected void | invalidateCachedOffsets()
int count = getChildCount();
if (count == 0) {
mChildOffsets = null;
mChildRelativeOffsets = null;
mChildOffsetsWithLayoutScale = null;
return;
}
mChildOffsets = new int[count];
mChildRelativeOffsets = new int[count];
mChildOffsetsWithLayoutScale = new int[count];
for (int i = 0; i < count; i++) {
mChildOffsets[i] = -1;
mChildRelativeOffsets[i] = -1;
mChildOffsetsWithLayoutScale[i] = -1;
}
|
private boolean | isAnimatingWarpPage()
return mWarpAnimation != null;
|
protected boolean | isDataReady()
return mIsDataReady;
|
private android.graphics.PointF | isFlingingToDelete()
ViewConfiguration config = ViewConfiguration.get(getContext());
mVelocityTracker.computeCurrentVelocity(1000, config.getScaledMaximumFlingVelocity());
if (mVelocityTracker.getYVelocity() < mFlingToDeleteThresholdVelocity) {
// Do a quick dot product test to ensure that we are flinging upwards
PointF vel = new PointF(mVelocityTracker.getXVelocity(),
mVelocityTracker.getYVelocity());
PointF upVec = new PointF(0f, -1f);
float theta = (float) Math.acos(((vel.x * upVec.x) + (vel.y * upVec.y)) /
(vel.length() * upVec.length()));
if (theta <= Math.toRadians(FLING_TO_DELETE_MAX_FLING_DEGREES)) {
return vel;
}
}
return null;
|
private boolean | isHorizontalCameraScroll(MotionEvent ev)
// Disallow scrolling if we don't have a valid pointer index
final int pointerIndex = ev.findPointerIndex(mActivePointerId);
if (pointerIndex == -1) return false;
// If we're only allowing edge swipes, we break out early if the down event wasn't
// at the edge.
if (mOnlyAllowEdgeSwipes && !mDownEventOnEdge) return false;
final float x = ev.getX(pointerIndex);
final int xDiff = (int) Math.abs(x - mDownMotionX);
final int touchSlop = Math.round(TOUCH_SLOP_SCALE * mTouchSlop);
boolean xPaged = xDiff > mPagingTouchSlop;
boolean xMoved = xDiff > touchSlop;
return mIsCameraEvent && (mUsePagingTouchSlop ? xPaged : xMoved);
|
private boolean | isHoveringOverDeleteDropTarget(int x, int y)
if (mDeleteDropTarget != null) {
mAltTmpRect.set(0, 0, 0, 0);
View parent = (View) mDeleteDropTarget.getParent();
if (parent != null) {
parent.getGlobalVisibleRect(mAltTmpRect);
}
mDeleteDropTarget.getGlobalVisibleRect(mTmpRect);
mTmpRect.offset(-mAltTmpRect.left, -mAltTmpRect.top);
return mTmpRect.contains(x, y);
}
return false;
|
protected boolean | isPageMoving()
return mIsPageMoving;
|
boolean | isReordering(boolean testTouchState)
boolean state = mIsReordering;
if (testTouchState) {
state &= (mTouchState == TOUCH_STATE_REORDERING);
}
return state;
|
protected boolean | isScrollingIndicatorEnabled()
return false;
|
private boolean | isTouchPointInCurrentPage(int x, int y)Returns whether x and y originated within the current page view bounds
View v = getPageAt(getCurrentPage());
if (v != null) {
mTmpRect.set((v.getLeft() - getScrollX()), 0, (v.getRight() - getScrollX()),
v.getBottom());
return mTmpRect.contains(x, y);
}
return false;
|
private boolean | isTouchPointInViewportWithBuffer(int x, int y)Returns whether x and y originated within the buffered viewport
mTmpRect.set(mViewport.left - mViewport.width() / 2, mViewport.top,
mViewport.right + mViewport.width() / 2, mViewport.bottom);
return mTmpRect.contains(x, y);
|
protected boolean | isWarping()
return mWarpPageExposed;
|
float[] | mapPointFromParentToView(View v, float x, float y)
mTmpPoint[0] = x - v.getLeft();
mTmpPoint[1] = y - v.getTop();
v.getMatrix().invert(mTmpInvMatrix);
mTmpInvMatrix.mapPoints(mTmpPoint);
return mTmpPoint;
|
float[] | mapPointFromViewToParent(View v, float x, float y)
mTmpPoint[0] = x;
mTmpPoint[1] = y;
v.getMatrix().mapPoints(mTmpPoint);
mTmpPoint[0] += v.getLeft();
mTmpPoint[1] += v.getTop();
return mTmpPoint;
|
protected float | maxOverScroll()
// Using the formula in overScroll, assuming that f = 1.0 (which it should generally not
// exceed). Used to find out how much extra wallpaper we need for the over scroll effect
float f = 1.0f;
f = f / (Math.abs(f)) * (overScrollInfluenceCurve(Math.abs(f)));
return OVERSCROLL_DAMP_FACTOR * f;
|
protected void | notifyPageSwitched()
if (mPageSwitchListener != null) {
mPageSwitchListener.onPageSwitched(getPageAt(mCurrentPage), mCurrentPage);
}
|
protected void | notifyPageSwitching(int whichPage)
if (mPageSwitchListener != null) {
mPageSwitchListener.onPageSwitching(getPageAt(whichPage), whichPage);
}
|
public abstract void | onAddView(View v, int index)
|
public void | onChildViewAdded(View parent, View child)
// This ensures that when children are added, they get the correct transforms / alphas
// in accordance with any scroll effects.
mForceScreenScrolled = true;
invalidate();
invalidateCachedOffsets();
|
public void | onChildViewRemoved(View parent, View child)
mForceScreenScrolled = true;
invalidate();
invalidateCachedOffsets();
|
private void | onDropToDelete()
final View dragView = mDragView;
final float toScale = 0f;
final float toAlpha = 0f;
// Create and start the complex animation
ArrayList<Animator> animations = new ArrayList<Animator>();
AnimatorSet motionAnim = new AnimatorSet();
motionAnim.setInterpolator(new DecelerateInterpolator(2));
motionAnim.playTogether(
ObjectAnimator.ofFloat(dragView, "scaleX", toScale),
ObjectAnimator.ofFloat(dragView, "scaleY", toScale));
animations.add(motionAnim);
AnimatorSet alphaAnim = new AnimatorSet();
alphaAnim.setInterpolator(new LinearInterpolator());
alphaAnim.playTogether(
ObjectAnimator.ofFloat(dragView, "alpha", toAlpha));
animations.add(alphaAnim);
mDeleteString = getContext().getResources()
.getString(R.string.keyguard_accessibility_widget_deleted,
mDragView.getContentDescription());
final Runnable onAnimationEndRunnable = createPostDeleteAnimationRunnable(dragView);
AnimatorSet anim = new AnimatorSet();
anim.playTogether(animations);
anim.setDuration(DRAG_TO_DELETE_FADE_OUT_DURATION);
anim.addListener(new AnimatorListenerAdapter() {
public void onAnimationEnd(Animator animation) {
onAnimationEndRunnable.run();
}
});
anim.start();
mDeferringForDelete = true;
|
protected void | onEndReordering()
if (AccessibilityManager.getInstance(mContext).isEnabled()) {
if (mDeleteString != null) {
announceForAccessibility(mDeleteString);
mDeleteString = null;
} else {
announceForAccessibility(mContext.getString(
R.string.keyguard_accessibility_widget_reorder_end));
}
}
mIsReordering = false;
// Mark all the non-widget pages as visible again
getVisiblePages(mTempVisiblePagesRange);
boundByReorderablePages(true, mTempVisiblePagesRange);
for (int i = 0; i < getPageCount(); ++i) {
if (i < mTempVisiblePagesRange[0] || i > mTempVisiblePagesRange[1]) {
getPageAt(i).setAlpha(1f);
}
}
|
public void | onFlingToDelete(android.graphics.PointF vel)
final long startTime = AnimationUtils.currentAnimationTimeMillis();
// NOTE: Because it takes time for the first frame of animation to actually be
// called and we expect the animation to be a continuation of the fling, we have
// to account for the time that has elapsed since the fling finished. And since
// we don't have a startDelay, we will always get call to update when we call
// start() (which we want to ignore).
final TimeInterpolator tInterpolator = new TimeInterpolator() {
private int mCount = -1;
private long mStartTime;
private float mOffset;
/* Anonymous inner class ctor */ {
mStartTime = startTime;
}
@Override
public float getInterpolation(float t) {
if (mCount < 0) {
mCount++;
} else if (mCount == 0) {
mOffset = Math.min(0.5f, (float) (AnimationUtils.currentAnimationTimeMillis() -
mStartTime) / FLING_TO_DELETE_FADE_OUT_DURATION);
mCount++;
}
return Math.min(1f, mOffset + t);
}
};
final Rect from = new Rect();
final View dragView = mDragView;
from.left = (int) dragView.getTranslationX();
from.top = (int) dragView.getTranslationY();
AnimatorUpdateListener updateCb = new FlingAlongVectorAnimatorUpdateListener(dragView, vel,
from, startTime, FLING_TO_DELETE_FRICTION);
mDeleteString = getContext().getResources()
.getString(R.string.keyguard_accessibility_widget_deleted,
mDragView.getContentDescription());
final Runnable onAnimationEndRunnable = createPostDeleteAnimationRunnable(dragView);
// Create and start the animation
ValueAnimator mDropAnim = new ValueAnimator();
mDropAnim.setInterpolator(tInterpolator);
mDropAnim.setDuration(FLING_TO_DELETE_FADE_OUT_DURATION);
mDropAnim.setFloatValues(0f, 1f);
mDropAnim.addUpdateListener(updateCb);
mDropAnim.addListener(new AnimatorListenerAdapter() {
public void onAnimationEnd(Animator animation) {
onAnimationEndRunnable.run();
}
});
mDropAnim.start();
mDeferringForDelete = true;
|
public boolean | onGenericMotionEvent(MotionEvent event)
if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
switch (event.getAction()) {
case MotionEvent.ACTION_SCROLL: {
// Handle mouse (or ext. device) by shifting the page depending on the scroll
final float vscroll;
final float hscroll;
if ((event.getMetaState() & KeyEvent.META_SHIFT_ON) != 0) {
vscroll = 0;
hscroll = event.getAxisValue(MotionEvent.AXIS_VSCROLL);
} else {
vscroll = -event.getAxisValue(MotionEvent.AXIS_VSCROLL);
hscroll = event.getAxisValue(MotionEvent.AXIS_HSCROLL);
}
if (hscroll != 0 || vscroll != 0) {
if (hscroll > 0 || vscroll > 0) {
scrollRight();
} else {
scrollLeft();
}
return true;
}
}
}
}
return super.onGenericMotionEvent(event);
|
public boolean | onHoverEvent(android.view.MotionEvent event)
return true;
|
public void | onInitializeAccessibilityEvent(android.view.accessibility.AccessibilityEvent event)
super.onInitializeAccessibilityEvent(event);
event.setScrollable(true);
if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED) {
event.setFromIndex(mCurrentPage);
event.setToIndex(mCurrentPage);
event.setItemCount(getChildCount());
}
|
public void | onInitializeAccessibilityNodeInfo(android.view.accessibility.AccessibilityNodeInfo info)
super.onInitializeAccessibilityNodeInfo(info);
info.setScrollable(getPageCount() > 1);
if (getCurrentPage() < getPageCount() - 1) {
info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
}
if (getCurrentPage() > 0) {
info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
}
|
public boolean | onInterceptTouchEvent(MotionEvent ev)
if (DISABLE_TOUCH_INTERACTION) {
return false;
}
/*
* This method JUST determines whether we want to intercept the motion.
* If we return true, onTouchEvent will be called and we do the actual
* scrolling there.
*/
acquireVelocityTrackerAndAddMovement(ev);
// Skip touch handling if there are no pages to swipe
if (getChildCount() <= 0) return super.onInterceptTouchEvent(ev);
/*
* Shortcut the most recurring case: the user is in the dragging
* state and he is moving his finger. We want to intercept this
* motion.
*/
final int action = ev.getAction();
if ((action == MotionEvent.ACTION_MOVE) &&
(mTouchState == TOUCH_STATE_SCROLLING)) {
return true;
}
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_MOVE: {
/*
* mIsBeingDragged == false, otherwise the shortcut would have caught it. Check
* whether the user has moved far enough from his original down touch.
*/
if (mActivePointerId != INVALID_POINTER) {
if (mIsCameraEvent || determineScrollingStart(ev)) {
startScrolling(ev);
}
break;
}
// if mActivePointerId is INVALID_POINTER, then we must have missed an ACTION_DOWN
// event. in that case, treat the first occurence of a move event as a ACTION_DOWN
// i.e. fall through to the next case (don't break)
// (We sometimes miss ACTION_DOWN events in Workspace because it ignores all events
// while it's small- this was causing a crash before we checked for INVALID_POINTER)
break;
}
case MotionEvent.ACTION_DOWN: {
if (mIsCameraEvent) {
animateWarpPageOnScreen("interceptTouch(): DOWN");
}
// Remember where the motion event started
saveDownState(ev);
/*
* If being flinged and user touches the screen, initiate drag;
* otherwise don't. mScroller.isFinished should be false when
* being flinged.
*/
final int xDist = Math.abs(mScroller.getFinalX() - mScroller.getCurrX());
final boolean finishedScrolling = (mScroller.isFinished() || xDist < mTouchSlop);
if (finishedScrolling) {
setTouchState(TOUCH_STATE_REST);
mScroller.abortAnimation();
} else {
if (mIsCameraEvent || isTouchPointInViewportWithBuffer(
(int) mDownMotionX, (int) mDownMotionY)) {
setTouchState(TOUCH_STATE_SCROLLING);
} else {
setTouchState(TOUCH_STATE_REST);
}
}
// check if this can be the beginning of a tap on the side of the pages
// to scroll the current page
if (!DISABLE_TOUCH_SIDE_PAGES) {
if (mTouchState != TOUCH_STATE_PREV_PAGE
&& mTouchState != TOUCH_STATE_NEXT_PAGE) {
if (getChildCount() > 0) {
float x = ev.getX();
float y = ev.getY();
if (hitsPreviousPage(x, y)) {
setTouchState(TOUCH_STATE_PREV_PAGE);
} else if (hitsNextPage(x, y)) {
setTouchState(TOUCH_STATE_NEXT_PAGE);
}
}
}
}
break;
}
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
resetTouchState();
// Just intercept the touch event on up if we tap outside the strict viewport
if (!isTouchPointInCurrentPage((int) mLastMotionX, (int) mLastMotionY)) {
return true;
}
break;
case MotionEvent.ACTION_POINTER_UP:
onSecondaryPointerUp(ev);
releaseVelocityTracker();
break;
}
/*
* The only time we want to intercept motion events is if we are in the
* drag mode.
*/
return mTouchState != TOUCH_STATE_REST;
|
protected void | onLayout(boolean changed, int left, int top, int right, int bottom)
if (!mIsDataReady || getChildCount() == 0) {
return;
}
if (DEBUG) Log.d(TAG, "PagedView.onLayout()");
final int childCount = getChildCount();
int offsetX = getViewportOffsetX();
int offsetY = getViewportOffsetY();
// Update the viewport offsets
mViewport.offset(offsetX, offsetY);
int childLeft = offsetX + getRelativeChildOffset(0);
for (int i = 0; i < childCount; i++) {
final View child = getPageAt(i);
int childTop = offsetY + getPaddingTop();
if (child.getVisibility() != View.GONE) {
final int childWidth = getScaledMeasuredWidth(child);
final int childHeight = child.getMeasuredHeight();
if (DEBUG) Log.d(TAG, "\tlayout-child" + i + ": " + childLeft + ", " + childTop);
child.layout(childLeft, childTop,
childLeft + child.getMeasuredWidth(), childTop + childHeight);
childLeft += childWidth + mPageSpacing;
}
}
if (mFirstLayout && mCurrentPage >= 0 && mCurrentPage < getChildCount()) {
setHorizontalScrollBarEnabled(false);
updateCurrentPageScroll();
setHorizontalScrollBarEnabled(true);
mFirstLayout = false;
}
|
protected void | onMeasure(int widthMeasureSpec, int heightMeasureSpec)
if (!mIsDataReady || getChildCount() == 0) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
return;
}
// We measure the dimensions of the PagedView to be larger than the pages so that when we
// zoom out (and scale down), the view is still contained in the parent
View parent = (View) getParent();
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
// NOTE: We multiply by 1.5f to account for the fact that depending on the offset of the
// viewport, we can be at most one and a half screens offset once we scale down
DisplayMetrics dm = getResources().getDisplayMetrics();
int maxSize = Math.max(dm.widthPixels, dm.heightPixels);
int parentWidthSize = (int) (1.5f * maxSize);
int parentHeightSize = maxSize;
int scaledWidthSize = (int) (parentWidthSize / mMinScale);
int scaledHeightSize = (int) (parentHeightSize / mMinScale);
mViewport.set(0, 0, widthSize, heightSize);
if (widthMode == MeasureSpec.UNSPECIFIED || heightMode == MeasureSpec.UNSPECIFIED) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
return;
}
// Return early if we aren't given a proper dimension
if (widthSize <= 0 || heightSize <= 0) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
return;
}
/* Allow the height to be set as WRAP_CONTENT. This allows the particular case
* of the All apps view on XLarge displays to not take up more space then it needs. Width
* is still not allowed to be set as WRAP_CONTENT since many parts of the code expect
* each page to have the same width.
*/
final int verticalPadding = getPaddingTop() + getPaddingBottom();
final int horizontalPadding = getPaddingLeft() + getPaddingRight();
// The children are given the same width and height as the workspace
// unless they were set to WRAP_CONTENT
if (DEBUG) Log.d(TAG, "PagedView.onMeasure(): " + widthSize + ", " + heightSize);
if (DEBUG) Log.d(TAG, "PagedView.scaledSize: " + scaledWidthSize + ", " + scaledHeightSize);
if (DEBUG) Log.d(TAG, "PagedView.parentSize: " + parentWidthSize + ", " + parentHeightSize);
if (DEBUG) Log.d(TAG, "PagedView.horizontalPadding: " + horizontalPadding);
if (DEBUG) Log.d(TAG, "PagedView.verticalPadding: " + verticalPadding);
final int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
// disallowing padding in paged view (just pass 0)
final View child = getPageAt(i);
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
int childWidthMode;
if (lp.width == LayoutParams.WRAP_CONTENT) {
childWidthMode = MeasureSpec.AT_MOST;
} else {
childWidthMode = MeasureSpec.EXACTLY;
}
int childHeightMode;
if (lp.height == LayoutParams.WRAP_CONTENT) {
childHeightMode = MeasureSpec.AT_MOST;
} else {
childHeightMode = MeasureSpec.EXACTLY;
}
final int childWidthMeasureSpec =
MeasureSpec.makeMeasureSpec(widthSize - horizontalPadding, childWidthMode);
final int childHeightMeasureSpec =
MeasureSpec.makeMeasureSpec(heightSize - verticalPadding, childHeightMode);
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}
setMeasuredDimension(scaledWidthSize, scaledHeightSize);
// We can't call getChildOffset/getRelativeChildOffset until we set the measured dimensions.
// We also wait until we set the measured dimensions before flushing the cache as well, to
// ensure that the cache is filled with good values.
invalidateCachedOffsets();
if (mChildCountOnLastMeasure != getChildCount() && !mDeferringForDelete) {
setCurrentPage(mCurrentPage);
}
mChildCountOnLastMeasure = getChildCount();
if (childCount > 0) {
if (DEBUG) Log.d(TAG, "getRelativeChildOffset(): " + getViewportWidth() + ", "
+ getChildWidth(0));
// Calculate the variable page spacing if necessary
if (mPageSpacing == AUTOMATIC_PAGE_SPACING) {
// The gap between pages in the PagedView should be equal to the gap from the page
// to the edge of the screen (so it is not visible in the current screen). To
// account for unequal padding on each side of the paged view, we take the maximum
// of the left/right gap and use that as the gap between each page.
int offset = getRelativeChildOffset(0);
int spacing = Math.max(offset, widthSize - offset -
getChildAt(0).getMeasuredWidth());
setPageSpacing(spacing);
}
}
updateScrollingIndicatorPosition();
if (childCount > 0) {
mMaxScrollX = getChildOffset(childCount - 1) - getRelativeChildOffset(childCount - 1);
} else {
mMaxScrollX = 0;
}
|
protected void | onPageBeginMoving()
|
public void | onPageBeginWarp()
|
protected void | onPageEndMoving()
|
public void | onPageEndWarp()
|
private void | onPostReorderingAnimationCompleted()
// Trigger the callback when reordering has settled
--mPostReorderingPreZoomInRemainingAnimationCount;
if (mPostReorderingPreZoomInRunnable != null &&
mPostReorderingPreZoomInRemainingAnimationCount == 0) {
mPostReorderingPreZoomInRunnable.run();
mPostReorderingPreZoomInRunnable = null;
}
|
public abstract void | onRemoveView(View v, boolean deletePermanently)
|
public abstract void | onRemoveViewAnimationCompleted()
|
protected boolean | onRequestFocusInDescendants(int direction, android.graphics.Rect previouslyFocusedRect)
int focusablePage;
if (mNextPage != INVALID_PAGE) {
focusablePage = mNextPage;
} else {
focusablePage = mCurrentPage;
}
View v = getPageAt(focusablePage);
if (v != null) {
return v.requestFocus(direction, previouslyFocusedRect);
}
return false;
|
private void | onSecondaryPointerUp(MotionEvent ev)
final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >>
MotionEvent.ACTION_POINTER_INDEX_SHIFT;
final int pointerId = ev.getPointerId(pointerIndex);
if (pointerId == mActivePointerId) {
// This was our active pointer going up. Choose a new
// active pointer and adjust accordingly.
// TODO: Make this decision more intelligent.
final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
mLastMotionX = mDownMotionX = ev.getX(newPointerIndex);
mLastMotionY = ev.getY(newPointerIndex);
mLastMotionXRemainder = 0;
mActivePointerId = ev.getPointerId(newPointerIndex);
if (mVelocityTracker != null) {
mVelocityTracker.clear();
}
}
|
protected void | onStartReordering()
if (AccessibilityManager.getInstance(mContext).isEnabled()) {
announceForAccessibility(mContext.getString(
R.string.keyguard_accessibility_widget_reorder_start));
}
// Set the touch state to reordering (allows snapping to pages, dragging a child, etc.)
setTouchState(TOUCH_STATE_REORDERING);
mIsReordering = true;
// Mark all the non-widget pages as invisible
getVisiblePages(mTempVisiblePagesRange);
boundByReorderablePages(true, mTempVisiblePagesRange);
for (int i = 0; i < getPageCount(); ++i) {
if (i < mTempVisiblePagesRange[0] || i > mTempVisiblePagesRange[1]) {
getPageAt(i).setAlpha(0f);
}
}
// We must invalidate to trigger a redraw to update the layers such that the drag view
// is always drawn on top
invalidate();
|
public boolean | onTouchEvent(MotionEvent ev)
if (DISABLE_TOUCH_INTERACTION) {
return false;
}
// Skip touch handling if there are no pages to swipe
if (getChildCount() <= 0) return super.onTouchEvent(ev);
acquireVelocityTrackerAndAddMovement(ev);
final int action = ev.getAction();
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
/*
* If being flinged and user touches, stop the fling. isFinished
* will be false if being flinged.
*/
if (!mScroller.isFinished()) {
mScroller.abortAnimation();
}
// Remember where the motion event started
saveDownState(ev);
if (mTouchState == TOUCH_STATE_SCROLLING) {
pageBeginMoving();
} else {
setTouchState(TOUCH_STATE_READY);
}
if (mIsCameraEvent) {
animateWarpPageOnScreen("onTouch(): DOWN");
}
break;
case MotionEvent.ACTION_MOVE:
if (mTouchState == TOUCH_STATE_SCROLLING) {
// Scroll to follow the motion event
final int pointerIndex = ev.findPointerIndex(mActivePointerId);
if (pointerIndex == -1) return true;
final float x = ev.getX(pointerIndex);
final float deltaX = mLastMotionX + mLastMotionXRemainder - x;
mTotalMotionX += Math.abs(deltaX);
// Only scroll and update mLastMotionX if we have moved some discrete amount. We
// keep the remainder because we are actually testing if we've moved from the last
// scrolled position (which is discrete).
if (Math.abs(deltaX) >= 1.0f) {
mTouchX += deltaX;
mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
if (isWarping()) {
KeyguardWidgetFrame v = (KeyguardWidgetFrame) getPageAt(getPageWarpIndex());
v.setTranslationX(v.getTranslationX() - deltaX);
} else if (!mDeferScrollUpdate) {
scrollBy((int) deltaX, 0);
if (DEBUG) Log.d(TAG, "onTouchEvent().Scrolling: " + deltaX);
} else {
invalidate();
}
mLastMotionX = x;
mLastMotionXRemainder = deltaX - (int) deltaX;
} else {
awakenScrollBars();
}
} else if (mTouchState == TOUCH_STATE_REORDERING) {
// Update the last motion position
mLastMotionX = ev.getX();
mLastMotionY = ev.getY();
// Update the parent down so that our zoom animations take this new movement into
// account
float[] pt = mapPointFromViewToParent(this, mLastMotionX, mLastMotionY);
mParentDownMotionX = pt[0];
mParentDownMotionY = pt[1];
updateDragViewTranslationDuringDrag();
// Find the closest page to the touch point
final int dragViewIndex = indexOfChild(mDragView);
int bufferSize = (int) (REORDERING_SIDE_PAGE_BUFFER_PERCENTAGE *
getViewportWidth());
int leftBufferEdge = (int) (mapPointFromViewToParent(this, mViewport.left, 0)[0]
+ bufferSize);
int rightBufferEdge = (int) (mapPointFromViewToParent(this, mViewport.right, 0)[0]
- bufferSize);
// Change the drag view if we are hovering over the drop target
boolean isHoveringOverDelete = isHoveringOverDeleteDropTarget(
(int) mParentDownMotionX, (int) mParentDownMotionY);
setPageHoveringOverDeleteDropTarget(dragViewIndex, isHoveringOverDelete);
if (DEBUG) Log.d(TAG, "leftBufferEdge: " + leftBufferEdge);
if (DEBUG) Log.d(TAG, "rightBufferEdge: " + rightBufferEdge);
if (DEBUG) Log.d(TAG, "mLastMotionX: " + mLastMotionX);
if (DEBUG) Log.d(TAG, "mLastMotionY: " + mLastMotionY);
if (DEBUG) Log.d(TAG, "mParentDownMotionX: " + mParentDownMotionX);
if (DEBUG) Log.d(TAG, "mParentDownMotionY: " + mParentDownMotionY);
float parentX = mParentDownMotionX;
int pageIndexToSnapTo = -1;
if (parentX < leftBufferEdge && dragViewIndex > 0) {
pageIndexToSnapTo = dragViewIndex - 1;
} else if (parentX > rightBufferEdge && dragViewIndex < getChildCount() - 1) {
pageIndexToSnapTo = dragViewIndex + 1;
}
final int pageUnderPointIndex = pageIndexToSnapTo;
if (pageUnderPointIndex > -1 && !isHoveringOverDelete) {
mTempVisiblePagesRange[0] = 0;
mTempVisiblePagesRange[1] = getPageCount() - 1;
boundByReorderablePages(true, mTempVisiblePagesRange);
if (mTempVisiblePagesRange[0] <= pageUnderPointIndex &&
pageUnderPointIndex <= mTempVisiblePagesRange[1] &&
pageUnderPointIndex != mSidePageHoverIndex && mScroller.isFinished()) {
mSidePageHoverIndex = pageUnderPointIndex;
mSidePageHoverRunnable = new Runnable() {
@Override
public void run() {
// Update the down scroll position to account for the fact that the
// current page is moved
mDownScrollX = getChildOffset(pageUnderPointIndex)
- getRelativeChildOffset(pageUnderPointIndex);
// Setup the scroll to the correct page before we swap the views
snapToPage(pageUnderPointIndex);
// For each of the pages between the paged view and the drag view,
// animate them from the previous position to the new position in
// the layout (as a result of the drag view moving in the layout)
int shiftDelta = (dragViewIndex < pageUnderPointIndex) ? -1 : 1;
int lowerIndex = (dragViewIndex < pageUnderPointIndex) ?
dragViewIndex + 1 : pageUnderPointIndex;
int upperIndex = (dragViewIndex > pageUnderPointIndex) ?
dragViewIndex - 1 : pageUnderPointIndex;
for (int i = lowerIndex; i <= upperIndex; ++i) {
View v = getChildAt(i);
// dragViewIndex < pageUnderPointIndex, so after we remove the
// drag view all subsequent views to pageUnderPointIndex will
// shift down.
int oldX = getViewportOffsetX() + getChildOffset(i);
int newX = getViewportOffsetX() + getChildOffset(i + shiftDelta);
// Animate the view translation from its old position to its new
// position
AnimatorSet anim = (AnimatorSet) v.getTag();
if (anim != null) {
anim.cancel();
}
v.setTranslationX(oldX - newX);
anim = new AnimatorSet();
anim.setDuration(REORDERING_REORDER_REPOSITION_DURATION);
anim.playTogether(
ObjectAnimator.ofFloat(v, "translationX", 0f));
anim.start();
v.setTag(anim);
}
removeView(mDragView);
onRemoveView(mDragView, false);
addView(mDragView, pageUnderPointIndex);
onAddView(mDragView, pageUnderPointIndex);
mSidePageHoverIndex = -1;
}
};
postDelayed(mSidePageHoverRunnable, REORDERING_SIDE_PAGE_HOVER_TIMEOUT);
}
} else {
removeCallbacks(mSidePageHoverRunnable);
mSidePageHoverIndex = -1;
}
} else if (determineScrollingStart(ev)) {
startScrolling(ev);
} else if (isHorizontalCameraScroll(ev)) {
startScrolling(ev);
// we need to cancel the camera animation
KeyguardWidgetFrame v = (KeyguardWidgetFrame) getPageAt(getPageWarpIndex());
v.animate().cancel();
}
break;
case MotionEvent.ACTION_UP:
if (mTouchState == TOUCH_STATE_SCROLLING) {
final int activePointerId = mActivePointerId;
final int pointerIndex = ev.findPointerIndex(activePointerId);
if (pointerIndex == -1) return true;
final float x = ev.getX(pointerIndex);
final VelocityTracker velocityTracker = mVelocityTracker;
velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
int velocityX = (int) velocityTracker.getXVelocity(activePointerId);
final int deltaX = (int) (x - mDownMotionX);
final int pageWidth = getScaledMeasuredWidth(getPageAt(mCurrentPage));
boolean isSignificantMove = Math.abs(deltaX) > pageWidth *
SIGNIFICANT_MOVE_THRESHOLD;
mTotalMotionX += Math.abs(mLastMotionX + mLastMotionXRemainder - x);
boolean isFling = mTotalMotionX > MIN_LENGTH_FOR_FLING &&
Math.abs(velocityX) > mFlingThresholdVelocity;
// In the case that the page is moved far to one direction and then is flung
// in the opposite direction, we use a threshold to determine whether we should
// just return to the starting page, or if we should skip one further.
boolean returnToOriginalPage = false;
if (Math.abs(deltaX) > pageWidth * RETURN_TO_ORIGINAL_PAGE_THRESHOLD &&
Math.signum(velocityX) != Math.signum(deltaX) && isFling) {
returnToOriginalPage = true;
}
int finalPage;
// We give flings precedence over large moves, which is why we short-circuit our
// test for a large move if a fling has been registered. That is, a large
// move to the left and fling to the right will register as a fling to the right.
if (((isSignificantMove && deltaX > 0 && !isFling) ||
(isFling && velocityX > 0)) && mCurrentPage > 0) {
finalPage = returnToOriginalPage || isWarping()
? mCurrentPage : mCurrentPage - 1;
snapToPageWithVelocity(finalPage, velocityX);
} else if (((isSignificantMove && deltaX < 0 && !isFling) ||
(isFling && velocityX < 0)) &&
mCurrentPage < getChildCount() - 1) {
finalPage = returnToOriginalPage ? mCurrentPage :
isWarping() ? getPageWarpIndex() : mCurrentPage + 1;
snapToPageWithVelocity(finalPage, velocityX);
} else {
snapToDestination();
}
} else if (mTouchState == TOUCH_STATE_PREV_PAGE) {
// at this point we have not moved beyond the touch slop
// (otherwise mTouchState would be TOUCH_STATE_SCROLLING), so
// we can just page
int nextPage = Math.max(0, mCurrentPage - 1);
if (nextPage != mCurrentPage) {
snapToPage(nextPage);
} else {
snapToDestination();
}
} else if (mTouchState == TOUCH_STATE_NEXT_PAGE) {
// at this point we have not moved beyond the touch slop
// (otherwise mTouchState would be TOUCH_STATE_SCROLLING), so
// we can just page
int nextPage = Math.min(getChildCount() - 1, mCurrentPage + 1);
if (nextPage != mCurrentPage) {
snapToPage(nextPage);
} else {
snapToDestination();
}
} else if (mTouchState == TOUCH_STATE_REORDERING) {
// Update the last motion position
mLastMotionX = ev.getX();
mLastMotionY = ev.getY();
// Update the parent down so that our zoom animations take this new movement into
// account
float[] pt = mapPointFromViewToParent(this, mLastMotionX, mLastMotionY);
mParentDownMotionX = pt[0];
mParentDownMotionY = pt[1];
updateDragViewTranslationDuringDrag();
boolean handledFling = false;
if (!DISABLE_FLING_TO_DELETE) {
// Check the velocity and see if we are flinging-to-delete
PointF flingToDeleteVector = isFlingingToDelete();
if (flingToDeleteVector != null) {
onFlingToDelete(flingToDeleteVector);
handledFling = true;
}
}
if (!handledFling && isHoveringOverDeleteDropTarget((int) mParentDownMotionX,
(int) mParentDownMotionY)) {
onDropToDelete();
}
} else {
if (DEBUG_WARP) Log.v(TAG, "calling onUnhandledTap()");
if (mWarpPageExposed && !isAnimatingWarpPage()) {
animateWarpPageOffScreen("unhandled tap", true);
}
onUnhandledTap(ev);
}
// Remove the callback to wait for the side page hover timeout
removeCallbacks(mSidePageHoverRunnable);
// End any intermediate reordering states
resetTouchState();
break;
case MotionEvent.ACTION_CANCEL:
if (mTouchState == TOUCH_STATE_SCROLLING) {
snapToDestination();
}
resetTouchState();
break;
case MotionEvent.ACTION_POINTER_UP:
onSecondaryPointerUp(ev);
break;
}
return true;
|
void | onTouchStateChanged(int newTouchState)
if (DEBUG) {
Log.v(TAG, "onTouchStateChanged(old="+ mTouchState + ", new=" + newTouchState + ")");
}
|
protected void | onUnhandledTap(MotionEvent ev)
|
protected void | overScroll(float amount)
dampedOverScroll(amount);
|
private float | overScrollInfluenceCurve(float f)
f -= 1.0f;
return f * f * f + 1.0f;
|
protected void | pageBeginMoving()
if (DEBUG_WARP) Log.v(TAG, "pageBeginMoving(" + mIsPageMoving + ")");
if (!mIsPageMoving) {
mIsPageMoving = true;
if (isWarping()) {
dispatchOnPageBeginWarp();
}
onPageBeginMoving();
}
|
protected void | pageEndMoving()
if (DEBUG_WARP) Log.v(TAG, "pageEndMoving(" + mIsPageMoving + ")");
if (mIsPageMoving) {
mIsPageMoving = false;
if (isWarping()) {
dispatchOnPageEndWarp();
mWarpPageExposed = false;
}
onPageEndMoving();
}
|
public boolean | performAccessibilityAction(int action, android.os.Bundle arguments)
if (super.performAccessibilityAction(action, arguments)) {
return true;
}
switch (action) {
case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: {
if (getCurrentPage() < getPageCount() - 1) {
scrollRight();
return true;
}
} break;
case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: {
if (getCurrentPage() > 0) {
scrollLeft();
return true;
}
} break;
}
return false;
|
private void | releaseVelocityTracker()
if (mVelocityTracker != null) {
mVelocityTracker.recycle();
mVelocityTracker = null;
}
|
public void | requestChildFocus(View child, View focused)
super.requestChildFocus(child, focused);
int page = indexToPage(indexOfChild(child));
if (page >= 0 && page != getCurrentPage() && !isInTouchMode()) {
snapToPage(page);
}
|
public boolean | requestChildRectangleOnScreen(View child, android.graphics.Rect rectangle, boolean immediate)
int page = indexToPage(indexOfChild(child));
if (page != mCurrentPage || !mScroller.isFinished()) {
snapToPage(page);
return true;
}
return false;
|
private void | resetTouchState()
releaseVelocityTracker();
endReordering();
setTouchState(TOUCH_STATE_REST);
mActivePointerId = INVALID_POINTER;
mDownEventOnEdge = false;
|
private void | saveDownState(MotionEvent ev)Save the state when we get {@link MotionEvent#ACTION_DOWN}
// Remember where the motion event started
mDownMotionX = mLastMotionX = ev.getX();
mDownMotionY = mLastMotionY = ev.getY();
mDownScrollX = getScrollX();
float[] p = mapPointFromViewToParent(this, mLastMotionX, mLastMotionY);
mParentDownMotionX = p[0];
mParentDownMotionY = p[1];
mLastMotionXRemainder = 0;
mTotalMotionX = 0;
mActivePointerId = ev.getPointerId(0);
// Determine if the down event is within the threshold to be an edge swipe
int leftEdgeBoundary = getViewportOffsetX() + mEdgeSwipeRegionSize;
int rightEdgeBoundary = getMeasuredWidth() - getViewportOffsetX() - mEdgeSwipeRegionSize;
if ((mDownMotionX <= leftEdgeBoundary || mDownMotionX >= rightEdgeBoundary)) {
mDownEventOnEdge = true;
}
|
protected void | screenScrolled(int screenCenter)
|
public void | scrollBy(int x, int y)
scrollTo(mUnboundedScrollX + x, getScrollY() + y);
|
public void | scrollLeft()
if (mScroller.isFinished()) {
if (mCurrentPage > 0) snapToPage(mCurrentPage - 1);
} else {
if (mNextPage > 0) snapToPage(mNextPage - 1);
}
|
public void | scrollRight()
if (mScroller.isFinished()) {
if (mCurrentPage < getChildCount() -1) snapToPage(mCurrentPage + 1);
} else {
if (mNextPage < getChildCount() -1) snapToPage(mNextPage + 1);
}
|
public void | scrollTo(int x, int y)
mUnboundedScrollX = x;
if (x < 0) {
super.scrollTo(0, y);
if (mAllowOverScroll) {
overScroll(x);
}
} else if (x > mMaxScrollX) {
super.scrollTo(mMaxScrollX, y);
if (mAllowOverScroll) {
overScroll(x - mMaxScrollX);
}
} else {
mOverScrollX = x;
super.scrollTo(x, y);
}
mTouchX = x;
mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
// Update the last motion events when scrolling
if (isReordering(true)) {
float[] p = mapPointFromParentToView(this, mParentDownMotionX, mParentDownMotionY);
mLastMotionX = p[0];
mLastMotionY = p[1];
updateDragViewTranslationDuringDrag();
}
|
void | setCurrentPage(int currentPage)Sets the current page.
notifyPageSwitching(currentPage);
if (!mScroller.isFinished()) {
mScroller.abortAnimation();
}
// don't introduce any checks like mCurrentPage == currentPage here-- if we change the
// the default
if (getChildCount() == 0) {
return;
}
mForceScreenScrolled = true;
mCurrentPage = Math.max(0, Math.min(currentPage, getPageCount() - 1));
updateCurrentPageScroll();
updateScrollingIndicator();
notifyPageSwitched();
invalidate();
|
protected void | setDataIsReady()Called by subclasses to mark that data is ready, and that we can begin loading and laying
out pages.
mIsDataReady = true;
|
void | setDeleteDropTarget(View v)
mDeleteDropTarget = v;
|
public void | setMinScale(float f)
mMinScale = f;
requestLayout();
|
public void | setOnLongClickListener(OnLongClickListener l)Registers the specified listener on each page contained in this workspace.
mLongClickListener = l;
final int count = getPageCount();
for (int i = 0; i < count; i++) {
getPageAt(i).setOnLongClickListener(l);
}
|
public void | setOnlyAllowEdgeSwipes(boolean enable)
mOnlyAllowEdgeSwipes = enable;
|
protected void | setPageHoveringOverDeleteDropTarget(int viewIndex, boolean isHovering)
|
public void | setPageSpacing(int pageSpacing)
mPageSpacing = pageSpacing;
invalidateCachedOffsets();
|
public void | setPageSwitchListener(com.android.keyguard.PagedView$PageSwitchListener pageSwitchListener)
mPageSwitchListener = pageSwitchListener;
if (mPageSwitchListener != null) {
mPageSwitchListener.onPageSwitched(getPageAt(mCurrentPage), mCurrentPage);
}
|
public void | setScaleX(float scaleX)
super.setScaleX(scaleX);
if (isReordering(true)) {
float[] p = mapPointFromParentToView(this, mParentDownMotionX, mParentDownMotionY);
mLastMotionX = p[0];
mLastMotionY = p[1];
updateDragViewTranslationDuringDrag();
}
|
private void | setTouchState(int touchState)
if (mTouchState != touchState) {
if (DEBUG_WARP) Log.v(TAG, "mTouchState changing to " + touchState);
onTouchStateChanged(touchState);
mTouchState = touchState;
}
|
protected boolean | shouldDrawChild(View child)
return child.getAlpha() > 0;
|
protected boolean | shouldSetTopAlignedPivotForWidget(int childIndex)
return mTopAlignPageWhenShrinkingForBouncer;
|
protected void | showScrollingIndicator(boolean immediately)
mShouldShowScrollIndicator = true;
mShouldShowScrollIndicatorImmediately = true;
if (getChildCount() <= 1) return;
if (!isScrollingIndicatorEnabled()) return;
mShouldShowScrollIndicator = false;
getScrollingIndicator();
if (mScrollIndicator != null) {
// Fade the indicator in
updateScrollingIndicatorPosition();
mScrollIndicator.setVisibility(View.VISIBLE);
cancelScrollingIndicatorAnimations();
if (immediately) {
mScrollIndicator.setAlpha(1f);
} else {
mScrollIndicatorAnimator = ObjectAnimator.ofFloat(mScrollIndicator, "alpha", 1f);
mScrollIndicatorAnimator.setDuration(sScrollIndicatorFadeInDuration);
mScrollIndicatorAnimator.start();
}
}
|
protected void | snapToDestination()
final int newPage = getPageNearestToCenterOfScreen();
if (isWarping()) {
cancelWarpAnimation("snapToDestination", mCurrentPage != newPage);
}
snapToPage(newPage, getPageSnapDuration());
|
protected void | snapToPage(int whichPage, int duration)
snapToPage(whichPage, duration, false);
|
protected void | snapToPage(int whichPage, int duration, boolean immediate)
whichPage = Math.max(0, Math.min(whichPage, getPageCount() - 1));
if (DEBUG) Log.d(TAG, "snapToPage.getChildOffset(): " + getChildOffset(whichPage));
if (DEBUG) Log.d(TAG, "snapToPage.getRelativeChildOffset(): " + getViewportWidth() + ", "
+ getChildWidth(whichPage));
int newX = getChildOffset(whichPage) - getRelativeChildOffset(whichPage);
final int sX = mUnboundedScrollX;
final int delta = newX - sX;
snapToPage(whichPage, delta, duration, immediate);
|
protected void | snapToPage(int whichPage, int delta, int duration)
snapToPage(whichPage, delta, duration, false);
|
protected void | snapToPage(int whichPage, int delta, int duration, boolean immediate)
if (isWarping() && whichPage == mCurrentPage+1) {
mNextPage = getPageWarpIndex(); // jump to the warp page
if (DEBUG_WARP) Log.v(TAG, "snapToPage(" + whichPage + ") : reset mPageSwapIndex");
} else {
mNextPage = whichPage;
}
if(mWarpPageExposed) {
dispatchOnPageEndWarp();
mWarpPageExposed = false;
}
notifyPageSwitching(whichPage);
View focusedChild = getFocusedChild();
if (focusedChild != null && whichPage != mCurrentPage &&
focusedChild == getPageAt(mCurrentPage)) {
focusedChild.clearFocus();
}
pageBeginMoving();
awakenScrollBars(duration);
if (immediate) {
duration = 0;
} else if (duration == 0) {
duration = Math.abs(delta);
}
if (!mScroller.isFinished()) mScroller.abortAnimation();
mScroller.startScroll(mUnboundedScrollX, 0, delta, 0, duration);
notifyPageSwitched();
// Trigger a compute() to finish switching pages if necessary
if (immediate) {
computeScroll();
}
mForceScreenScrolled = true;
invalidate();
|
protected void | snapToPage(int whichPage)
snapToPage(whichPage, getPageSnapDuration());
|
protected void | snapToPageImmediately(int whichPage)
snapToPage(whichPage, getPageSnapDuration(), true);
|
protected void | snapToPageWithVelocity(int whichPage, int velocity)
whichPage = Math.max(0, Math.min(whichPage, getChildCount() - 1));
int halfScreenSize = getViewportWidth() / 2;
if (isWarping()) {
cancelWarpAnimation("snapToPageWithVelocity", mCurrentPage != whichPage);
}
if (DEBUG) Log.d(TAG, "snapToPage.getChildOffset(): " + getChildOffset(whichPage));
if (DEBUG) Log.d(TAG, "snapToPageWithVelocity.getRelativeChildOffset(): "
+ getViewportWidth() + ", " + getChildWidth(whichPage));
final int newX = getChildOffset(whichPage) - getRelativeChildOffset(whichPage);
int delta = newX - mUnboundedScrollX;
int duration = 0;
if (Math.abs(velocity) < mMinFlingVelocity) {
// If the velocity is low enough, then treat this more as an automatic page advance
// as opposed to an apparent physical response to flinging
snapToPage(whichPage, getPageSnapDuration());
return;
}
// Here we compute a "distance" that will be used in the computation of the overall
// snap duration. This is a function of the actual distance that needs to be traveled;
// we keep this value close to half screen size in order to reduce the variance in snap
// duration as a function of the distance the page needs to travel.
float distanceRatio = Math.min(1f, 1.0f * Math.abs(delta) / (2 * halfScreenSize));
float distance = halfScreenSize + halfScreenSize *
distanceInfluenceForSnapDuration(distanceRatio);
velocity = Math.abs(velocity);
velocity = Math.max(mMinSnapVelocity, velocity);
// we want the page's snap velocity to approximately match the velocity at which the
// user flings, so we scale the duration by a value near to the derivative of the scroll
// interpolator at zero, ie. 5. We use 4 to make it a little slower.
duration = 4 * Math.round(1000 * Math.abs(distance / velocity));
snapToPage(whichPage, delta, duration);
|
public void | startPageWarp(int pageIndex)
if (DEBUG_WARP) Log.v(TAG, "START WARP");
if (pageIndex != mCurrentPage + 1) {
mPageSwapIndex = mCurrentPage + 1;
}
mPageWarpIndex = pageIndex;
|
public boolean | startReordering()
int dragViewIndex = getPageNearestToCenterOfScreen();
mTempVisiblePagesRange[0] = 0;
mTempVisiblePagesRange[1] = getPageCount() - 1;
boundByReorderablePages(true, mTempVisiblePagesRange);
// Check if we are within the reordering range
if (mTempVisiblePagesRange[0] <= dragViewIndex &&
dragViewIndex <= mTempVisiblePagesRange[1]) {
mReorderingStarted = true;
if (zoomOut()) {
// Find the drag view under the pointer
mDragView = getChildAt(dragViewIndex);
onStartReordering();
}
return true;
}
return false;
|
private void | startScrolling(MotionEvent ev)
// Ignore if we don't have a valid pointer index
final int pointerIndex = ev.findPointerIndex(mActivePointerId);
if (pointerIndex == -1) return;
final float x = ev.getX(pointerIndex);
setTouchState(TOUCH_STATE_SCROLLING);
mTotalMotionX += Math.abs(mLastMotionX - x);
mLastMotionX = x;
mLastMotionXRemainder = 0;
mTouchX = getViewportOffsetX() + getScrollX();
mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
pageBeginMoving();
|
public void | stopPageWarp()
if (DEBUG_WARP) Log.v(TAG, "END WARP");
// mPageSwapIndex is reset in snapToPage() after the scroll animation completes
|
void | swapPages(int indexA, int indexB)Swaps the position of the views by setting the left and right edges appropriately.
View viewA = getPageAt(indexA);
View viewB = getPageAt(indexB);
if (viewA != viewB && viewA != null && viewB != null) {
int deltaX = viewA.getLeft() - viewB.getLeft();
viewA.offsetLeftAndRight(-deltaX);
viewB.offsetLeftAndRight(deltaX);
}
|
protected void | updateCurrentPageScroll()Updates the scroll of the current page immediately to its final scroll position. We use this
in CustomizePagedView to allow tabs to share the same PagedView while resetting the scroll of
the previous tab page.
int offset = getChildOffset(mCurrentPage);
int relOffset = getRelativeChildOffset(mCurrentPage);
int newX = offset - relOffset;
scrollTo(newX, 0);
mScroller.setFinalX(newX);
mScroller.forceFinished(true);
|
void | updateDragViewTranslationDuringDrag()
float x = mLastMotionX - mDownMotionX + getScrollX() - mDownScrollX;
float y = mLastMotionY - mDownMotionY;
mDragView.setTranslationX(x);
mDragView.setTranslationY(y);
if (DEBUG) Log.d(TAG, "PagedView.updateDragViewTranslationDuringDrag(): " + x + ", " + y);
|
private void | updateScrollingIndicator()
if (getChildCount() <= 1) return;
if (!isScrollingIndicatorEnabled()) return;
getScrollingIndicator();
if (mScrollIndicator != null) {
updateScrollingIndicatorPosition();
}
if (mShouldShowScrollIndicator) {
showScrollingIndicator(mShouldShowScrollIndicatorImmediately);
}
|
private void | updateScrollingIndicatorPosition()
if (!isScrollingIndicatorEnabled()) return;
if (mScrollIndicator == null) return;
int numPages = getChildCount();
int pageWidth = getViewportWidth();
int lastChildIndex = Math.max(0, getChildCount() - 1);
int maxScrollX = getChildOffset(lastChildIndex) - getRelativeChildOffset(lastChildIndex);
int trackWidth = pageWidth - mScrollIndicatorPaddingLeft - mScrollIndicatorPaddingRight;
int indicatorWidth = mScrollIndicator.getMeasuredWidth() -
mScrollIndicator.getPaddingLeft() - mScrollIndicator.getPaddingRight();
float offset = Math.max(0f, Math.min(1f, (float) getScrollX() / maxScrollX));
int indicatorSpace = trackWidth / numPages;
int indicatorPos = (int) (offset * (trackWidth - indicatorSpace)) + mScrollIndicatorPaddingLeft;
if (hasElasticScrollIndicator()) {
if (mScrollIndicator.getMeasuredWidth() != indicatorSpace) {
mScrollIndicator.getLayoutParams().width = indicatorSpace;
mScrollIndicator.requestLayout();
}
} else {
int indicatorCenterOffset = indicatorSpace / 2 - indicatorWidth / 2;
indicatorPos += indicatorCenterOffset;
}
mScrollIndicator.setTranslationX(indicatorPos);
|
protected boolean | zoomIn(java.lang.Runnable onCompleteRunnable)
if (mZoomInOutAnim != null && mZoomInOutAnim.isRunning()) {
mZoomInOutAnim.cancel();
}
if (getScaleX() < 1f || getScaleY() < 1f) {
mZoomInOutAnim = new AnimatorSet();
mZoomInOutAnim.setDuration(REORDERING_ZOOM_IN_OUT_DURATION);
mZoomInOutAnim.playTogether(
ObjectAnimator.ofFloat(this, "scaleX", 1f),
ObjectAnimator.ofFloat(this, "scaleY", 1f));
mZoomInOutAnim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
// Hide the delete drop target
if (mDeleteDropTarget != null) {
mDeleteDropTarget.animate().alpha(0f)
.setDuration(REORDERING_DELETE_DROP_TARGET_FADE_DURATION)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mDeleteDropTarget.setVisibility(View.GONE);
}
});
}
}
@Override
public void onAnimationCancel(Animator animation) {
mDragView = null;
}
@Override
public void onAnimationEnd(Animator animation) {
mDragView = null;
if (onCompleteRunnable != null) {
onCompleteRunnable.run();
}
}
});
mZoomInOutAnim.start();
return true;
} else {
if (onCompleteRunnable != null) {
onCompleteRunnable.run();
}
}
return false;
|
protected boolean | zoomOut()
if (mZoomInOutAnim != null && mZoomInOutAnim.isRunning()) {
mZoomInOutAnim.cancel();
}
if (!(getScaleX() < 1f || getScaleY() < 1f)) {
mZoomInOutAnim = new AnimatorSet();
mZoomInOutAnim.setDuration(REORDERING_ZOOM_IN_OUT_DURATION);
mZoomInOutAnim.playTogether(
ObjectAnimator.ofFloat(this, "scaleX", mMinScale),
ObjectAnimator.ofFloat(this, "scaleY", mMinScale));
mZoomInOutAnim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
// Show the delete drop target
if (mDeleteDropTarget != null) {
mDeleteDropTarget.setVisibility(View.VISIBLE);
mDeleteDropTarget.animate().alpha(1f)
.setDuration(REORDERING_DELETE_DROP_TARGET_FADE_DURATION)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
mDeleteDropTarget.setAlpha(0f);
}
});
}
}
});
mZoomInOutAnim.start();
return true;
}
return false;
|