Adding RTL paging.
Change-Id: Ic27d499cb76c7c30da37ed93f5372dd8441118b7
diff --git a/src/com/android/launcher2/AppsCustomizePagedView.java b/src/com/android/launcher2/AppsCustomizePagedView.java
index bfc2db0..a9f7faf 100644
--- a/src/com/android/launcher2/AppsCustomizePagedView.java
+++ b/src/com/android/launcher2/AppsCustomizePagedView.java
@@ -1344,6 +1344,7 @@
// In apps customize, we have a scrolling effect which emulates pulling cards off of a stack.
@Override
protected void screenScrolled(int screenCenter) {
+ final boolean isRtl = isLayoutRtl();
super.screenScrolled(screenCenter);
for (int i = 0; i < getChildCount(); i++) {
@@ -1351,19 +1352,28 @@
if (v != null) {
float scrollProgress = getScrollProgress(screenCenter, v, i);
- float interpolatedProgress =
- mZInterpolator.getInterpolation(Math.abs(Math.min(scrollProgress, 0)));
+ float interpolatedProgress;
+ float translationX;
+ float maxScrollProgress = Math.max(0, scrollProgress);
+ float minScrollProgress = Math.min(0, scrollProgress);
+
+ if (isRtl) {
+ translationX = maxScrollProgress * v.getMeasuredWidth();
+ interpolatedProgress = mZInterpolator.getInterpolation(Math.abs(maxScrollProgress));
+ } else {
+ translationX = minScrollProgress * v.getMeasuredWidth();
+ interpolatedProgress = mZInterpolator.getInterpolation(Math.abs(minScrollProgress));
+ }
float scale = (1 - interpolatedProgress) +
interpolatedProgress * TRANSITION_SCALE_FACTOR;
- float translationX = Math.min(0, scrollProgress) * v.getMeasuredWidth();
float alpha;
-
- if (scrollProgress < 0) {
- alpha = scrollProgress < 0 ? mAlphaInterpolator.getInterpolation(
- 1 - Math.abs(scrollProgress)) : 1.0f;
+ if (isRtl && (scrollProgress > 0)) {
+ alpha = mAlphaInterpolator.getInterpolation(1 - Math.abs(maxScrollProgress));
+ } else if (!isRtl && (scrollProgress < 0)) {
+ alpha = mAlphaInterpolator.getInterpolation(1 - Math.abs(scrollProgress));
} else {
- // On large screens we need to fade the page as it nears its leftmost position
+ // On large screens we need to fade the page as it nears its leftmost position
alpha = mLeftScreenAlphaInterpolator.getInterpolation(1 - scrollProgress);
}
@@ -1372,17 +1382,21 @@
int pageHeight = v.getMeasuredHeight();
if (PERFORM_OVERSCROLL_ROTATION) {
- if (i == 0 && scrollProgress < 0) {
+ float xPivot = isRtl ? 1f - TRANSITION_PIVOT : TRANSITION_PIVOT;
+ boolean isOverscrollingFirstPage = isRtl ? scrollProgress > 0 : scrollProgress < 0;
+ boolean isOverscrollingLastPage = isRtl ? scrollProgress < 0 : scrollProgress > 0;
+
+ if (i == 0 && isOverscrollingFirstPage) {
// Overscroll to the left
- v.setPivotX(TRANSITION_PIVOT * pageWidth);
+ v.setPivotX(xPivot * pageWidth);
v.setRotationY(-TRANSITION_MAX_ROTATION * scrollProgress);
scale = 1.0f;
alpha = 1.0f;
// On the first page, we don't want the page to have any lateral motion
translationX = 0;
- } else if (i == getChildCount() - 1 && scrollProgress > 0) {
+ } else if (i == getChildCount() - 1 && isOverscrollingLastPage) {
// Overscroll to the right
- v.setPivotX((1 - TRANSITION_PIVOT) * pageWidth);
+ v.setPivotX((1 - xPivot) * pageWidth);
v.setRotationY(-TRANSITION_MAX_ROTATION * scrollProgress);
scale = 1.0f;
alpha = 1.0f;
diff --git a/src/com/android/launcher2/PagedView.java b/src/com/android/launcher2/PagedView.java
index 6d5d151..494534c 100644
--- a/src/com/android/launcher2/PagedView.java
+++ b/src/com/android/launcher2/PagedView.java
@@ -257,6 +257,13 @@
}
/**
+ * Note: this is a reimplementation of View.isLayoutRtl() since that is currently hidden api.
+ */
+ public boolean isLayoutRtl() {
+ return (getLayoutDirection() == LAYOUT_DIRECTION_RTL);
+ }
+
+ /**
* Called by subclasses to mark that data is ready, and that we can begin loading and laying
* out pages.
*/
@@ -401,17 +408,28 @@
@Override
public void scrollTo(int x, int y) {
+ final boolean isRtl = isLayoutRtl();
mUnboundedScrollX = x;
- if (x < 0) {
+ boolean isXBeforeFirstPage = isRtl ? (x > mMaxScrollX) : (x < 0);
+ boolean isXAfterLastPage = isRtl ? (x < 0) : (x > mMaxScrollX);
+ if (isXBeforeFirstPage) {
super.scrollTo(0, y);
if (mAllowOverScroll) {
- overScroll(x);
+ if (isRtl) {
+ overScroll(x - mMaxScrollX);
+ } else {
+ overScroll(x);
+ }
}
- } else if (x > mMaxScrollX) {
+ } else if (isXAfterLastPage) {
super.scrollTo(mMaxScrollX, y);
if (mAllowOverScroll) {
- overScroll(x - mMaxScrollX);
+ if (isRtl) {
+ overScroll(x);
+ } else {
+ overScroll(x - mMaxScrollX);
+ }
}
} else {
mOverScrollX = x;
@@ -566,7 +584,8 @@
updateScrollingIndicatorPosition();
if (childCount > 0) {
- mMaxScrollX = getChildOffset(childCount - 1) - getRelativeChildOffset(childCount - 1);
+ final int index = isLayoutRtl() ? 0 : childCount - 1;
+ mMaxScrollX = getChildOffset(index) - getRelativeChildOffset(index);
} else {
mMaxScrollX = 0;
}
@@ -631,9 +650,13 @@
if (DEBUG) Log.d(TAG, "PagedView.onLayout()");
final int verticalPadding = getPaddingTop() + getPaddingBottom();
final int childCount = getChildCount();
- int childLeft = getRelativeChildOffset(0);
+ final boolean isRtl = isLayoutRtl();
- for (int i = 0; i < childCount; i++) {
+ final int startIndex = isRtl ? childCount - 1 : 0;
+ final int endIndex = isRtl ? -1 : childCount;
+ final int delta = isRtl ? -1 : 1;
+ int childLeft = getRelativeChildOffset(startIndex);
+ for (int i = startIndex; i != endIndex; i += delta) {
final View child = getPageAt(i);
if (child.getVisibility() != View.GONE) {
final int childWidth = getScaledMeasuredWidth(child);
@@ -710,6 +733,7 @@
}
protected int getChildOffset(int index) {
+ final boolean isRtl = isLayoutRtl();
int[] childOffsets = Float.compare(mLayoutScale, 1f) == 0 ?
mChildOffsets : mChildOffsetsWithLayoutScale;
@@ -719,8 +743,11 @@
if (getChildCount() == 0)
return 0;
- int offset = getRelativeChildOffset(0);
- for (int i = 0; i < index; ++i) {
+ final int startIndex = isRtl ? getChildCount() - 1 : 0;
+ final int endIndex = isRtl ? index : index;
+ final int delta = isRtl ? -1 : 1;
+ int offset = getRelativeChildOffset(startIndex);
+ for (int i = startIndex; i != endIndex; i += delta) {
offset += getScaledMeasuredWidth(getPageAt(i)) + mPageSpacing;
}
if (childOffsets != null) {
@@ -754,28 +781,31 @@
}
protected void getVisiblePages(int[] range) {
+ final boolean isRtl = isLayoutRtl();
final int pageCount = getChildCount();
if (pageCount > 0) {
final int screenWidth = getMeasuredWidth();
- int leftScreen = 0;
+ int leftScreen = isRtl ? pageCount - 1 : 0;
int rightScreen = 0;
+ int endIndex = isRtl ? 0 : pageCount - 1;
+ int delta = isRtl ? -1 : 1;
View currPage = getPageAt(leftScreen);
- while (leftScreen < pageCount - 1 &&
+ while (leftScreen != endIndex &&
currPage.getX() + currPage.getWidth() -
currPage.getPaddingRight() < getScrollX()) {
- leftScreen++;
+ leftScreen += delta;
currPage = getPageAt(leftScreen);
}
rightScreen = leftScreen;
- currPage = getPageAt(rightScreen + 1);
- while (rightScreen < pageCount - 1 &&
+ currPage = getPageAt(rightScreen + delta);
+ while (rightScreen != endIndex &&
currPage.getX() - currPage.getPaddingLeft() < getScrollX() + screenWidth) {
- rightScreen++;
- currPage = getPageAt(rightScreen + 1);
+ rightScreen += delta;
+ currPage = getPageAt(rightScreen + delta);
}
- range[0] = leftScreen;
- range[1] = rightScreen;
+ range[0] = Math.min(leftScreen, rightScreen);
+ range[1] = Math.max(leftScreen, rightScreen);
} else {
range[0] = -1;
range[1] = -1;
@@ -854,6 +884,7 @@
@Override
public boolean dispatchUnhandledMove(View focused, int direction) {
+ // XXX-RTL: This will be fixed in a future CL
if (direction == View.FOCUS_LEFT) {
if (getCurrentPage() > 0) {
snapToPage(getCurrentPage() - 1);
@@ -870,6 +901,7 @@
@Override
public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
+ // XXX-RTL: This will be fixed in a future CL
if (mCurrentPage >= 0 && mCurrentPage < getPageCount()) {
getPageAt(mCurrentPage).addFocusables(views, direction, focusableMode);
}
@@ -930,14 +962,23 @@
* Return true if a tap at (x, y) should trigger a flip to the previous page.
*/
protected boolean hitsPreviousPage(float x, float y) {
- return (x < getRelativeChildOffset(mCurrentPage) - mPageSpacing);
+ if (isLayoutRtl()) {
+ return (x > (getMeasuredWidth() - getRelativeChildOffset(mCurrentPage) + mPageSpacing));
+ } else {
+ return (x < getRelativeChildOffset(mCurrentPage) - mPageSpacing);
+ }
}
/**
* Return true if a tap at (x, y) should trigger a flip to the next page.
*/
protected boolean hitsNextPage(float x, float y) {
- return (x > (getMeasuredWidth() - getRelativeChildOffset(mCurrentPage) + mPageSpacing));
+ if (isLayoutRtl()) {
+ return (x < getRelativeChildOffset(mCurrentPage) - mPageSpacing);
+ } else {
+ return (x > (getMeasuredWidth() - getRelativeChildOffset(mCurrentPage) + mPageSpacing));
+ }
+
}
@Override
@@ -1269,12 +1310,15 @@
// 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) {
+ final boolean isRtl = isLayoutRtl();
+ boolean isDeltaXLeft = isRtl ? deltaX > 0 : deltaX < 0;
+ boolean isVelocityXLeft = isRtl ? velocityX > 0 : velocityX < 0;
+ if (((isSignificantMove && !isDeltaXLeft && !isFling) ||
+ (isFling && !isVelocityXLeft)) && mCurrentPage > 0) {
finalPage = returnToOriginalPage ? mCurrentPage : mCurrentPage - 1;
snapToPageWithVelocity(finalPage, velocityX);
- } else if (((isSignificantMove && deltaX < 0 && !isFling) ||
- (isFling && velocityX < 0)) &&
+ } else if (((isSignificantMove && isDeltaXLeft && !isFling) ||
+ (isFling && isVelocityXLeft)) &&
mCurrentPage < getChildCount() - 1) {
finalPage = returnToOriginalPage ? mCurrentPage : mCurrentPage + 1;
snapToPageWithVelocity(finalPage, velocityX);
@@ -1342,7 +1386,9 @@
hscroll = event.getAxisValue(MotionEvent.AXIS_HSCROLL);
}
if (hscroll != 0 || vscroll != 0) {
- if (hscroll > 0 || vscroll > 0) {
+ boolean isForwardScroll = isLayoutRtl() ? (hscroll < 0 || vscroll < 0)
+ : (hscroll > 0 || vscroll > 0);
+ if (isForwardScroll) {
scrollRight();
} else {
scrollLeft();
@@ -1400,10 +1446,14 @@
}
protected int getChildIndexForRelativeOffset(int relativeOffset) {
+ final boolean isRtl = isLayoutRtl();
final int childCount = getChildCount();
int left;
int right;
- for (int i = 0; i < childCount; ++i) {
+ final int startIndex = isRtl ? childCount - 1 : 0;
+ final int endIndex = isRtl ? -1 : childCount;
+ final int delta = isRtl ? -1 : 1;
+ for (int i = startIndex; i != endIndex; i += delta) {
left = getRelativeChildOffset(i);
right = (left + getScaledMeasuredWidth(getPageAt(i)));
if (left <= relativeOffset && relativeOffset <= right) {
@@ -1839,17 +1889,20 @@
}
private void updateScrollingIndicatorPosition() {
+ final boolean isRtl = isLayoutRtl();
if (!isScrollingIndicatorEnabled()) return;
if (mScrollIndicator == null) return;
int numPages = getChildCount();
int pageWidth = getMeasuredWidth();
- 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));
+ float scrollPos = isRtl ? mMaxScrollX - getScrollX() : getScrollX();
+ float offset = Math.max(0f, Math.min(1f, (float) scrollPos / mMaxScrollX));
+ if (isRtl) {
+ offset = 1f - offset;
+ }
int indicatorSpace = trackWidth / numPages;
int indicatorPos = (int) (offset * (trackWidth - indicatorSpace)) + mScrollIndicatorPaddingLeft;
if (hasElasticScrollIndicator()) {
diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java
index 9d8845b..529f425 100644
--- a/src/com/android/launcher2/Workspace.java
+++ b/src/com/android/launcher2/Workspace.java
@@ -1182,18 +1182,6 @@
}
}
- float overScrollBackgroundAlphaInterpolator(float r) {
- float threshold = 0.08f;
-
- if (r > mOverScrollMaxBackgroundAlpha) {
- mOverScrollMaxBackgroundAlpha = r;
- } else if (r < mOverScrollMaxBackgroundAlpha) {
- r = mOverScrollMaxBackgroundAlpha;
- }
-
- return Math.min(r / threshold, 1.0f);
- }
-
private void updatePageAlphaValues(int screenCenter) {
boolean isInOverscroll = mOverScrollX < 0 || mOverScrollX > mMaxScrollX;
if (mWorkspaceFadeInAdjacentScreens &&
@@ -1226,23 +1214,38 @@
@Override
protected void screenScrolled(int screenCenter) {
+ final boolean isRtl = isLayoutRtl();
super.screenScrolled(screenCenter);
updatePageAlphaValues(screenCenter);
enableHwLayersOnVisiblePages();
if (mOverScrollX < 0 || mOverScrollX > mMaxScrollX) {
- int index = mOverScrollX < 0 ? 0 : getChildCount() - 1;
+ int index = 0;
+ float pivotX = 0f;
+ final float leftBiasedPivot = 0.25f;
+ final float rightBiasedPivot = 0.75f;
+ final int lowerIndex = 0;
+ final int upperIndex = getChildCount() - 1;
+ if (isRtl) {
+ index = mOverScrollX < 0 ? upperIndex : lowerIndex;
+ pivotX = (index == 0 ? leftBiasedPivot : rightBiasedPivot);
+ } else {
+ index = mOverScrollX < 0 ? lowerIndex : upperIndex;
+ pivotX = (index == 0 ? rightBiasedPivot : leftBiasedPivot);
+ }
+
CellLayout cl = (CellLayout) getChildAt(index);
float scrollProgress = getScrollProgress(screenCenter, cl, index);
- cl.setOverScrollAmount(Math.abs(scrollProgress), index == 0);
- float rotation = - WORKSPACE_OVERSCROLL_ROTATION * scrollProgress;
+ final boolean isLeftPage = (isRtl ? index > 0 : index == 0);
+ cl.setOverScrollAmount(Math.abs(scrollProgress), isLeftPage);
+ float rotation = -WORKSPACE_OVERSCROLL_ROTATION * scrollProgress;
cl.setRotationY(rotation);
setFadeForOverScroll(Math.abs(scrollProgress));
if (!mOverscrollTransformsSet) {
mOverscrollTransformsSet = true;
cl.setCameraDistance(mDensity * mCameraDistance);
- cl.setPivotX(cl.getMeasuredWidth() * (index == 0 ? 0.75f : 0.25f));
+ cl.setPivotX(cl.getMeasuredWidth() * pivotX);
cl.setPivotY(cl.getMeasuredHeight() * 0.5f);
cl.setOverscrollTransformsDirty(true);
}