diff options
Diffstat (limited to 'src/com/android/launcher2/Workspace.java')
-rw-r--r-- | src/com/android/launcher2/Workspace.java | 814 |
1 files changed, 484 insertions, 330 deletions
diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java index a6a1ed535..dffaf896c 100644 --- a/src/com/android/launcher2/Workspace.java +++ b/src/com/android/launcher2/Workspace.java @@ -17,7 +17,6 @@ package com.android.launcher2; import android.animation.Animator; -import android.animation.Animator.AnimatorListener; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; @@ -42,7 +41,6 @@ import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Point; -import android.graphics.PorterDuff; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Region.Op; @@ -59,6 +57,8 @@ import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; import android.view.ViewGroup; +import android.view.View.MeasureSpec; +import android.view.animation.AccelerateInterpolator; import android.view.animation.DecelerateInterpolator; import android.widget.ImageView; import android.widget.TextView; @@ -79,7 +79,7 @@ import java.util.List; */ public class Workspace extends SmoothPagedView implements DropTarget, DragSource, DragScroller, View.OnTouchListener, - DragController.DragListener { + DragController.DragListener, LauncherTransitionable { @SuppressWarnings({"UnusedDeclaration"}) private static final String TAG = "Launcher.Workspace"; @@ -94,6 +94,7 @@ public class Workspace extends SmoothPagedView private static final int BACKGROUND_FADE_OUT_DURATION = 350; private static final int ADJACENT_SCREEN_DROP_DURATION = 300; + private static final int FLING_THRESHOLD_VELOCITY = 500; // These animators are used to fade the children's outlines private ObjectAnimator mChildrenOutlineFadeInAnimation; @@ -131,6 +132,7 @@ public class Workspace extends SmoothPagedView * The CellLayout that is currently being dragged over */ private CellLayout mDragTargetLayout = null; + private boolean mDragHasEnteredWorkspace = false; private Launcher mLauncher; private IconCache mIconCache; @@ -158,11 +160,6 @@ public class Workspace extends SmoothPagedView enum State { NORMAL, SPRING_LOADED, SMALL }; private State mState = State.NORMAL; private boolean mIsSwitchingState = false; - private boolean mSwitchStateAfterFirstLayout = false; - private State mStateAfterFirstLayout; - - private AnimatorSet mAnimator; - private AnimatorListener mChangeStateAnimationListener; boolean mAnimatingViewIntoPlace = false; boolean mIsDragOccuring = false; @@ -175,8 +172,8 @@ public class Workspace extends SmoothPagedView private Bitmap mDragOutline = null; private final Rect mTempRect = new Rect(); private final int[] mTempXY = new int[2]; - private int mDragViewMultiplyColor; private float mOverscrollFade = 0; + public static final int DRAG_BITMAP_PADDING = 0; // Paint used to draw external drop outline private final Paint mExternalDragOutlinePaint = new Paint(); @@ -194,6 +191,7 @@ public class Workspace extends SmoothPagedView private Runnable mDelayedResizeRunnable; private int mDisplayWidth; private int mDisplayHeight; + private boolean mIsStaticWallpaper; private int mWallpaperTravelWidth; // Variables relating to the creation of user folders by hovering shortcuts over shortcuts @@ -210,6 +208,17 @@ public class Workspace extends SmoothPagedView final static float MAX_SWIPE_ANGLE = (float) Math.PI / 3; final static float TOUCH_SLOP_DAMPING_FACTOR = 4; + // Relating to the animation of items being dropped externally + public static final int ANIMATE_INTO_POSITION_AND_DISAPPEAR = 0; + public static final int ANIMATE_INTO_POSITION_AND_REMAIN = 1; + public static final int ANIMATE_INTO_POSITION_AND_RESIZE = 2; + public static final int COMPLETE_TWO_STAGE_WIDGET_DROP_ANIMATION = 3; + public static final int CANCEL_TWO_STAGE_WIDGET_DROP_ANIMATION = 4; + + // Relating to workspace drag fade out + private float mDragFadeOutAlpha; + private int mDragFadeOutDuration; + // These variables are used for storing the initial and final values during workspace animations private int mSavedScrollX; private float mSavedRotationY; @@ -261,8 +270,10 @@ public class Workspace extends SmoothPagedView // With workspace, data is available straight from the get-go setDataIsReady(); - mFadeInAdjacentScreens = - getResources().getBoolean(R.bool.config_workspaceFadeAdjacentScreens); + final Resources res = getResources(); + mFadeInAdjacentScreens = res.getBoolean(R.bool.config_workspaceFadeAdjacentScreens); + mDragFadeOutAlpha = res.getInteger(R.integer.config_dragFadeOutAlpha) / 100f; + mDragFadeOutDuration = res.getInteger(R.integer.config_dragFadeOutDuration); mWallpaperManager = WallpaperManager.getInstance(context); int cellCountX = DEFAULT_CELL_COUNT_X; @@ -271,7 +282,6 @@ public class Workspace extends SmoothPagedView TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Workspace, defStyle, 0); - final Resources res = context.getResources(); if (LauncherApplication.isScreenLarge()) { // Determine number of rows/columns dynamically // TODO: This code currently fails on tablets with an aspect ratio < 1.3. @@ -299,7 +309,6 @@ public class Workspace extends SmoothPagedView mSpringLoadedShrinkFactor = res.getInteger(R.integer.config_workspaceSpringLoadShrinkPercentage) / 100.0f; - mDragViewMultiplyColor = res.getColor(R.color.drag_view_multiply_color); // if the value is manually specified, use that instead cellCountX = a.getInt(R.styleable.Workspace_cellCountX, cellCountX); @@ -320,13 +329,13 @@ public class Workspace extends SmoothPagedView // estimate the size of a widget with spans hSpan, vSpan. return MAX_VALUE for each // dimension if unsuccessful public int[] estimateItemSize(int hSpan, int vSpan, - PendingAddItemInfo pendingItemInfo, boolean springLoaded) { + ItemInfo itemInfo, boolean springLoaded) { int[] size = new int[2]; if (getChildCount() > 0) { CellLayout cl = (CellLayout) mLauncher.getWorkspace().getChildAt(0); - RectF r = estimateItemPosition(cl, pendingItemInfo, 0, 0, hSpan, vSpan); - size[0] = (int) r.width(); - size[1] = (int) r.height(); + Rect r = estimateItemPosition(cl, itemInfo, 0, 0, hSpan, vSpan); + size[0] = r.width(); + size[1] = r.height(); if (springLoaded) { size[0] *= mSpringLoadedShrinkFactor; size[1] *= mSpringLoadedShrinkFactor; @@ -338,19 +347,10 @@ public class Workspace extends SmoothPagedView return size; } } - public RectF estimateItemPosition(CellLayout cl, ItemInfo pendingInfo, + public Rect estimateItemPosition(CellLayout cl, ItemInfo pendingInfo, int hCell, int vCell, int hSpan, int vSpan) { - RectF r = new RectF(); + Rect r = new Rect(); cl.cellToRect(hCell, vCell, hSpan, vSpan, r); - if (pendingInfo instanceof PendingAddWidgetInfo) { - PendingAddWidgetInfo widgetInfo = (PendingAddWidgetInfo) pendingInfo; - Rect p = AppWidgetHostView.getDefaultPaddingForWidget(mContext, - widgetInfo.componentName, null); - r.top += p.top; - r.left += p.left; - r.right -= p.right; - r.bottom -= p.bottom; - } return r; } @@ -368,12 +368,32 @@ public class Workspace extends SmoothPagedView mIsDragOccuring = true; updateChildrenLayersEnabled(); mLauncher.lockScreenOrientationOnLargeUI(); + + // Fade out the workspace slightly to highlight the currently dragging item + int count = getChildCount(); + for (int i = 0; i < count; i++) { + CellLayout cl = (CellLayout) getPageAt(i); + cl.getChildrenLayout().animate().alpha(mDragFadeOutAlpha) + .setInterpolator(new AccelerateInterpolator(1.5f)) + .setDuration(mDragFadeOutDuration) + .start(); + } } public void onDragEnd() { mIsDragOccuring = false; updateChildrenLayersEnabled(); mLauncher.unlockScreenOrientationOnLargeUI(); + + // Fade the workspace back in after we have completed dragging + int count = getChildCount(); + for (int i = 0; i < count; i++) { + CellLayout cl = (CellLayout) getPageAt(i); + cl.getChildrenLayout().animate().alpha(1f) + .setInterpolator(new DecelerateInterpolator(1.5f)) + .setDuration(mDragFadeOutDuration) + .start(); + } } /** @@ -396,28 +416,15 @@ public class Workspace extends SmoothPagedView // In this case, we will skip drawing background protection } - mChangeStateAnimationListener = new AnimatorListenerAdapter() { - @Override - public void onAnimationStart(Animator animation) { - mIsSwitchingState = true; - } - - @Override - public void onAnimationEnd(Animator animation) { - mIsSwitchingState = false; - mWallpaperOffset.setOverrideHorizontalCatchupConstant(false); - mAnimator = null; - updateChildrenLayersEnabled(); - } - }; - - mSnapVelocity = 600; mWallpaperOffset = new WallpaperOffsetInterpolator(); Display display = mLauncher.getWindowManager().getDefaultDisplay(); mDisplayWidth = display.getWidth(); mDisplayHeight = display.getHeight(); mWallpaperTravelWidth = (int) (mDisplayWidth * wallpaperTravelToScreenWidthRatio(mDisplayWidth, mDisplayHeight)); + + mFlingThresholdVelocity = (int) (FLING_THRESHOLD_VELOCITY * mDensity); + } @Override @@ -523,10 +530,12 @@ public class Workspace extends SmoothPagedView child.setOnKeyListener(new IconKeyEventListener()); } - CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams(); - if (lp == null) { + LayoutParams genericLp = child.getLayoutParams(); + CellLayout.LayoutParams lp; + if (genericLp == null || !(genericLp instanceof CellLayout.LayoutParams)) { lp = new CellLayout.LayoutParams(x, y, spanX, spanY); } else { + lp = (CellLayout.LayoutParams) genericLp; lp.cellX = x; lp.cellY = y; lp.cellHSpan = spanX; @@ -599,20 +608,26 @@ public class Workspace extends SmoothPagedView */ @Override public boolean onTouch(View v, MotionEvent event) { - return (isSmall() || mIsSwitchingState); + return (isSmall() || !isFinishedSwitchingState()); } public boolean isSwitchingState() { return mIsSwitchingState; } + /** This differs from isSwitchingState in that we take into account how far the transition + * has completed. */ + public boolean isFinishedSwitchingState() { + return !mIsSwitchingState || (mTransitionProgress > 0.5f); + } + protected void onWindowVisibilityChanged (int visibility) { mLauncher.onWindowVisibilityChanged(visibility); } @Override public boolean dispatchUnhandledMove(View focused, int direction) { - if (isSmall() || mIsSwitchingState) { + if (isSmall() || !isFinishedSwitchingState()) { // when the home screens are shrunken, shouldn't allow side-scrolling return false; } @@ -640,35 +655,36 @@ public class Workspace extends SmoothPagedView @Override protected void determineScrollingStart(MotionEvent ev) { - if (!isSmall() && !mIsSwitchingState) { - float deltaX = Math.abs(ev.getX() - mXDown); - float deltaY = Math.abs(ev.getY() - mYDown); + if (isSmall()) return; + if (!isFinishedSwitchingState()) return; - if (Float.compare(deltaX, 0f) == 0) return; + float deltaX = Math.abs(ev.getX() - mXDown); + float deltaY = Math.abs(ev.getY() - mYDown); - float slope = deltaY / deltaX; - float theta = (float) Math.atan(slope); + if (Float.compare(deltaX, 0f) == 0) return; - if (deltaX > mTouchSlop || deltaY > mTouchSlop) { - cancelCurrentPageLongPress(); - } + float slope = deltaY / deltaX; + float theta = (float) Math.atan(slope); - if (theta > MAX_SWIPE_ANGLE) { - // Above MAX_SWIPE_ANGLE, we don't want to ever start scrolling the workspace - return; - } else if (theta > START_DAMPING_TOUCH_SLOP_ANGLE) { - // Above START_DAMPING_TOUCH_SLOP_ANGLE and below MAX_SWIPE_ANGLE, we want to - // increase the touch slop to make it harder to begin scrolling the workspace. This - // results in vertically scrolling widgets to more easily. The higher the angle, the - // more we increase touch slop. - theta -= START_DAMPING_TOUCH_SLOP_ANGLE; - float extraRatio = (float) - Math.sqrt((theta / (MAX_SWIPE_ANGLE - START_DAMPING_TOUCH_SLOP_ANGLE))); - super.determineScrollingStart(ev, 1 + TOUCH_SLOP_DAMPING_FACTOR * extraRatio); - } else { - // Below START_DAMPING_TOUCH_SLOP_ANGLE, we don't do anything special - super.determineScrollingStart(ev); - } + if (deltaX > mTouchSlop || deltaY > mTouchSlop) { + cancelCurrentPageLongPress(); + } + + if (theta > MAX_SWIPE_ANGLE) { + // Above MAX_SWIPE_ANGLE, we don't want to ever start scrolling the workspace + return; + } else if (theta > START_DAMPING_TOUCH_SLOP_ANGLE) { + // Above START_DAMPING_TOUCH_SLOP_ANGLE and below MAX_SWIPE_ANGLE, we want to + // increase the touch slop to make it harder to begin scrolling the workspace. This + // results in vertically scrolling widgets to more easily. The higher the angle, the + // more we increase touch slop. + theta -= START_DAMPING_TOUCH_SLOP_ANGLE; + float extraRatio = (float) + Math.sqrt((theta / (MAX_SWIPE_ANGLE - START_DAMPING_TOUCH_SLOP_ANGLE))); + super.determineScrollingStart(ev, 1 + TOUCH_SLOP_DAMPING_FACTOR * extraRatio); + } else { + // Below START_DAMPING_TOUCH_SLOP_ANGLE, we don't do anything special + super.determineScrollingStart(ev); } } @@ -696,7 +712,19 @@ public class Workspace extends SmoothPagedView // Only show page outlines as we pan if we are on large screen if (LauncherApplication.isScreenLarge()) { showOutlines(); + mIsStaticWallpaper = mWallpaperManager.getWallpaperInfo() == null; + } + + // If we are not fading in adjacent screens, we still need to restore the alpha in case the + // user scrolls while we are transitioning (should not affect dispatchDraw optimizations) + if (!mFadeInAdjacentScreens) { + for (int i = 0; i < getChildCount(); ++i) { + getPageAt(i).setAlpha(1f); + } } + + // Show the scroll indicator as you pan the page + showScrollingIndicator(false); } protected void onPageEndMoving() { @@ -708,12 +736,23 @@ public class Workspace extends SmoothPagedView clearChildrenCache(); } - // Hide the outlines, as long as we're not dragging - if (!mDragController.dragging()) { - // Only hide page outlines as we pan if we are on large screen + + if (mDragController.isDragging()) { + if (isSmall()) { + // If we are in springloaded mode, then force an event to check if the current touch + // is under a new page (to scroll to) + mDragController.forceMoveEvent(); + } + } else { + // If we are not mid-dragging, hide the page outlines if we are on a large screen if (LauncherApplication.isScreenLarge()) { hideOutlines(); } + + // Hide the scroll indicator as you pan the page + if (!mDragController.isDragging()) { + hideScrollingIndicator(false); + } } mOverScrollMaxBackgroundAlpha = 0.0f; mOverScrollPageIndex = -1; @@ -784,28 +823,7 @@ public class Workspace extends SmoothPagedView }.start(); } - public void setVerticalWallpaperOffset(float offset) { - mWallpaperOffset.setFinalY(offset); - } - public float getVerticalWallpaperOffset() { - return mWallpaperOffset.getCurrY(); - } - public void setHorizontalWallpaperOffset(float offset) { - mWallpaperOffset.setFinalX(offset); - } - public float getHorizontalWallpaperOffset() { - return mWallpaperOffset.getCurrX(); - } - private float wallpaperOffsetForCurrentScroll() { - // The wallpaper travel width is how far, from left to right, the wallpaper will move - // at this orientation. On tablets in portrait mode we don't move all the way to the - // edges of the wallpaper, or otherwise the parallax effect would be too strong. - int wallpaperTravelWidth = mWallpaperWidth; - if (LauncherApplication.isScreenLarge()) { - wallpaperTravelWidth = mWallpaperTravelWidth; - } - // Set wallpaper offset steps (1 / (number of screens - 1)) mWallpaperManager.setWallpaperOffsetSteps(1.0f / (getChildCount() - 1), 1.0f); @@ -823,11 +841,22 @@ public class Workspace extends SmoothPagedView float scrollProgress = adjustedScrollX / (float) scrollRange; - float offsetInDips = wallpaperTravelWidth * scrollProgress + - (mWallpaperWidth - wallpaperTravelWidth) / 2; // center it - float offset = offsetInDips / (float) mWallpaperWidth; - return offset; + + if (LauncherApplication.isScreenLarge() && mIsStaticWallpaper) { + // The wallpaper travel width is how far, from left to right, the wallpaper will move + // at this orientation. On tablets in portrait mode we don't move all the way to the + // edges of the wallpaper, or otherwise the parallax effect would be too strong. + int wallpaperTravelWidth = Math.min(mWallpaperTravelWidth, mWallpaperWidth); + + float offsetInDips = wallpaperTravelWidth * scrollProgress + + (mWallpaperWidth - wallpaperTravelWidth) / 2; // center it + float offset = offsetInDips / (float) mWallpaperWidth; + return offset; + } else { + return scrollProgress; + } } + private void syncWallpaperOffsetWithScroll() { final boolean enableWallpaperEffects = isHardwareAccelerated(); if (enableWallpaperEffects) { @@ -857,7 +886,7 @@ public class Workspace extends SmoothPagedView } } if (keepUpdating) { - fastInvalidate(); + invalidate(); } } @@ -1169,13 +1198,12 @@ public class Workspace extends SmoothPagedView backgroundAlphaInterpolator(Math.abs(scrollProgress))); } } - cl.setFastTranslationX(translationX); - cl.setFastRotationY(rotation); + cl.setTranslationX(translationX); + cl.setRotationY(rotation); if (mFadeInAdjacentScreens && !isSmall()) { float alpha = 1 - Math.abs(scrollProgress); - cl.setFastAlpha(alpha); + cl.setAlpha(alpha); } - cl.fastInvalidate(); } } if (!isSwitchingState() && !isInOverscroll) { @@ -1248,19 +1276,6 @@ public class Workspace extends SmoothPagedView mUpdateWallpaperOffsetImmediately = true; } super.onLayout(changed, left, top, right, bottom); - - // if shrinkToBottom() is called on initialization, it has to be deferred - // until after the first call to onLayout so that it has the correct width - if (mSwitchStateAfterFirstLayout) { - mSwitchStateAfterFirstLayout = false; - // shrink can trigger a synchronous onLayout call, so we - // post this to avoid a stack overflow / tangled onLayout calls - post(new Runnable() { - public void run() { - changeState(mStateAfterFirstLayout, false); - } - }); - } } @Override @@ -1283,32 +1298,6 @@ public class Workspace extends SmoothPagedView return (mBackground != null && mBackgroundAlpha > 0.0f && mDrawBackground); } - public void scrollTo (int x, int y) { - super.scrollTo(x, y); - syncChildrenLayersEnabledOnVisiblePages(); - } - - // This method just applies the value mChildrenLayersEnabled to all the pages that - // will be rendered on the next frame. - // We do this because calling setChildrenLayersEnabled on a view that's not - // visible/rendered causes slowdowns on some graphics cards - private void syncChildrenLayersEnabledOnVisiblePages() { - if (mChildrenLayersEnabled) { - getVisiblePages(mTempVisiblePagesRange); - final int leftScreen = mTempVisiblePagesRange[0]; - final int rightScreen = mTempVisiblePagesRange[1]; - if (leftScreen != -1 && rightScreen != -1) { - for (int i = leftScreen; i <= rightScreen; i++) { - ViewGroup page = (ViewGroup) getPageAt(i); - if (page.getVisibility() == VISIBLE && - page.getAlpha() > ViewConfiguration.ALPHA_THRESHOLD) { - ((ViewGroup)getPageAt(i)).setChildrenLayersEnabled(true); - } - } - } - } - } - @Override protected void dispatchDraw(Canvas canvas) { super.dispatchDraw(canvas); @@ -1323,8 +1312,9 @@ public class Workspace extends SmoothPagedView final int paddingTop = mPaddingTop + offset; final int paddingBottom = mPaddingBottom + offset; - final CellLayout leftPage = (CellLayout) getChildAt(mCurrentPage - 1); - final CellLayout rightPage = (CellLayout) getChildAt(mCurrentPage + 1); + final int page = (mNextPage != INVALID_PAGE ? mNextPage : mCurrentPage); + final CellLayout leftPage = (CellLayout) getChildAt(page - 1); + final CellLayout rightPage = (CellLayout) getChildAt(page + 1); if (leftPage != null && leftPage.getIsDragOverlapping()) { final Drawable d = getResources().getDrawable(R.drawable.page_hover_left_holo); @@ -1415,13 +1405,8 @@ public class Workspace extends SmoothPagedView if (enableChildrenLayers != mChildrenLayersEnabled) { mChildrenLayersEnabled = enableChildrenLayers; - // calling setChildrenLayersEnabled on a view that's not visible/rendered - // causes slowdowns on some graphics cards, so we only disable it here and leave - // the enabling to dispatchDraw - if (!enableChildrenLayers) { - for (int i = 0; i < getPageCount(); i++) { - ((ViewGroup)getChildAt(i)).setChildrenLayersEnabled(false); - } + for (int i = 0; i < getPageCount(); i++) { + ((ViewGroup)getChildAt(i)).setChildrenLayersEnabled(mChildrenLayersEnabled); } } } @@ -1510,23 +1495,18 @@ public class Workspace extends SmoothPagedView public void onDragStartedWithItem(View v) { final Canvas canvas = new Canvas(); - // We need to add extra padding to the bitmap to make room for the glow effect - final int bitmapPadding = HolographicOutlineHelper.MAX_OUTER_BLUR_RADIUS; - // The outline is used to visualize where the item will land if dropped - mDragOutline = createDragOutline(v, canvas, bitmapPadding); + mDragOutline = createDragOutline(v, canvas, DRAG_BITMAP_PADDING); } public void onDragStartedWithItem(PendingAddItemInfo info, Bitmap b, Paint alphaClipPaint) { final Canvas canvas = new Canvas(); - // We need to add extra padding to the bitmap to make room for the glow effect - final int bitmapPadding = HolographicOutlineHelper.MAX_OUTER_BLUR_RADIUS; - int[] size = estimateItemSize(info.spanX, info.spanY, info, false); // The outline is used to visualize where the item will land if dropped - mDragOutline = createDragOutline(b, canvas, bitmapPadding, size[0], size[1], alphaClipPaint); + mDragOutline = createDragOutline(b, canvas, DRAG_BITMAP_PADDING, size[0], + size[1], alphaClipPaint); } // we call this method whenever a drag and drop in Launcher finishes, even if Workspace was @@ -1564,32 +1544,19 @@ public class Workspace extends SmoothPagedView mNewRotationYs = new float[childCount]; } - public void changeState(State shrinkState) { - changeState(shrinkState, true); + Animator getChangeStateAnimation(final State state, boolean animated) { + return getChangeStateAnimation(state, animated, 0); } - void changeState(final State state, boolean animated) { - changeState(state, animated, 0); - } - - void changeState(final State state, boolean animated, int delay) { + Animator getChangeStateAnimation(final State state, boolean animated, int delay) { if (mState == state) { - return; - } - if (mFirstLayout) { - // (mFirstLayout == "first layout has not happened yet") - // cancel any pending shrinks that were set earlier - mSwitchStateAfterFirstLayout = false; - mStateAfterFirstLayout = state; - return; + return null; } // Initialize animation arrays for the first time if necessary initAnimationArrays(); - // Cancel any running transition animations - if (mAnimator != null) mAnimator.cancel(); - mAnimator = new AnimatorSet(); + AnimatorSet anim = animated ? new AnimatorSet() : null; // Stop any scrolling, move to the current page right away setCurrentPage((mNextPage != INVALID_PAGE) ? mNextPage : mCurrentPage); @@ -1689,81 +1656,65 @@ public class Workspace extends SmoothPagedView cl.setBackgroundAlphaMultiplier(finalAlphaMultiplierValue); cl.setAlpha(finalAlpha); cl.setRotationY(rotation); - mChangeStateAnimationListener.onAnimationEnd(null); } } if (animated) { - ValueAnimator animWithInterpolator = - ValueAnimator.ofFloat(0f, 1f).setDuration(duration); - - if (zoomIn) { - animWithInterpolator.setInterpolator(mZoomInInterpolator); - } - - animWithInterpolator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(android.animation.Animator animation) { - // The above code to determine initialAlpha and finalAlpha will ensure that only - // the current page is visible during (and subsequently, after) the transition - // animation. If fade adjacent pages is disabled, then re-enable the page - // visibility after the transition animation. - if (!mFadeInAdjacentScreens && stateIsNormal && oldStateIsSmall) { - for (int i = 0; i < getChildCount(); i++) { - final CellLayout cl = (CellLayout) getChildAt(i); - cl.setAlpha(1f); - } - } - } - }); - animWithInterpolator.addUpdateListener(new LauncherAnimatorUpdateListener() { - public void onAnimationUpdate(float a, float b) { - mTransitionProgress = b; - if (b == 0f) { - // an optimization, but not required - return; - } - invalidate(); - for (int i = 0; i < getChildCount(); i++) { - final CellLayout cl = (CellLayout) getChildAt(i); - cl.invalidate(); - cl.setFastTranslationX(a * mOldTranslationXs[i] + b * mNewTranslationXs[i]); - cl.setFastTranslationY(a * mOldTranslationYs[i] + b * mNewTranslationYs[i]); - cl.setFastScaleX(a * mOldScaleXs[i] + b * mNewScaleXs[i]); - cl.setFastScaleY(a * mOldScaleYs[i] + b * mNewScaleYs[i]); - cl.setFastBackgroundAlpha( - a * mOldBackgroundAlphas[i] + b * mNewBackgroundAlphas[i]); - cl.setBackgroundAlphaMultiplier(a * mOldBackgroundAlphaMultipliers[i] + - b * mNewBackgroundAlphaMultipliers[i]); - cl.setFastAlpha(a * mOldAlphas[i] + b * mNewAlphas[i]); - cl.invalidate(); + for (int index = 0; index < getChildCount(); index++) { + final int i = index; + final CellLayout cl = (CellLayout) getChildAt(i); + if (mOldAlphas[i] == 0 && mNewAlphas[i] == 0) { + cl.setTranslationX(mNewTranslationXs[i]); + cl.setTranslationY(mNewTranslationYs[i]); + cl.setScaleX(mNewScaleXs[i]); + cl.setScaleY(mNewScaleYs[i]); + cl.setBackgroundAlpha(mNewBackgroundAlphas[i]); + cl.setBackgroundAlphaMultiplier(mNewBackgroundAlphaMultipliers[i]); + cl.setAlpha(mNewAlphas[i]); + cl.setRotationY(mNewRotationYs[i]); + } else { + LauncherViewPropertyAnimator a = new LauncherViewPropertyAnimator(cl); + a.translationX(mNewTranslationXs[i]) + .translationY(mNewTranslationYs[i]) + .scaleX(mNewScaleXs[i]) + .scaleY(mNewScaleYs[i]) + .setDuration(duration) + .setInterpolator(mZoomInInterpolator); + if (mOldAlphas[i] != mNewAlphas[i]) { + a.alpha(mNewAlphas[i]); } - syncChildrenLayersEnabledOnVisiblePages(); - } - }); - - ValueAnimator rotationAnim = - ValueAnimator.ofFloat(0f, 1f).setDuration(duration); - rotationAnim.setInterpolator(new DecelerateInterpolator(2.0f)); - rotationAnim.addUpdateListener(new LauncherAnimatorUpdateListener() { - public void onAnimationUpdate(float a, float b) { - if (b == 0f) { - // an optimization, but not required - return; + anim.play(a); + if (mOldRotationYs[i] != 0 || mNewRotationYs[i] != 0) { + ValueAnimator rotate = ValueAnimator.ofFloat(0f, 1f).setDuration(duration); + rotate.setInterpolator(new DecelerateInterpolator(2.0f)); + rotate.addUpdateListener(new LauncherAnimatorUpdateListener() { + public void onAnimationUpdate(float a, float b) { + cl.setRotationY(a * mOldRotationYs[i] + b * mNewRotationYs[i]); + } + }); + anim.play(rotate); } - for (int i = 0; i < getChildCount(); i++) { - final CellLayout cl = (CellLayout) getChildAt(i); - cl.setFastRotationY(a * mOldRotationYs[i] + b * mNewRotationYs[i]); + if (mOldBackgroundAlphas[i] != 0 || + mNewBackgroundAlphas[i] != 0 || + mOldBackgroundAlphaMultipliers[i] != 0 || + mNewBackgroundAlphaMultipliers[i] != 0) { + ValueAnimator bgAnim = ValueAnimator.ofFloat(0f, 1f).setDuration(duration); + bgAnim.setInterpolator(mZoomInInterpolator); + bgAnim.addUpdateListener(new LauncherAnimatorUpdateListener() { + public void onAnimationUpdate(float a, float b) { + cl.setBackgroundAlpha( + a * mOldBackgroundAlphas[i] + + b * mNewBackgroundAlphas[i]); + cl.setBackgroundAlphaMultiplier( + a * mOldBackgroundAlphaMultipliers[i] + + b * mNewBackgroundAlphaMultipliers[i]); + } + }); + anim.play(bgAnim); } } - }); - - mAnimator.playTogether(animWithInterpolator, rotationAnim); - mAnimator.setStartDelay(delay); - // If we call this when we're not animated, onAnimationEnd is never called on - // the listener; make sure we only use the listener when we're actually animating - mAnimator.addListener(mChangeStateAnimationListener); - mAnimator.start(); + } + anim.setStartDelay(delay); } if (stateIsSpringLoaded) { @@ -1776,7 +1727,39 @@ public class Workspace extends SmoothPagedView // Fade the background gradient away animateBackgroundGradient(0f, true); } - syncChildrenLayersEnabledOnVisiblePages(); + return anim; + } + + @Override + public void onLauncherTransitionStart(Launcher l, boolean animated, boolean toWorkspace) { + mIsSwitchingState = true; + } + + @Override + public void onLauncherTransitionStep(Launcher l, float t) { + mTransitionProgress = t; + } + + @Override + public void onLauncherTransitionEnd(Launcher l, boolean animated, boolean toWorkspace) { + mIsSwitchingState = false; + mWallpaperOffset.setOverrideHorizontalCatchupConstant(false); + updateChildrenLayersEnabled(); + // The code in getChangeStateAnimation to determine initialAlpha and finalAlpha will ensure + // ensure that only the current page is visible during (and subsequently, after) the + // transition animation. If fade adjacent pages is disabled, then re-enable the page + // visibility after the transition animation. + if (!mFadeInAdjacentScreens) { + for (int i = 0; i < getChildCount(); i++) { + final CellLayout cl = (CellLayout) getChildAt(i); + cl.setAlpha(1f); + } + } + } + + @Override + public View getContent() { + return this; } /** @@ -1846,8 +1829,6 @@ public class Workspace extends SmoothPagedView canvas.setBitmap(b); drawDragView(v, canvas, padding, true); - mOutlineHelper.applyOuterBlur(b, canvas, outlineColor); - canvas.drawColor(mDragViewMultiplyColor, PorterDuff.Mode.MULTIPLY); canvas.setBitmap(null); return b; @@ -1929,35 +1910,29 @@ public class Workspace extends SmoothPagedView } mDragInfo = cellInfo; - child.setVisibility(GONE); + child.setVisibility(INVISIBLE); child.clearFocus(); child.setPressed(false); final Canvas canvas = new Canvas(); - // We need to add extra padding to the bitmap to make room for the glow effect - final int bitmapPadding = HolographicOutlineHelper.MAX_OUTER_BLUR_RADIUS; - // The outline is used to visualize where the item will land if dropped - mDragOutline = createDragOutline(child, canvas, bitmapPadding); + mDragOutline = createDragOutline(child, canvas, DRAG_BITMAP_PADDING); beginDragShared(child, this); } public void beginDragShared(View child, DragSource source) { Resources r = getResources(); - // We need to add extra padding to the bitmap to make room for the glow effect - final int bitmapPadding = HolographicOutlineHelper.MAX_OUTER_BLUR_RADIUS; - // The drag bitmap follows the touch point around on the screen - final Bitmap b = createDragBitmap(child, new Canvas(), bitmapPadding); + final Bitmap b = createDragBitmap(child, new Canvas(), DRAG_BITMAP_PADDING); final int bmpWidth = b.getWidth(); mLauncher.getDragLayer().getLocationInDragLayer(child, mTempXY); final int dragLayerX = (int) mTempXY[0] + (child.getWidth() - bmpWidth) / 2; - int dragLayerY = mTempXY[1] - bitmapPadding / 2; + int dragLayerY = mTempXY[1] - DRAG_BITMAP_PADDING / 2; Point dragVisualizeOffset = null; Rect dragRect = null; @@ -1971,7 +1946,8 @@ public class Workspace extends SmoothPagedView dragLayerY += top; // Note: The drag region is used to calculate drag layer offsets, but the // dragVisualizeOffset in addition to the dragRect (the size) to position the outline. - dragVisualizeOffset = new Point(-bitmapPadding / 2, iconPaddingTop - bitmapPadding / 2); + dragVisualizeOffset = new Point(-DRAG_BITMAP_PADDING / 2, + iconPaddingTop - DRAG_BITMAP_PADDING / 2); dragRect = new Rect(left, top, right, bottom); } else if (child instanceof FolderIcon) { int previewSize = r.getDimensionPixelSize(R.dimen.folder_preview_size); @@ -1985,8 +1961,11 @@ public class Workspace extends SmoothPagedView } mDragController.startDrag(b, dragLayerX, dragLayerY, source, child.getTag(), - DragController.DRAG_ACTION_MOVE, dragVisualizeOffset, dragRect); + DragController.DRAG_ACTION_MOVE, dragVisualizeOffset, dragRect, 1f); b.recycle(); + + // Show the scrolling indicator when you pick up an item + showScrollingIndicator(false); } void addApplicationShortcut(ShortcutInfo info, CellLayout target, long container, int screen, @@ -2001,7 +1980,7 @@ public class Workspace extends SmoothPagedView } public boolean transitionStateShouldAllowDrop() { - return (!isSwitchingState() || mTransitionProgress > 0.5f); + return ((!isSwitchingState() || mTransitionProgress > 0.5f) && mState != State.SMALL); } /** @@ -2040,8 +2019,15 @@ public class Workspace extends SmoothPagedView spanY = dragInfo.spanY; } + int minSpanX = spanX; + int minSpanY = spanY; + if (d.dragInfo instanceof PendingAddWidgetInfo) { + minSpanX = ((PendingAddWidgetInfo) d.dragInfo).minSpanX; + minSpanY = ((PendingAddWidgetInfo) d.dragInfo).minSpanY; + } mTargetCell = findNearestArea((int) mDragViewVisualCenter[0], - (int) mDragViewVisualCenter[1], spanX, spanY, mDragTargetLayout, mTargetCell); + (int) mDragViewVisualCenter[1], minSpanX, minSpanY, mDragTargetLayout, + mTargetCell); if (willCreateUserFolder((ItemInfo) d.dragInfo, mDragTargetLayout, mTargetCell, true)) { return true; } @@ -2051,7 +2037,7 @@ public class Workspace extends SmoothPagedView } // Don't accept the drop if there's no room for the item - if (!mDragTargetLayout.findCellForSpanIgnoring(null, spanX, spanY, ignoreView)) { + if (!mDragTargetLayout.findCellForSpanIgnoring(null, minSpanX, minSpanY, ignoreView)) { // Don't show the message if we are dropping on the AllApps button and the hotseat // is full if (mTargetCell != null && mLauncher.isHotseatLayout(mDragTargetLayout)) { @@ -2171,7 +2157,7 @@ public class Workspace extends SmoothPagedView return false; } - public void onDrop(DragObject d) { + public void onDrop(final DragObject d) { mDragViewVisualCenter = getDragViewVisualCenter(d.x, d.y, d.xOffset, d.yOffset, d.dragView, mDragViewVisualCenter); @@ -2187,6 +2173,7 @@ public class Workspace extends SmoothPagedView CellLayout dropTargetLayout = mDragTargetLayout; int snapScreen = -1; + boolean resizeOnDrop = false; if (d.dragSource != this) { final int[] touchXY = new int[] { (int) mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1] }; @@ -2194,6 +2181,7 @@ public class Workspace extends SmoothPagedView } else if (mDragInfo != null) { final View cell = mDragInfo.cell; + Runnable resizeRunnable = null; if (dropTargetLayout != null) { // Move internally boolean hasMovedLayouts = (getParentCellLayoutForView(cell) != dropTargetLayout); @@ -2222,29 +2210,46 @@ public class Workspace extends SmoothPagedView // Aside from the special case where we're dropping a shortcut onto a shortcut, // we need to find the nearest cell location that is vacant + ItemInfo item = (ItemInfo) d.dragInfo; + int minSpanX = item.spanX; + int minSpanY = item.spanY; + if (item.minSpanX > 0 && item.minSpanY > 0) { + minSpanX = item.minSpanX; + minSpanY = item.minSpanY; + } + int[] resultSpan = new int[2]; mTargetCell = findNearestVacantArea((int) mDragViewVisualCenter[0], - (int) mDragViewVisualCenter[1], mDragInfo.spanX, mDragInfo.spanY, cell, - dropTargetLayout, mTargetCell); + (int) mDragViewVisualCenter[1], minSpanX, minSpanY, mDragInfo.spanX, + mDragInfo.spanY, cell, dropTargetLayout, mTargetCell, resultSpan); + boolean foundCell = mTargetCell[0] >= 0 && mTargetCell[1] >= 0; + if (foundCell && (resultSpan[0] != item.spanX || resultSpan[1] != item.spanY)) { + resizeOnDrop = true; + item.spanX = resultSpan[0]; + item.spanY = resultSpan[1]; + } if (mCurrentPage != screen && !hasMovedIntoHotseat) { snapScreen = screen; snapToPage(screen); } - if (mTargetCell[0] >= 0 && mTargetCell[1] >= 0) { + if (foundCell) { + final ItemInfo info = (ItemInfo) cell.getTag(); if (hasMovedLayouts) { // Reparent the view getParentCellLayoutForView(cell).removeView(cell); addInScreen(cell, container, screen, mTargetCell[0], mTargetCell[1], - mDragInfo.spanX, mDragInfo.spanY); + info.spanX, info.spanY); } // update the item's position after drop - final ItemInfo info = (ItemInfo) cell.getTag(); CellLayout.LayoutParams lp = (CellLayout.LayoutParams) cell.getLayoutParams(); - dropTargetLayout.onMove(cell, mTargetCell[0], mTargetCell[1]); + dropTargetLayout.onMove(cell, mTargetCell[0], mTargetCell[1], + item.spanX, item.spanY); lp.cellX = mTargetCell[0]; lp.cellY = mTargetCell[1]; + lp.cellHSpan = item.spanX; + lp.cellVSpan = item.spanY; cell.setId(LauncherModel.getCellLayoutChildId(container, mDragInfo.screen, mTargetCell[0], mTargetCell[1], mDragInfo.spanX, mDragInfo.spanY)); @@ -2257,18 +2262,18 @@ public class Workspace extends SmoothPagedView final LauncherAppWidgetHostView hostView = (LauncherAppWidgetHostView) cell; AppWidgetProviderInfo pinfo = hostView.getAppWidgetInfo(); if (pinfo.resizeMode != AppWidgetProviderInfo.RESIZE_NONE) { - final Runnable resizeRunnable = new Runnable() { + final Runnable addResizeFrame = new Runnable() { public void run() { DragLayer dragLayer = mLauncher.getDragLayer(); dragLayer.addResizeFrame(info, hostView, cellLayout); } }; - post(new Runnable() { + resizeRunnable = (new Runnable() { public void run() { if (!isPageMoving()) { - resizeRunnable.run(); + addResizeFrame.run(); } else { - mDelayedResizeRunnable = resizeRunnable; + mDelayedResizeRunnable = addResizeFrame; } } }); @@ -2277,28 +2282,42 @@ public class Workspace extends SmoothPagedView LauncherModel.moveItemInDatabase(mLauncher, info, container, screen, lp.cellX, lp.cellY); + } else { + // If we can't find a drop location, we return the item to its original position + CellLayout.LayoutParams lp = (CellLayout.LayoutParams) cell.getLayoutParams(); + mTargetCell[0] = lp.cellX; + mTargetCell[1] = lp.cellY; } } final CellLayout parent = (CellLayout) cell.getParent().getParent(); - + final Runnable finalResizeRunnable = resizeRunnable; // Prepare it to be animated into its new position // This must be called after the view has been re-parented - final Runnable disableHardwareLayersRunnable = new Runnable() { + final Runnable onCompleteRunnable = new Runnable() { @Override public void run() { mAnimatingViewIntoPlace = false; updateChildrenLayersEnabled(); + if (finalResizeRunnable != null) { + finalResizeRunnable.run(); + } } }; mAnimatingViewIntoPlace = true; if (d.dragView.hasDrawn()) { - int duration = snapScreen < 0 ? -1 : ADJACENT_SCREEN_DROP_DURATION; - setFinalScrollForPageChange(snapScreen); - mLauncher.getDragLayer().animateViewIntoPosition(d.dragView, cell, duration, - disableHardwareLayersRunnable); - resetFinalScrollForPageChange(snapScreen); + final ItemInfo info = (ItemInfo) cell.getTag(); + if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET) { + int animationType = resizeOnDrop ? ANIMATE_INTO_POSITION_AND_RESIZE : + ANIMATE_INTO_POSITION_AND_DISAPPEAR; + animateWidgetDrop(info, parent, d.dragView, + onCompleteRunnable, animationType, cell, false); + } else { + mLauncher.getDragLayer().animateViewIntoPosition(d.dragView, cell, + onCompleteRunnable); + } } else { + d.deferDragViewCleanupPostAnimation = false; cell.setVisibility(VISIBLE); } parent.onDropChild(cell); @@ -2341,6 +2360,7 @@ public class Workspace extends SmoothPagedView } public void onDragEnter(DragObject d) { + mDragHasEnteredWorkspace = true; if (mDragTargetLayout != null) { mDragTargetLayout.setIsDragOverlapping(false); mDragTargetLayout.onDragExit(); @@ -2376,6 +2396,7 @@ public class Workspace extends SmoothPagedView } public void onDragExit(DragObject d) { + mDragHasEnteredWorkspace = false; doDragExit(d); } @@ -2443,19 +2464,18 @@ public class Workspace extends SmoothPagedView // Create the drag outline // We need to add extra padding to the bitmap to make room for the glow effect final Canvas canvas = new Canvas(); - final int bitmapPadding = HolographicOutlineHelper.MAX_OUTER_BLUR_RADIUS; - mDragOutline = createExternalDragOutline(canvas, bitmapPadding); + mDragOutline = createExternalDragOutline(canvas, DRAG_BITMAP_PADDING); // Show the current page outlines to indicate that we can accept this drop showOutlines(); layout.onDragEnter(); - layout.visualizeDropLocation(null, mDragOutline, x, y, 1, 1, null, null); + layout.visualizeDropLocation(null, mDragOutline, x, y, 1, 1, 1, 1, null, null); return true; } case DragEvent.ACTION_DRAG_LOCATION: // Visualize the drop location - layout.visualizeDropLocation(null, mDragOutline, x, y, 1, 1, null, null); + layout.visualizeDropLocation(null, mDragOutline, x, y, 1, 1, 1, 1, null, null); return true; case DragEvent.ACTION_DROP: { // Try and add any shortcuts @@ -2488,7 +2508,8 @@ public class Workspace extends SmoothPagedView final PendingAddWidgetInfo createInfo = new PendingAddWidgetInfo(widgetInfo, mimeType, data); mLauncher.addAppWidgetFromDrop(createInfo, - LauncherSettings.Favorites.CONTAINER_DESKTOP, mCurrentPage, null, pos); + LauncherSettings.Favorites.CONTAINER_DESKTOP, mCurrentPage, + null, null, pos); } else { // Show the widget picker dialog if there is more than one widget // that can handle this data type @@ -2542,7 +2563,11 @@ public class Workspace extends SmoothPagedView v.getMatrix().invert(mTempInverseMatrix); cachedInverseMatrix = mTempInverseMatrix; } - xy[0] = xy[0] + mScrollX - v.getLeft(); + int scrollX = mScrollX; + if (mNextPage != INVALID_PAGE) { + scrollX = mScroller.getFinalX(); + } + xy[0] = xy[0] + scrollX - v.getLeft(); xy[1] = xy[1] + mScrollY - v.getTop(); cachedInverseMatrix.mapPoints(xy); } @@ -2564,7 +2589,11 @@ public class Workspace extends SmoothPagedView */ void mapPointFromChildToSelf(View v, float[] xy) { v.getMatrix().mapPoints(xy); - xy[0] -= (mScrollX - v.getLeft()); + int scrollX = mScrollX; + if (mNextPage != INVALID_PAGE) { + scrollX = mScroller.getFinalX(); + } + xy[0] -= (scrollX - v.getLeft()); xy[1] -= (mScrollY - v.getTop()); } @@ -2709,8 +2738,7 @@ public class Workspace extends SmoothPagedView public void onDragOver(DragObject d) { // Skip drag over events while we are dragging over side pages - if (mInScrollArea) return; - if (mIsSwitchingState) return; + if (mInScrollArea || mIsSwitchingState || mState == State.SMALL) return; Rect r = new Rect(); CellLayout layout = null; @@ -2821,10 +2849,16 @@ public class Workspace extends SmoothPagedView mLastDragOverView = dragOverView; if (!mCreateUserFolderOnDrop && !isOverFolder) { + int minSpanX = item.spanX; + int minSpanY = item.spanY; + if (item.minSpanX > 0 && item.minSpanY > 0) { + minSpanX = item.minSpanX; + minSpanY = item.minSpanY; + } mDragTargetLayout.visualizeDropLocation(child, mDragOutline, (int) mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1], - item.spanX, item.spanY, d.dragView.getDragVisualizeOffset(), - d.dragView.getDragRegion()); + minSpanX, minSpanY, item.spanX, item.spanY, + d.dragView.getDragVisualizeOffset(), d.dragView.getDragRegion()); } } } @@ -2911,7 +2945,7 @@ public class Workspace extends SmoothPagedView final Runnable exitSpringLoadedRunnable = new Runnable() { @Override public void run() { - mLauncher.exitSpringLoadedDragModeDelayed(true, false); + mLauncher.exitSpringLoadedDragModeDelayed(true, false, null); } }; @@ -2945,9 +2979,19 @@ public class Workspace extends SmoothPagedView findNearestVacantCell = false; } } + final ItemInfo item = (ItemInfo) d.dragInfo; + int minSpanX = item.spanX; + int minSpanY = item.spanY; + if (item.minSpanX > 0 && item.minSpanY > 0) { + minSpanX = item.minSpanX; + minSpanY = item.minSpanY; + } if (findNearestVacantCell) { - mTargetCell = findNearestVacantArea(touchXY[0], touchXY[1], spanX, spanY, null, - cellLayout, mTargetCell); + int[] resultSpan = new int[2]; + mTargetCell = findNearestVacantArea(touchXY[0], touchXY[1], minSpanX, minSpanY, + spanX, spanY, null, cellLayout, mTargetCell, resultSpan); + item.spanX = resultSpan[0]; + item.spanY = resultSpan[1]; } Runnable onAnimationCompleteRunnable = new Runnable() { @@ -2957,8 +3001,11 @@ public class Workspace extends SmoothPagedView // widgets/shortcuts/folders in a slightly different way switch (pendingInfo.itemType) { case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET: + int span[] = new int[2]; + span[0] = item.spanX; + span[1] = item.spanY; mLauncher.addAppWidgetFromDrop((PendingAddWidgetInfo) pendingInfo, - container, screen, mTargetCell, null); + container, screen, mTargetCell, span, null); break; case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT: mLauncher.processShortcutFromDrop(pendingInfo.componentName, @@ -2971,28 +3018,15 @@ public class Workspace extends SmoothPagedView cellLayout.onDragExit(); } }; - - // Now we animate the dragView, (ie. the widget or shortcut preview) into its final - // location and size on the home screen. - RectF r = estimateItemPosition(cellLayout, pendingInfo, - mTargetCell[0], mTargetCell[1], spanX, spanY); - int loc[] = new int[2]; - loc[0] = (int) r.left; - loc[1] = (int) r.top; - setFinalTransitionTransform(cellLayout); - float cellLayoutScale = - mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(cellLayout, loc); - resetTransitionTransform(cellLayout); - - float dragViewScale = Math.min(r.width() / d.dragView.getMeasuredWidth(), - r.height() / d.dragView.getMeasuredHeight()); - // The animation will scale the dragView about its center, so we need to center about - // the final location. - loc[0] -= (d.dragView.getMeasuredWidth() - cellLayoutScale * r.width()) / 2; - loc[1] -= (d.dragView.getMeasuredHeight() - cellLayoutScale * r.height()) / 2; - - mLauncher.getDragLayer().animateViewIntoPosition(d.dragView, loc, - dragViewScale * cellLayoutScale, onAnimationCompleteRunnable); + View finalView = pendingInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET + ? ((PendingAddWidgetInfo) pendingInfo).boundWidget : null; + int animationStyle = ANIMATE_INTO_POSITION_AND_DISAPPEAR; + if (pendingInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET && + ((PendingAddWidgetInfo) pendingInfo).info.configure != null) { + animationStyle = ANIMATE_INTO_POSITION_AND_REMAIN; + } + animateWidgetDrop(info, cellLayout, d.dragView, onAnimationCompleteRunnable, + animationStyle, finalView, true); } else { // This is for other drag/drop cases, like dragging from All Apps View view = null; @@ -3059,6 +3093,109 @@ public class Workspace extends SmoothPagedView } } + public Bitmap createWidgetBitmap(ItemInfo widgetInfo, View layout) { + int[] unScaledSize = mLauncher.getWorkspace().estimateItemSize(widgetInfo.spanX, + widgetInfo.spanY, widgetInfo, false); + int visibility = layout.getVisibility(); + layout.setVisibility(VISIBLE); + + int width = MeasureSpec.makeMeasureSpec(unScaledSize[0], MeasureSpec.EXACTLY); + int height = MeasureSpec.makeMeasureSpec(unScaledSize[1], MeasureSpec.EXACTLY); + Bitmap b = Bitmap.createBitmap(unScaledSize[0], unScaledSize[1], + Bitmap.Config.ARGB_8888); + Canvas c = new Canvas(b); + + layout.measure(width, height); + layout.layout(0, 0, unScaledSize[0], unScaledSize[1]); + layout.draw(c); + c.setBitmap(null); + layout.setVisibility(visibility); + return b; + } + + private void getFinalPositionForDropAnimation(int[] loc, float[] scaleXY, + DragView dragView, CellLayout layout, ItemInfo info, int[] targetCell, View finalView, + boolean external) { + // Now we animate the dragView, (ie. the widget or shortcut preview) into its final + // location and size on the home screen. + int spanX = info.spanX; + int spanY = info.spanY; + + Rect r = estimateItemPosition(layout, info, targetCell[0], targetCell[1], spanX, spanY); + loc[0] = r.left; + loc[1] = r.top; + + setFinalTransitionTransform(layout); + float cellLayoutScale = + mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(layout, loc); + resetTransitionTransform(layout); + float dragViewScaleX = (1.0f * r.width()) / dragView.getMeasuredWidth(); + float dragViewScaleY = (1.0f * r.height()) / dragView.getMeasuredHeight(); + + // The animation will scale the dragView about its center, so we need to center about + // the final location. + loc[0] -= (dragView.getMeasuredWidth() - cellLayoutScale * r.width()) / 2; + loc[1] -= (dragView.getMeasuredHeight() - cellLayoutScale * r.height()) / 2; + + scaleXY[0] = dragViewScaleX * cellLayoutScale; + scaleXY[1] = dragViewScaleY * cellLayoutScale; + } + + public void animateWidgetDrop(ItemInfo info, CellLayout cellLayout, DragView dragView, + final Runnable onCompleteRunnable, int animationType, final View finalView, + boolean external) { + Rect from = new Rect(); + mLauncher.getDragLayer().getViewRectRelativeToSelf(dragView, from); + + int[] finalPos = new int[2]; + float scaleXY[] = new float[2]; + getFinalPositionForDropAnimation(finalPos, scaleXY, dragView, cellLayout, info, mTargetCell, + finalView, external); + + Resources res = mLauncher.getResources(); + int duration = res.getInteger(R.integer.config_dropAnimMaxDuration) - 200; + + // In the case where we've prebound the widget, we remove it from the DragLayer + if (finalView instanceof AppWidgetHostView && external) { + mLauncher.getDragLayer().removeView(finalView); + } + if ((animationType == ANIMATE_INTO_POSITION_AND_RESIZE || external) && finalView != null) { + Bitmap crossFadeBitmap = createWidgetBitmap(info, finalView); + dragView.setCrossFadeBitmap(crossFadeBitmap); + dragView.crossFade((int) (duration * 0.8f)); + } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET && external) { + scaleXY[0] = scaleXY[1] = Math.min(scaleXY[0], scaleXY[1]); + } + + DragLayer dragLayer = mLauncher.getDragLayer(); + if (animationType == CANCEL_TWO_STAGE_WIDGET_DROP_ANIMATION) { + mLauncher.getDragLayer().animateViewIntoPosition(dragView, finalPos, 0f, 0.1f, 0.1f, + DragLayer.ANIMATION_END_DISAPPEAR, onCompleteRunnable, duration); + } else { + int endStyle; + if (animationType == ANIMATE_INTO_POSITION_AND_REMAIN) { + endStyle = DragLayer.ANIMATION_END_REMAIN_VISIBLE; + } else { + endStyle = DragLayer.ANIMATION_END_DISAPPEAR;; + } + + Runnable onComplete = new Runnable() { + @Override + public void run() { + if (finalView != null) { + finalView.setVisibility(VISIBLE); + } + if (onCompleteRunnable != null) { + onCompleteRunnable.run(); + } + } + }; + dragLayer.animateViewIntoPosition(dragView, from.left, from.top, finalPos[0], + finalPos[1], 1, 1, 1, scaleXY[0], scaleXY[1], onComplete, endStyle, + duration, this); + } + } + public void setFinalTransitionTransform(CellLayout layout) { if (isSwitchingState()) { int index = indexOfChild(layout); @@ -3115,7 +3252,19 @@ public class Workspace extends SmoothPagedView private int[] findNearestVacantArea(int pixelX, int pixelY, int spanX, int spanY, View ignoreView, CellLayout layout, int[] recycle) { return layout.findNearestVacantArea( - pixelX, pixelY, spanX, spanY, ignoreView, recycle); + pixelX, pixelY, spanX, spanY, spanX, spanY, ignoreView, recycle, null); + } + + /** + * Calculate the nearest cell where the given object would be dropped. + * + * pixelX and pixelY should be in the coordinate system of layout + */ + private int[] findNearestVacantArea(int pixelX, int pixelY, int minSpanX, int minSpanY, + int spanX, int spanY, View ignoreView, CellLayout layout, int[] recycle, + int[] returnSpan) { + return layout.findNearestVacantArea( + pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, ignoreView, recycle, returnSpan); } /** @@ -3170,6 +3319,9 @@ public class Workspace extends SmoothPagedView } mDragOutline = null; mDragInfo = null; + + // Hide the scrolling indicator after you pick up an item + hideScrollingIndicator(false); } public boolean isDropEnabled() { @@ -3219,11 +3371,12 @@ public class Workspace extends SmoothPagedView if (!isSmall() && !mIsSwitchingState) { mInScrollArea = true; - final int page = mCurrentPage + (direction == DragController.SCROLL_LEFT ? -1 : 1); - final CellLayout layout = (CellLayout) getChildAt(page); + final int page = (mNextPage != INVALID_PAGE ? mNextPage : mCurrentPage) + + (direction == DragController.SCROLL_LEFT ? -1 : 1); cancelFolderCreation(); - if (layout != null) { + if (0 <= page && page < getChildCount()) { + CellLayout layout = (CellLayout) getChildAt(page); // Exit the current layout and mark the overlapping layout if (mDragTargetLayout != null) { mDragTargetLayout.setIsDragOverlapping(false); @@ -3246,16 +3399,17 @@ public class Workspace extends SmoothPagedView boolean result = false; if (mInScrollArea) { if (mDragTargetLayout != null) { - // Unmark the overlapping layout and re-enter the current layout mDragTargetLayout.setIsDragOverlapping(false); - mDragTargetLayout = getCurrentDropLayout(); - mDragTargetLayout.onDragEnter(); - // Workspace is responsible for drawing the edge glow on adjacent pages, // so we need to redraw the workspace when this may have changed. invalidate(); - result = true; } + if (mDragTargetLayout != null && mDragHasEnteredWorkspace) { + // Unmark the overlapping layout and re-enter the current layout + mDragTargetLayout = getCurrentDropLayout(); + mDragTargetLayout.onDragEnter(); + } + result = true; mInScrollArea = false; } return result; @@ -3527,7 +3681,7 @@ public class Workspace extends SmoothPagedView final ViewGroup parent = (ViewGroup) getParent(); final ImageView qsbDivider = (ImageView) (parent.findViewById(R.id.qsb_divider)); final ImageView dockDivider = (ImageView) (parent.findViewById(R.id.dock_divider)); - final ImageView scrollIndicator = getScrollingIndicator(); + final View scrollIndicator = getScrollingIndicator(); cancelScrollingIndicatorAnimations(); if (qsbDivider != null) qsbDivider.setAlpha(reducedFade); |