From f358a4bbd6ce5b6ddadfae19e6b9c6872530d627 Mon Sep 17 00:00:00 2001 From: Adam Cohen Date: Tue, 23 Jul 2013 16:47:31 -0700 Subject: Adding overview mode for reordering, widget adding and wallpaper switching Change-Id: I082ba0b90ca4b3fbba32e8dfdec8ba79486d841c --- res/layout-land/launcher.xml | 4 + res/layout-port/launcher.xml | 24 +- res/layout-sw720dp/launcher.xml | 24 +- res/layout/overview_panel.xml | 39 +++ res/values/config.xml | 2 + res/values/dimens.xml | 2 + res/values/strings.xml | 5 + src/com/android/launcher3/Launcher.java | 52 +++- src/com/android/launcher3/PagedView.java | 415 +++++++++++++------------------ src/com/android/launcher3/Workspace.java | 138 ++++++++-- 10 files changed, 415 insertions(+), 290 deletions(-) create mode 100644 res/layout/overview_panel.xml diff --git a/res/layout-land/launcher.xml b/res/layout-land/launcher.xml index 8ee1413ee..3454ad49f 100644 --- a/res/layout-land/launcher.xml +++ b/res/layout-land/launcher.xml @@ -65,6 +65,10 @@ android:id="@+id/qsb_bar" layout="@layout/qsb_bar" /> + + diff --git a/res/layout-port/launcher.xml b/res/layout-port/launcher.xml index 0fee045fc..a2e829819 100644 --- a/res/layout-port/launcher.xml +++ b/res/layout-port/launcher.xml @@ -30,16 +30,6 @@ android:layout_height="match_parent" android:fitsSystemWindows="true"> - - - + + + + + diff --git a/res/layout-sw720dp/launcher.xml b/res/layout-sw720dp/launcher.xml index 852d1ec21..82f01788a 100644 --- a/res/layout-sw720dp/launcher.xml +++ b/res/layout-sw720dp/launcher.xml @@ -30,16 +30,6 @@ android:layout_height="match_parent" android:fitsSystemWindows="true"> - - - + + + + + diff --git a/res/layout/overview_panel.xml b/res/layout/overview_panel.xml new file mode 100644 index 000000000..713adea3c --- /dev/null +++ b/res/layout/overview_panel.xml @@ -0,0 +1,39 @@ + + + + + + + + diff --git a/res/values/config.xml b/res/values/config.xml index cc3d4f0bf..2fc3473a7 100644 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -15,6 +15,8 @@ 300 80 + + 50 diff --git a/res/values/dimens.xml b/res/values/dimens.xml index 2bfb31cc7..13a15e394 100644 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -50,6 +50,8 @@ 0dp 12sp 15dp + 50dp + 40dp 6dp 2dp diff --git a/res/values/strings.xml b/res/values/strings.xml index 052e13b3b..51da40be5 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -282,4 +282,9 @@ s --> * HPROF + + + Add Widget + + Wallpaper diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index f990d2595..09881b609 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -79,6 +79,7 @@ import android.view.MenuItem; import android.view.MotionEvent; import android.view.Surface; import android.view.View; +import android.view.View.OnClickListener; import android.view.View.OnLongClickListener; import android.view.ViewGroup; import android.view.ViewTreeObserver; @@ -236,6 +237,8 @@ public class Launcher extends Activity private FolderInfo mFolderInfo; private Hotseat mHotseat; + private View mOverviewPanel; + private View mAllAppsButton; private SearchDropTargetBar mSearchDropTargetBar; @@ -1065,6 +1068,20 @@ public class Launcher extends Activity mHotseat.setup(this); } + mOverviewPanel = findViewById(R.id.overview_panel); + findViewById(R.id.widget_button).setOnClickListener(new OnClickListener() { + @Override + public void onClick(View arg0) { + showAllApps(true); + } + }); + findViewById(R.id.wallpaper_button).setOnClickListener(new OnClickListener() { + @Override + public void onClick(View arg0) { + startWallpaper(); + } + }); + // Setup the workspace mWorkspace.setHapticFeedbackEnabled(false); mWorkspace.setOnLongClickListener(this); @@ -1560,6 +1577,9 @@ public class Launcher extends Activity // otherwise, just wait until onResume to set the state back to Workspace if (alreadyOnHome) { showWorkspace(true); + if (mWorkspace.isInOverviewMode()) { + mWorkspace.exitOverviewMode(); + } } else { mOnResumeState = State.WORKSPACE; } @@ -2050,6 +2070,8 @@ public class Launcher extends Activity public void onBackPressed() { if (isAllAppsVisible()) { showWorkspace(true); + } else if (mWorkspace.isInOverviewMode()) { + mWorkspace.exitOverviewMode(); } else if (mWorkspace.getOpenFolder() != null) { Folder openFolder = mWorkspace.getOpenFolder(); if (openFolder.isEditingName()) { @@ -2090,6 +2112,19 @@ public class Launcher extends Activity return; } + if (v instanceof PageIndicator) { + if (!mWorkspace.isInOverviewMode()) { + mWorkspace.enterOverviewMode(); + } + return; + } + + if (v instanceof CellLayout) { + if (mWorkspace.isInOverviewMode()) { + mWorkspace.exitOverviewMode(mWorkspace.indexOfChild(v)); + } + } + Object tag = v.getTag(); if (tag instanceof ShortcutInfo) { // Open shortcut @@ -2138,11 +2173,6 @@ public class Launcher extends Activity } public boolean onTouch(View v, MotionEvent event) { - // this is an intercepted event being forwarded from mWorkspace; - // clicking anywhere on the workspace causes the customization drawer to slide down - if (event.getAction() == MotionEvent.ACTION_DOWN) { - showWorkspace(true); - } return false; } @@ -2510,10 +2540,10 @@ public class Launcher extends Activity mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); // Disabling reordering until we sort out some issues. - if (mWorkspace.getIdForScreen((CellLayout) v) >= 0) { - mWorkspace.startReordering(); + if (mWorkspace.isInOverviewMode()) { + mWorkspace.startReordering(v); } else { - startWallpaper(); + mWorkspace.enterOverviewMode(); } } else { if (!(itemUnderLongClick instanceof Folder)) { @@ -2532,6 +2562,9 @@ public class Launcher extends Activity Hotseat getHotseat() { return mHotseat; } + View getOverviewPanel() { + return mOverviewPanel; + } SearchDropTargetBar getSearchBar() { return mSearchDropTargetBar; } @@ -2852,11 +2885,10 @@ public class Launcher extends Activity final View fromView = mAppsCustomizeTabHost; final View toView = mWorkspace; Animator workspaceAnim = null; - if (toState == State.WORKSPACE) { int stagger = res.getInteger(R.integer.config_appsCustomizeWorkspaceAnimationStagger); workspaceAnim = mWorkspace.getChangeStateAnimation( - Workspace.State.NORMAL, animated, stagger); + Workspace.State.NORMAL, animated, stagger, -1); } else if (toState == State.APPS_CUSTOMIZE_SPRING_LOADED) { workspaceAnim = mWorkspace.getChangeStateAnimation( Workspace.State.SPRING_LOADED, animated); diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java index bb596a79e..ccf21561d 100644 --- a/src/com/android/launcher3/PagedView.java +++ b/src/com/android/launcher3/PagedView.java @@ -88,9 +88,13 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc // We are disabling touch interaction of the widget region for factory ROM. private static final boolean DISABLE_TOUCH_INTERACTION = false; - private static final boolean DISABLE_TOUCH_SIDE_PAGES = false; + private static final boolean DISABLE_TOUCH_SIDE_PAGES = true; private static final boolean DISABLE_FLING_TO_DELETE = true; + private boolean mFreeScroll = false; + private int mFreeScrollMinScrollX = -1; + private int mFreeScrollMaxScrollX = -1; + static final int AUTOMATIC_PAGE_SPACING = -1; protected int mFlingThresholdVelocity; @@ -117,6 +121,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc private float mDownMotionX; private float mDownMotionY; private float mDownScrollX; + private float mDragViewBaselineLeft; protected float mLastMotionX; protected float mLastMotionXRemainder; protected float mLastMotionY; @@ -205,9 +210,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc private int REORDERING_DROP_REPOSITION_DURATION = 200; protected int REORDERING_REORDER_REPOSITION_DURATION = 300; protected int REORDERING_ZOOM_IN_OUT_DURATION = 250; - private int REORDERING_SIDE_PAGE_HOVER_TIMEOUT = 300; - private float REORDERING_SIDE_PAGE_BUFFER_PERCENTAGE = 0.1f; - private long REORDERING_DELETE_DROP_TARGET_FADE_DURATION = 150; + private int REORDERING_SIDE_PAGE_HOVER_TIMEOUT = 80; private float mMinScale = 1f; protected View mDragView; protected AnimatorSet mZoomInOutAnim; @@ -223,11 +226,6 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc private int mPostReorderingPreZoomInRemainingAnimationCount; private Runnable mPostReorderingPreZoomInRunnable; - // Edge swiping - private boolean mOnlyAllowEdgeSwipes = false; - private boolean mDownEventOnEdge = false; - private int mEdgeSwipeRegionSize = 0; - // Convenience/caching private Matrix mTmpInvMatrix = new Matrix(); private float[] mTmpPoint = new float[2]; @@ -332,7 +330,9 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc for (int i = 0; i < getChildCount(); ++i) { markers.add(getPageIndicatorMarker(i)); } + mPageIndicator.addMarkers(markers); + mPageIndicator.setOnClickListener((Launcher) getContext()); } } @@ -363,12 +363,16 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc } void updateDragViewTranslationDuringDrag() { - float x = mLastMotionX - mDownMotionX + getScrollX() - mDownScrollX; - float y = mLastMotionY - mDownMotionY; - mDragView.setTranslationX(x); - mDragView.setTranslationY(y); + if (mDragView != null) { + float x = (mLastMotionX - mDownMotionX) + (getScrollX() - mDownScrollX) + + (mDragViewBaselineLeft - mDragView.getLeft()); + float y = mLastMotionY - mDownMotionY; + mDragView.setTranslationX(x); + mDragView.setTranslationY(y); - if (DEBUG) Log.d(TAG, "PagedView.updateDragViewTranslationDuringDrag(): " + x + ", " + y); + if (DEBUG) Log.d(TAG, "PagedView.updateDragViewTranslationDuringDrag(): " + + x + ", " + y); + } } public void setMinScale(float f) { @@ -580,6 +584,12 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc @Override public void scrollTo(int x, int y) { + // In free scroll mode, we clamp the scrollX + if (mFreeScroll) { + x = Math.min(x, mFreeScrollMaxScrollX); + x = Math.max(x, mFreeScrollMinScrollX); + } + final boolean isRtl = isLayoutRtl(); mUnboundedScrollX = x; @@ -627,7 +637,9 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc if (getScrollX() != mScroller.getCurrX() || getScrollY() != mScroller.getCurrY() || mOverScrollX != mScroller.getCurrX()) { - scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); + float scaleX = mFreeScroll ? getScaleX() : 1f; + int scrollX = (int) (mScroller.getCurrX() * (1 / scaleX)); + scrollTo(scrollX, mScroller.getCurrY()); } invalidate(); return true; @@ -899,6 +911,10 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc } } mChildCountOnLastLayout = getChildCount(); + + if (isReordering(true)) { + updateDragViewTranslationDuringDrag(); + } } protected void screenScrolled(int screenCenter) { @@ -991,7 +1007,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc return offset; } - void getReorderablePages(int[] range) { + protected void getOverviewModePages(int[] range) { range[0] = 0; range[1] = getChildCount() - 1; } @@ -1217,17 +1233,6 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc return mTmpRect.contains(x, y); } - /** Returns whether x and y originated within the current page view bounds */ - private boolean isTouchPointInCurrentPage(int x, int y) { - 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; - } - @Override public boolean onInterceptTouchEvent(MotionEvent ev) { if (DISABLE_TOUCH_INTERACTION) { @@ -1288,13 +1293,6 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc 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; - } - /* * If being flinged and user touches the screen, initiate drag; * otherwise don't. mScroller.isFinished should be false when @@ -1332,10 +1330,6 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc 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: @@ -1369,10 +1363,6 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc final float y = ev.getY(pointerIndex); if (!isTouchPointInViewportWithBuffer((int) x, (int) y)) return; - // If we're only allowing edge swipes, we break out early if the down event wasn't - // at the edge. - if (mOnlyAllowEdgeSwipes && !mDownEventOnEdge) return; - final int xDiff = (int) Math.abs(x - mLastMotionX); final int yDiff = (int) Math.abs(y - mLastMotionY); @@ -1509,6 +1499,75 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc return OVERSCROLL_DAMP_FACTOR * f; } + protected void enableFreeScroll() { + setEnableFreeScroll(true, -1); + } + + protected void disableFreeScroll(int snapPage) { + setEnableFreeScroll(false, snapPage); + } + + private void setEnableFreeScroll(boolean freeScroll, int snapPage) { + mFreeScroll = freeScroll; + + if (snapPage == -1) { + snapPage = getPageNearestToCenterOfScreen(); + } + + getOverviewModePages(mTempVisiblePagesRange); + if (!mFreeScroll) { + snapToPage(snapPage); + + for (int i = 0; i < getPageCount(); ++i) { + if (i < mTempVisiblePagesRange[0] || i > mTempVisiblePagesRange[1]) { + getPageAt(i).setAlpha(1f); + } + } + } else { + mFreeScrollMinScrollX = getScrollForPage(mTempVisiblePagesRange[0]); + mFreeScrollMaxScrollX = getScrollForPage(mTempVisiblePagesRange[1]); + + for (int i = 0; i < getPageCount(); ++i) { + if (i < mTempVisiblePagesRange[0] || i > mTempVisiblePagesRange[1]) { + getPageAt(i).setAlpha(0f); + } + } + + if (getCurrentPage() < mTempVisiblePagesRange[0]) { + setCurrentPage(mTempVisiblePagesRange[0]); + } else if (getCurrentPage() > mTempVisiblePagesRange[1]) { + setCurrentPage(mTempVisiblePagesRange[1]); + } + } + + setEnableOverscroll(!freeScroll); + } + + private void setEnableOverscroll(boolean enable) { + mAllowOverScroll = enable; + } + + int getNearestHoverOverPageIndex() { + if (mDragView != null) { + int dragX = (int) (mDragView.getLeft() + (mDragView.getMeasuredWidth() / 2) + + mDragView.getTranslationX()); + getOverviewModePages(mTempVisiblePagesRange); + int minDistance = Integer.MAX_VALUE; + int minIndex = indexOfChild(mDragView); + for (int i = mTempVisiblePagesRange[0]; i <= mTempVisiblePagesRange[1]; i++) { + View page = getPageAt(i); + int pageX = (int) (page.getLeft() + page.getMeasuredWidth() / 2); + int d = Math.abs(dragX - pageX); + if (d < minDistance) { + minIndex = i; + minDistance = d; + } + } + return minIndex; + } + return -1; + } + @Override public boolean onTouchEvent(MotionEvent ev) { if (DISABLE_TOUCH_INTERACTION) { @@ -1543,13 +1602,6 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc 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; - } - if (mTouchState == TOUCH_STATE_SCROLLING) { pageBeginMoving(); } @@ -1598,38 +1650,23 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc // 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) { + final int pageUnderPointIndex = getNearestHoverOverPageIndex(); + if (pageUnderPointIndex > -1 && pageUnderPointIndex != indexOfChild(mDragView) && + !isHoveringOverDelete) { mTempVisiblePagesRange[0] = 0; mTempVisiblePagesRange[1] = getPageCount() - 1; - getReorderablePages(mTempVisiblePagesRange); + getOverviewModePages(mTempVisiblePagesRange); if (mTempVisiblePagesRange[0] <= pageUnderPointIndex && pageUnderPointIndex <= mTempVisiblePagesRange[1] && pageUnderPointIndex != mSidePageHoverIndex && mScroller.isFinished()) { @@ -1637,10 +1674,6 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc mSidePageHoverRunnable = new Runnable() { @Override public void run() { - // Update the down scroll position to account for the fact that the - // current page is moved - mDownScrollX = getScrollForPage(pageUnderPointIndex); - // Setup the scroll to the correct page before we swap the views snapToPage(pageUnderPointIndex); @@ -1713,42 +1746,56 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc 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; - } + if (!mFreeScroll) { + // 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. - 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 && isDeltaXLeft && !isFling) || - (isFling && isVelocityXLeft)) && - mCurrentPage < getChildCount() - 1) { - finalPage = returnToOriginalPage ? mCurrentPage : 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); + 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. + 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 && isDeltaXLeft && !isFling) || + (isFling && isVelocityXLeft)) && + mCurrentPage < getChildCount() - 1) { + finalPage = returnToOriginalPage ? mCurrentPage : 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 { - snapToDestination(); + if (!mScroller.isFinished()) { + mScroller.abortAnimation(); + } + + float scaleX = getScaleX(); + int vX = (int) (-velocityX * scaleX); + int initialScrollX = (int) (getScrollX() * scaleX); + + mScroller.fling(initialScrollX, + getScrollY(), vX, 0, Integer.MIN_VALUE, Integer.MAX_VALUE, 0, 0); + invalidate(); } } else if (mTouchState == TOUCH_STATE_NEXT_PAGE) { // at this point we have not moved beyond the touch slop @@ -1803,6 +1850,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc case MotionEvent.ACTION_POINTER_UP: onSecondaryPointerUp(ev); + releaseVelocityTracker(); break; } @@ -1819,7 +1867,6 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc endReordering(); mTouchState = TOUCH_STATE_REST; mActivePointerId = INVALID_POINTER; - mDownEventOnEdge = false; } protected void onUnhandledTap(MotionEvent ev) {} @@ -1864,6 +1911,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc private void releaseVelocityTracker() { if (mVelocityTracker != null) { + mVelocityTracker.clear(); mVelocityTracker.recycle(); mVelocityTracker = null; } @@ -2031,7 +2079,9 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc duration = Math.abs(delta); } - if (!mScroller.isFinished()) mScroller.abortAnimation(); + if (!mScroller.isFinished()) { + mScroller.abortAnimation(); + } mScroller.startScroll(mUnboundedScrollX, 0, delta, 0, duration); notifyPageSwitchListener(); @@ -2231,7 +2281,9 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc anim.setDuration(REORDERING_DROP_REPOSITION_DURATION); anim.playTogether( ObjectAnimator.ofFloat(mDragView, "translationX", 0f), - ObjectAnimator.ofFloat(mDragView, "translationY", 0f)); + ObjectAnimator.ofFloat(mDragView, "translationY", 0f), + ObjectAnimator.ofFloat(mDragView, "scaleX", 1f), + ObjectAnimator.ofFloat(mDragView, "scaleY", 1f)); anim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { @@ -2242,59 +2294,11 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc } } - // "Zooms out" the PagedView to reveal more side pages - 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); - } - }); - } - } - @Override - public void onAnimationEnd(Animator animation) { - // Update the visible pages - invalidate(); - } - }); - mZoomInOutAnim.start(); - return true; - } - return false; - } - protected void onStartReordering() { // Set the touch state to reordering (allows snapping to pages, dragging a child, etc.) mTouchState = TOUCH_STATE_REORDERING; mIsReordering = true; - // Mark all the non-widget pages as invisible - getReorderablePages(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(); @@ -2312,32 +2316,24 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc protected void onEndReordering() { mIsReordering = false; - - // Mark all the non-widget pages as visible again - getReorderablePages(mTempVisiblePagesRange); - for (int i = 0; i < getPageCount(); ++i) { - if (i < mTempVisiblePagesRange[0] || i > mTempVisiblePagesRange[1]) { - getPageAt(i).setAlpha(1f); - } - } } - public boolean startReordering() { - int dragViewIndex = getPageNearestToCenterOfScreen(); + public boolean startReordering(View v) { + int dragViewIndex = indexOfChild(v);//getPageNearestToCenterOfScreen(); mTempVisiblePagesRange[0] = 0; mTempVisiblePagesRange[1] = getPageCount() - 1; - getReorderablePages(mTempVisiblePagesRange); + getOverviewModePages(mTempVisiblePagesRange); mReorderingStarted = true; // Check if we are within the reordering range if (mTempVisiblePagesRange[0] <= dragViewIndex && - dragViewIndex <= mTempVisiblePagesRange[1]) { - if (zoomOut()) { - // Find the drag view under the pointer - mDragView = getChildAt(dragViewIndex); - - onStartReordering(); - } + dragViewIndex <= mTempVisiblePagesRange[1]) { + // Find the drag view under the pointer + mDragView = getChildAt(dragViewIndex); + mDragView.animate().scaleX(1.15f).scaleY(1.15f).setDuration(100).start(); + mDragViewBaselineLeft = mDragView.getLeft(); + disableFreeScroll(-1); + onStartReordering(); return true; } return false; @@ -2367,7 +2363,8 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc if (!mDeferringForDelete) { mPostReorderingPreZoomInRunnable = new Runnable() { public void run() { - zoomIn(onCompleteRunnable); + onCompleteRunnable.run(); + enableFreeScroll(); }; }; @@ -2382,56 +2379,6 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc } } - // "Zooms in" the PagedView to highlight the current page - protected boolean zoomIn(final 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(); - } - // Update the visible pages - invalidate(); - } - }); - mZoomInOutAnim.start(); - return true; - } else { - if (onCompleteRunnable != null) { - onCompleteRunnable.run(); - } - } - return false; - } - /* * Flinging to delete - IN PROGRESS */ @@ -2507,7 +2454,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc // 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 - getReorderablePages(mTempVisiblePagesRange); + getOverviewModePages(mTempVisiblePagesRange); boolean isLastWidgetPage = (mTempVisiblePagesRange[0] == mTempVisiblePagesRange[1]); boolean slideFromLeft = (isLastWidgetPage || dragViewIndex > mTempVisiblePagesRange[0]); @@ -2568,15 +2515,9 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc 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); + mDeferringForDelete = false; + onEndReordering(); + onRemoveViewAnimationCompleted(); } }); slideAnimations.start(); @@ -2748,4 +2689,4 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc public boolean onHoverEvent(android.view.MotionEvent event) { return true; } -} +} \ No newline at end of file diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index 6989c9aa6..4e95f09f2 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -17,6 +17,8 @@ package com.android.launcher3; import android.animation.Animator; +import android.animation.Animator.AnimatorListener; +import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.LayoutTransition; import android.animation.ObjectAnimator; @@ -87,6 +89,8 @@ public class Workspace extends SmoothPagedView private static final int ADJACENT_SCREEN_DROP_DURATION = 300; private static final int FLING_THRESHOLD_VELOCITY = 500; + private static final float ALPHA_CUTOFF_THRESHOLD = 0.01f; + // These animators are used to fade the children's outlines private ObjectAnimator mChildrenOutlineFadeInAnimation; private ObjectAnimator mChildrenOutlineFadeOutAnimation; @@ -160,6 +164,7 @@ public class Workspace extends SmoothPagedView private SpringLoadedDragController mSpringLoadedDragController; private float mSpringLoadedShrinkFactor; + private float mOverviewModeShrinkFactor; private static final int DEFAULT_CELL_COUNT_X = 4; private static final int DEFAULT_CELL_COUNT_Y = 4; @@ -167,7 +172,7 @@ public class Workspace extends SmoothPagedView // State variable that indicates whether the pages are small (ie when you're // in all apps or customize mode) - enum State { NORMAL, SPRING_LOADED, SMALL }; + enum State { NORMAL, SPRING_LOADED, SMALL, OVERVIEW}; private State mState = State.NORMAL; private boolean mIsSwitchingState = false; @@ -331,13 +336,14 @@ public class Workspace extends SmoothPagedView mSpringLoadedShrinkFactor = res.getInteger(R.integer.config_workspaceSpringLoadShrinkPercentage) / 100.0f; + mOverviewModeShrinkFactor = + res.getInteger(R.integer.config_workspaceOverviewShrinkPercentage) / 100.0f; mCameraDistance = res.getInteger(R.integer.config_cameraDistance); // if the value is manually specified, use that instead cellCountX = a.getInt(R.styleable.Workspace_cellCountX, cellCountX); cellCountY = a.getInt(R.styleable.Workspace_cellCountY, cellCountY); mDefaultPage = a.getInt(R.styleable.Workspace_defaultScreen, 1); - a.recycle(); setOnHierarchyChangeListener(this); @@ -518,6 +524,7 @@ public class Workspace extends SmoothPagedView mLauncher.getLayoutInflater().inflate(R.layout.workspace_screen, null); newScreen.setOnLongClickListener(mLongClickListener); + newScreen.setOnClickListener(mLauncher); mWorkspaceScreens.put(screenId, newScreen); mScreenOrder.add(insertIndex, screenId); addView(newScreen, insertIndex); @@ -761,7 +768,8 @@ public class Workspace extends SmoothPagedView */ @Override public boolean onTouch(View v, MotionEvent event) { - return (isSmall() || !isFinishedSwitchingState()); + return (isSmall() || !isFinishedSwitchingState()) + || (!isSmall() && indexOfChild(v) != mCurrentPage); } public boolean isSwitchingState() { @@ -810,11 +818,6 @@ public class Workspace extends SmoothPagedView } } } - - if (mLauncher != null && mLauncher.onTouch(this, ev)) { - return true; - } - return super.onInterceptTouchEvent(ev); } @@ -843,7 +846,6 @@ public class Workspace extends SmoothPagedView @Override protected void determineScrollingStart(MotionEvent ev) { - if (isSmall()) return; if (!isFinishedSwitchingState()) return; float deltaX = Math.abs(ev.getX() - mXDown); @@ -1315,11 +1317,9 @@ public class Workspace extends SmoothPagedView } private void updateStateForCustomContent(int screenCenter) { - if (hasCustomContent()) { + if (hasCustomContent() && !isSmall() && !isSwitchingState()) { int index = mScreenOrder.indexOf(CUSTOM_CONTENT_SCREEN_ID); - int scrollDelta = getScrollForPage(index + 1) - getScrollX(); - float progress = (1.0f * scrollDelta) / (getScrollForPage(index + 1) - getScrollForPage(index)); progress = Math.max(0, progress); @@ -1338,7 +1338,14 @@ public class Workspace extends SmoothPagedView mLauncher.getHotseat().setAlpha(1 - progress); } if (getPageIndicator() != null) { - getPageIndicator().setAlpha(1 - progress); + final float alpha = 1 - progress; + final View pi = getPageIndicator(); + getPageIndicator().setAlpha(alpha); + if (alpha < ALPHA_CUTOFF_THRESHOLD && pi.getVisibility() != INVISIBLE) { + pi.setVisibility(INVISIBLE); + } else if (alpha > ALPHA_CUTOFF_THRESHOLD && pi.getVisibility() != VISIBLE) { + pi.setVisibility(VISIBLE); + } } } } @@ -1474,7 +1481,7 @@ public class Workspace extends SmoothPagedView } public boolean isSmall() { - return mState == State.SMALL || mState == State.SPRING_LOADED; + return mState == State.SMALL || mState == State.SPRING_LOADED || mState == State.OVERVIEW; } void enableChildrenCache(int fromPage, int toPage) { @@ -1508,9 +1515,8 @@ public class Workspace extends SmoothPagedView } } - private void updateChildrenLayersEnabled(boolean force) { - boolean small = mState == State.SMALL || mIsSwitchingState; + boolean small = mState == State.SMALL || mState == State.OVERVIEW || mIsSwitchingState; boolean enableChildrenLayers = force || small || mAnimatingViewIntoPlace || isPageMoving(); if (enableChildrenLayers != mChildrenLayersEnabled) { @@ -1682,10 +1688,11 @@ public class Workspace extends SmoothPagedView } Animator getChangeStateAnimation(final State state, boolean animated) { - return getChangeStateAnimation(state, animated, 0); + return getChangeStateAnimation(state, animated, 0, -1); } - void getReorderablePages(int[] range) { + @Override + protected void getOverviewModePages(int[] range) { int count = mScreenOrder.size(); int start = -1; @@ -1734,7 +1741,43 @@ public class Workspace extends SmoothPagedView setLayoutTransition(mLayoutTransition); } - Animator getChangeStateAnimation(final State state, boolean animated, int delay) { + public boolean isInOverviewMode() { + return mState == State.OVERVIEW; + } + + public void enterOverviewMode() { + enableOverviewMode(true, -1); + } + + public void exitOverviewMode() { + exitOverviewMode(-1); + } + + public void exitOverviewMode(int snapPage) { + enableOverviewMode(false, snapPage); + } + + private void enableOverviewMode(boolean enable, int snapPage) { + State finalState = Workspace.State.OVERVIEW; + if (!enable) { + finalState = Workspace.State.NORMAL; + } + + Animator workspaceAnim = getChangeStateAnimation(finalState, true, 0, snapPage); + workspaceAnim.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator arg0) { + mIsSwitchingState = false; + } + @Override + public void onAnimationStart(Animator arg0) { + mIsSwitchingState = true; + } + }); + workspaceAnim.start(); + } + + Animator getChangeStateAnimation(final State state, boolean animated, int delay, int snapPage) { if (mState == state) { return null; } @@ -1744,23 +1787,37 @@ public class Workspace extends SmoothPagedView AnimatorSet anim = animated ? LauncherAnimUtils.createAnimatorSet() : null; - // Stop any scrolling, move to the current page right away - setCurrentPage(getNextPage()); - final State oldState = mState; final boolean oldStateIsNormal = (oldState == State.NORMAL); final boolean oldStateIsSpringLoaded = (oldState == State.SPRING_LOADED); final boolean oldStateIsSmall = (oldState == State.SMALL); + final boolean oldStateIsOverview = (oldState == State.OVERVIEW); mState = state; final boolean stateIsNormal = (state == State.NORMAL); final boolean stateIsSpringLoaded = (state == State.SPRING_LOADED); final boolean stateIsSmall = (state == State.SMALL); + final boolean stateIsOverview = (state == State.OVERVIEW); float finalBackgroundAlpha = stateIsSpringLoaded ? 1.0f : 0f; + float finalHotseatAndPageIndicatorAlpha = (stateIsOverview || stateIsSmall) ? 0f : 1f; + float finalOverviewPanelAlpha = stateIsOverview ? 1f : 0f; + boolean zoomIn = true; mNewScale = 1.0f; + if (oldStateIsOverview) { + disableFreeScroll(snapPage); + } else if (stateIsOverview) { + enableFreeScroll(); + } + if (state != State.NORMAL) { - mNewScale = mSpringLoadedShrinkFactor - (stateIsSmall ? 0.1f : 0); + if (stateIsSpringLoaded) { + mNewScale = mSpringLoadedShrinkFactor; + } else if (stateIsOverview) { + mNewScale = mOverviewModeShrinkFactor; + } else if (stateIsSmall){ + mNewScale = mOverviewModeShrinkFactor - 0.1f; + } if (oldStateIsNormal && stateIsSmall) { zoomIn = false; updateChildrenLayersEnabled(false); @@ -1844,7 +1901,24 @@ public class Workspace extends SmoothPagedView } } } + ObjectAnimator hotseatAlpha = ObjectAnimator.ofFloat(mLauncher.getHotseat(), "alpha", + finalHotseatAndPageIndicatorAlpha); + ObjectAnimator pageIndicatorAlpha = ObjectAnimator.ofFloat(getPageIndicator(), "alpha", + finalHotseatAndPageIndicatorAlpha); + ObjectAnimator overviewPanelAlpha = ObjectAnimator.ofFloat(mLauncher.getOverviewPanel(), + "alpha", finalOverviewPanelAlpha); + overviewPanelAlpha.addUpdateListener(new AlphaUpdateListener( + mLauncher.getOverviewPanel())); + hotseatAlpha.addUpdateListener(new AlphaUpdateListener(mLauncher.getHotseat())); + pageIndicatorAlpha.addUpdateListener(new AlphaUpdateListener(getPageIndicator())); + anim.play(overviewPanelAlpha); + anim.play(hotseatAlpha); + anim.play(pageIndicatorAlpha); anim.setStartDelay(delay); + } else { + mLauncher.getOverviewPanel().setAlpha(finalOverviewPanelAlpha); + mLauncher.getHotseat().setAlpha(finalHotseatAndPageIndicatorAlpha); + getPageIndicator().setAlpha(finalHotseatAndPageIndicatorAlpha); } if (stateIsSpringLoaded) { @@ -1860,6 +1934,24 @@ public class Workspace extends SmoothPagedView return anim; } + class AlphaUpdateListener implements AnimatorUpdateListener { + View view; + public AlphaUpdateListener(View v) { + view = v; + } + + @Override + public void onAnimationUpdate(ValueAnimator arg0) { + if (view.getAlpha() < ALPHA_CUTOFF_THRESHOLD && view.getVisibility() != INVISIBLE) { + view.setVisibility(INVISIBLE); + } else if (view.getAlpha() > ALPHA_CUTOFF_THRESHOLD + && view.getVisibility() != VISIBLE) { + view.setVisibility(VISIBLE); + } + } + + } + @Override public void onLauncherTransitionPrepare(Launcher l, boolean animated, boolean toWorkspace) { mIsSwitchingState = true; -- cgit v1.2.3