summaryrefslogtreecommitdiffstats
path: root/src/com/cyanogenmod/trebuchet/DragLayer.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/cyanogenmod/trebuchet/DragLayer.java')
-rw-r--r--src/com/cyanogenmod/trebuchet/DragLayer.java677
1 files changed, 677 insertions, 0 deletions
diff --git a/src/com/cyanogenmod/trebuchet/DragLayer.java b/src/com/cyanogenmod/trebuchet/DragLayer.java
new file mode 100644
index 000000000..20e94018d
--- /dev/null
+++ b/src/com/cyanogenmod/trebuchet/DragLayer.java
@@ -0,0 +1,677 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.cyanogenmod.trebuchet;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.animation.TimeInterpolator;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewParent;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.Interpolator;
+import android.widget.FrameLayout;
+import android.widget.TextView;
+
+import com.cyanogenmod.trebuchet.R;
+
+import java.util.ArrayList;
+
+/**
+ * A ViewGroup that coordinates dragging across its descendants
+ */
+public class DragLayer extends FrameLayout {
+ private DragController mDragController;
+ private int[] mTmpXY = new int[2];
+
+ private int mXDown, mYDown;
+ private Launcher mLauncher;
+
+ // Variables relating to resizing widgets
+ private final ArrayList<AppWidgetResizeFrame> mResizeFrames =
+ new ArrayList<AppWidgetResizeFrame>();
+ private AppWidgetResizeFrame mCurrentResizeFrame;
+
+ // Variables relating to animation of views after drop
+ private ValueAnimator mDropAnim = null;
+ private ValueAnimator mFadeOutAnim = null;
+ private TimeInterpolator mCubicEaseOutInterpolator = new DecelerateInterpolator(1.5f);
+ private View mDropView = null;
+
+ private int[] mDropViewPos = new int[2];
+ private float mDropViewScale;
+ private float mDropViewAlpha;
+ private boolean mHoverPointClosesFolder = false;
+ private Rect mHitRect = new Rect();
+ private int mWorkspaceIndex = -1;
+ private int mQsbIndex = -1;
+
+ /**
+ * Used to create a new DragLayer from XML.
+ *
+ * @param context The application's context.
+ * @param attrs The attributes set containing the Workspace's customization values.
+ */
+ public DragLayer(Context context, AttributeSet attrs) {
+ super(context, attrs);
+
+ // Disable multitouch across the workspace/all apps/customize tray
+ setMotionEventSplittingEnabled(false);
+ setChildrenDrawingOrderEnabled(true);
+ }
+
+ public void setup(Launcher launcher, DragController controller) {
+ mLauncher = launcher;
+ mDragController = controller;
+ }
+
+ @Override
+ public boolean dispatchKeyEvent(KeyEvent event) {
+ return mDragController.dispatchKeyEvent(event) || super.dispatchKeyEvent(event);
+ }
+
+ private boolean isEventOverFolderTextRegion(Folder folder, MotionEvent ev) {
+ getDescendantRectRelativeToSelf(folder.getEditTextRegion(), mHitRect);
+ if (mHitRect.contains((int) ev.getX(), (int) ev.getY())) {
+ return true;
+ }
+ return false;
+ }
+
+ private boolean isEventOverFolder(Folder folder, MotionEvent ev) {
+ getDescendantRectRelativeToSelf(folder, mHitRect);
+ if (mHitRect.contains((int) ev.getX(), (int) ev.getY())) {
+ return true;
+ }
+ return false;
+ }
+
+ private boolean handleTouchDown(MotionEvent ev, boolean intercept) {
+ Rect hitRect = new Rect();
+ int x = (int) ev.getX();
+ int y = (int) ev.getY();
+
+ for (AppWidgetResizeFrame child: mResizeFrames) {
+ child.getHitRect(hitRect);
+ if (hitRect.contains(x, y)) {
+ if (child.beginResizeIfPointInRegion(x - child.getLeft(), y - child.getTop())) {
+ mCurrentResizeFrame = child;
+ mXDown = x;
+ mYDown = y;
+ requestDisallowInterceptTouchEvent(true);
+ return true;
+ }
+ }
+ }
+
+ Folder currentFolder = mLauncher.getWorkspace().getOpenFolder();
+ if (currentFolder != null && !mLauncher.isFolderClingVisible() && intercept) {
+ if (currentFolder.isEditingName()) {
+ if (!isEventOverFolderTextRegion(currentFolder, ev)) {
+ currentFolder.dismissEditingName();
+ return true;
+ }
+ }
+
+ getDescendantRectRelativeToSelf(currentFolder, hitRect);
+ if (!isEventOverFolder(currentFolder, ev)) {
+ mLauncher.closeFolder();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+ if (handleTouchDown(ev, true)) {
+ return true;
+ }
+ }
+ clearAllResizeFrames();
+ return mDragController.onInterceptTouchEvent(ev);
+ }
+
+ @Override
+ public boolean onInterceptHoverEvent(MotionEvent ev) {
+ Folder currentFolder = mLauncher.getWorkspace().getOpenFolder();
+ if (currentFolder == null) {
+ return false;
+ } else {
+ if (AccessibilityManager.getInstance(mContext).isTouchExplorationEnabled()) {
+ final int action = ev.getAction();
+ boolean isOverFolder;
+ switch (action) {
+ case MotionEvent.ACTION_HOVER_ENTER:
+ isOverFolder = isEventOverFolder(currentFolder, ev);
+ if (!isOverFolder) {
+ sendTapOutsideFolderAccessibilityEvent(currentFolder.isEditingName());
+ mHoverPointClosesFolder = true;
+ return true;
+ } else if (isOverFolder) {
+ mHoverPointClosesFolder = false;
+ } else {
+ return true;
+ }
+ case MotionEvent.ACTION_HOVER_MOVE:
+ isOverFolder = isEventOverFolder(currentFolder, ev);
+ if (!isOverFolder && !mHoverPointClosesFolder) {
+ sendTapOutsideFolderAccessibilityEvent(currentFolder.isEditingName());
+ mHoverPointClosesFolder = true;
+ return true;
+ } else if (isOverFolder) {
+ mHoverPointClosesFolder = false;
+ } else {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ private void sendTapOutsideFolderAccessibilityEvent(boolean isEditingName) {
+ if (AccessibilityManager.getInstance(mContext).isEnabled()) {
+ int stringId = isEditingName ? R.string.folder_tap_to_rename : R.string.folder_tap_to_close;
+ AccessibilityEvent event = AccessibilityEvent.obtain(
+ AccessibilityEvent.TYPE_VIEW_FOCUSED);
+ onInitializeAccessibilityEvent(event);
+ event.getText().add(mContext.getString(stringId));
+ AccessibilityManager.getInstance(mContext).sendAccessibilityEvent(event);
+ }
+ }
+
+ @Override
+ public boolean onHoverEvent(MotionEvent ev) {
+ // If we've received this, we've already done the necessary handling
+ // in onInterceptHoverEvent. Return true to consume the event.
+ return false;
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ boolean handled = false;
+ int action = ev.getAction();
+
+ int x = (int) ev.getX();
+ int y = (int) ev.getY();
+
+ if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+ if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+ if (handleTouchDown(ev, false)) {
+ return true;
+ }
+ }
+ }
+
+ if (mCurrentResizeFrame != null) {
+ handled = true;
+ switch (action) {
+ case MotionEvent.ACTION_MOVE:
+ mCurrentResizeFrame.visualizeResizeForDelta(x - mXDown, y - mYDown);
+ break;
+ case MotionEvent.ACTION_CANCEL:
+ case MotionEvent.ACTION_UP:
+ mCurrentResizeFrame.commitResizeForDelta(x - mXDown, y - mYDown);
+ mCurrentResizeFrame = null;
+ }
+ }
+ if (handled) return true;
+ return mDragController.onTouchEvent(ev);
+ }
+
+ /**
+ * Determine the rect of the descendant in this DragLayer's coordinates
+ *
+ * @param descendant The descendant whose coordinates we want to find.
+ * @param r The rect into which to place the results.
+ * @return The factor by which this descendant is scaled relative to this DragLayer.
+ */
+ public float getDescendantRectRelativeToSelf(View descendant, Rect r) {
+ mTmpXY[0] = 0;
+ mTmpXY[1] = 0;
+ float scale = getDescendantCoordRelativeToSelf(descendant, mTmpXY);
+ r.set(mTmpXY[0], mTmpXY[1],
+ mTmpXY[0] + descendant.getWidth(), mTmpXY[1] + descendant.getHeight());
+ return scale;
+ }
+
+ public void getLocationInDragLayer(View child, int[] loc) {
+ loc[0] = 0;
+ loc[1] = 0;
+ getDescendantCoordRelativeToSelf(child, loc);
+ }
+
+ /**
+ * Given a coordinate relative to the descendant, find the coordinate in this DragLayer's
+ * coordinates.
+ *
+ * @param descendant The descendant to which the passed coordinate is relative.
+ * @param coord The coordinate that we want mapped.
+ * @return The factor by which this descendant is scaled relative to this DragLayer.
+ */
+ public float getDescendantCoordRelativeToSelf(View descendant, int[] coord) {
+ float scale = 1.0f;
+ float[] pt = {coord[0], coord[1]};
+ descendant.getMatrix().mapPoints(pt);
+ scale *= descendant.getScaleX();
+ pt[0] += descendant.getLeft();
+ pt[1] += descendant.getTop();
+ ViewParent viewParent = descendant.getParent();
+ while (viewParent instanceof View && viewParent != this) {
+ final View view = (View)viewParent;
+ view.getMatrix().mapPoints(pt);
+ scale *= view.getScaleX();
+ pt[0] += view.getLeft() - view.getScrollX();
+ pt[1] += view.getTop() - view.getScrollY();
+ viewParent = view.getParent();
+ }
+ coord[0] = (int) Math.round(pt[0]);
+ coord[1] = (int) Math.round(pt[1]);
+ return scale;
+ }
+
+ public void getViewRectRelativeToSelf(View v, Rect r) {
+ int[] loc = new int[2];
+ getLocationInWindow(loc);
+ int x = loc[0];
+ int y = loc[1];
+
+ v.getLocationInWindow(loc);
+ int vX = loc[0];
+ int vY = loc[1];
+
+ int left = vX - x;
+ int top = vY - y;
+ r.set(left, top, left + v.getMeasuredWidth(), top + v.getMeasuredHeight());
+ }
+
+ @Override
+ public boolean dispatchUnhandledMove(View focused, int direction) {
+ return mDragController.dispatchUnhandledMove(focused, direction);
+ }
+
+ public static class LayoutParams extends FrameLayout.LayoutParams {
+ public int x, y;
+ public boolean customPosition = false;
+
+ /**
+ * {@inheritDoc}
+ */
+ public LayoutParams(int width, int height) {
+ super(width, height);
+ }
+
+ public void setWidth(int width) {
+ this.width = width;
+ }
+
+ public int getWidth() {
+ return width;
+ }
+
+ public void setHeight(int height) {
+ this.height = height;
+ }
+
+ public int getHeight() {
+ return height;
+ }
+
+ public void setX(int x) {
+ this.x = x;
+ }
+
+ public int getX() {
+ return x;
+ }
+
+ public void setY(int y) {
+ this.y = y;
+ }
+
+ public int getY() {
+ return y;
+ }
+ }
+
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ super.onLayout(changed, l, t, r, b);
+ int count = getChildCount();
+ for (int i = 0; i < count; i++) {
+ View child = getChildAt(i);
+ final FrameLayout.LayoutParams flp = (FrameLayout.LayoutParams) child.getLayoutParams();
+ if (flp instanceof LayoutParams) {
+ final LayoutParams lp = (LayoutParams) flp;
+ if (lp.customPosition) {
+ child.layout(lp.x, lp.y, lp.x + lp.width, lp.y + lp.height);
+ }
+ }
+ }
+ }
+
+ public void clearAllResizeFrames() {
+ if (mResizeFrames.size() > 0) {
+ for (AppWidgetResizeFrame frame: mResizeFrames) {
+ removeView(frame);
+ }
+ mResizeFrames.clear();
+ }
+ }
+
+ public boolean hasResizeFrames() {
+ return mResizeFrames.size() > 0;
+ }
+
+ public boolean isWidgetBeingResized() {
+ return mCurrentResizeFrame != null;
+ }
+
+ public void addResizeFrame(ItemInfo itemInfo, LauncherAppWidgetHostView widget,
+ CellLayout cellLayout) {
+ AppWidgetResizeFrame resizeFrame = new AppWidgetResizeFrame(getContext(),
+ itemInfo, widget, cellLayout, this);
+
+ LayoutParams lp = new LayoutParams(-1, -1);
+ lp.customPosition = true;
+
+ addView(resizeFrame, lp);
+ mResizeFrames.add(resizeFrame);
+
+ resizeFrame.snapToWidget(false);
+ }
+
+ public void animateViewIntoPosition(DragView dragView, final View child) {
+ animateViewIntoPosition(dragView, child, null);
+ }
+
+ public void animateViewIntoPosition(DragView dragView, final int[] pos, float scale,
+ Runnable onFinishRunnable) {
+ Rect r = new Rect();
+ getViewRectRelativeToSelf(dragView, r);
+ final int fromX = r.left;
+ final int fromY = r.top;
+
+ animateViewIntoPosition(dragView, fromX, fromY, pos[0], pos[1], scale,
+ onFinishRunnable, true, -1);
+ }
+
+ public void animateViewIntoPosition(DragView dragView, final View child,
+ final Runnable onFinishAnimationRunnable) {
+ animateViewIntoPosition(dragView, child, -1, onFinishAnimationRunnable);
+ }
+
+ public void animateViewIntoPosition(DragView dragView, final View child, int duration,
+ final Runnable onFinishAnimationRunnable) {
+ ((CellLayoutChildren) child.getParent()).measureChild(child);
+ CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
+
+ Rect r = new Rect();
+ getViewRectRelativeToSelf(dragView, r);
+
+ int coord[] = new int[2];
+ coord[0] = lp.x;
+ coord[1] = lp.y;
+ // Since the child hasn't necessarily been laid out, we force the lp to be updated with
+ // the correct coordinates (above) and use these to determine the final location
+ float scale = getDescendantCoordRelativeToSelf((View) child.getParent(), coord);
+ int toX = coord[0];
+ int toY = coord[1];
+ if (child instanceof TextView) {
+ TextView tv = (TextView) child;
+ Drawable d = tv.getCompoundDrawables()[1];
+
+ // Center in the y coordinate about the target's drawable
+ toY += Math.round(scale * tv.getPaddingTop());
+ toY -= (dragView.getHeight() - (int) Math.round(scale * d.getIntrinsicHeight())) / 2;
+ // Center in the x coordinate about the target's drawable
+ toX -= (dragView.getMeasuredWidth() - Math.round(scale * child.getMeasuredWidth())) / 2;
+ } else if (child instanceof FolderIcon) {
+ // Account for holographic blur padding on the drag view
+ toY -= HolographicOutlineHelper.MAX_OUTER_BLUR_RADIUS / 2;
+ // Center in the x coordinate about the target's drawable
+ toX -= (dragView.getMeasuredWidth() - Math.round(scale * child.getMeasuredWidth())) / 2;
+ } else {
+ toY -= (Math.round(scale * (dragView.getHeight() - child.getMeasuredHeight()))) / 2;
+ toX -= (Math.round(scale * (dragView.getMeasuredWidth()
+ - child.getMeasuredWidth()))) / 2;
+ }
+
+ final int fromX = r.left;
+ final int fromY = r.top;
+ child.setVisibility(INVISIBLE);
+ child.setAlpha(0);
+ Runnable onCompleteRunnable = new Runnable() {
+ public void run() {
+ child.setVisibility(VISIBLE);
+ ObjectAnimator oa = ObjectAnimator.ofFloat(child, "alpha", 0f, 1f);
+ oa.setDuration(60);
+ oa.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(android.animation.Animator animation) {
+ if (onFinishAnimationRunnable != null) {
+ onFinishAnimationRunnable.run();
+ }
+ }
+ });
+ oa.start();
+ }
+ };
+ animateViewIntoPosition(dragView, fromX, fromY, toX, toY, scale,
+ onCompleteRunnable, true, duration);
+ }
+
+ private void animateViewIntoPosition(final View view, final int fromX, final int fromY,
+ final int toX, final int toY, float finalScale, Runnable onCompleteRunnable,
+ boolean fadeOut, int duration) {
+ Rect from = new Rect(fromX, fromY, fromX +
+ view.getMeasuredWidth(), fromY + view.getMeasuredHeight());
+ Rect to = new Rect(toX, toY, toX + view.getMeasuredWidth(), toY + view.getMeasuredHeight());
+ animateView(view, from, to, 1f, finalScale, duration, null, null, onCompleteRunnable, true);
+ }
+
+ /**
+ * This method animates a view at the end of a drag and drop animation.
+ *
+ * @param view The view to be animated. This view is drawn directly into DragLayer, and so
+ * doesn't need to be a child of DragLayer.
+ * @param from The initial location of the view. Only the left and top parameters are used.
+ * @param to The final location of the view. Only the left and top parameters are used. This
+ * location doesn't account for scaling, and so should be centered about the desired
+ * final location (including scaling).
+ * @param finalAlpha The final alpha of the view, in case we want it to fade as it animates.
+ * @param finalScale The final scale of the view. The view is scaled about its center.
+ * @param duration The duration of the animation.
+ * @param motionInterpolator The interpolator to use for the location of the view.
+ * @param alphaInterpolator The interpolator to use for the alpha of the view.
+ * @param onCompleteRunnable Optional runnable to run on animation completion.
+ * @param fadeOut Whether or not to fade out the view once the animation completes. If true,
+ * the runnable will execute after the view is faded out.
+ */
+ public void animateView(final View view, final Rect from, final Rect to, final float finalAlpha,
+ final float finalScale, int duration, final Interpolator motionInterpolator,
+ final Interpolator alphaInterpolator, final Runnable onCompleteRunnable,
+ final boolean fadeOut) {
+ // Calculate the duration of the animation based on the object's distance
+ final float dist = (float) Math.sqrt(Math.pow(to.left - from.left, 2) +
+ Math.pow(to.top - from.top, 2));
+ final Resources res = getResources();
+ final float maxDist = (float) res.getInteger(R.integer.config_dropAnimMaxDist);
+
+ // If duration < 0, this is a cue to compute the duration based on the distance
+ if (duration < 0) {
+ duration = res.getInteger(R.integer.config_dropAnimMaxDuration);
+ if (dist < maxDist) {
+ duration *= mCubicEaseOutInterpolator.getInterpolation(dist / maxDist);
+ }
+ }
+
+ if (mDropAnim != null) {
+ mDropAnim.cancel();
+ }
+
+ if (mFadeOutAnim != null) {
+ mFadeOutAnim.cancel();
+ }
+
+ mDropView = view;
+ final float initialAlpha = view.getAlpha();
+ mDropAnim = new ValueAnimator();
+ if (alphaInterpolator == null || motionInterpolator == null) {
+ mDropAnim.setInterpolator(mCubicEaseOutInterpolator);
+ }
+
+ mDropAnim.setDuration(duration);
+ mDropAnim.setFloatValues(0.0f, 1.0f);
+ mDropAnim.removeAllUpdateListeners();
+ mDropAnim.addUpdateListener(new AnimatorUpdateListener() {
+ public void onAnimationUpdate(ValueAnimator animation) {
+ final float percent = (Float) animation.getAnimatedValue();
+ // Invalidate the old position
+ int width = view.getMeasuredWidth();
+ int height = view.getMeasuredHeight();
+ invalidate(mDropViewPos[0], mDropViewPos[1],
+ mDropViewPos[0] + width, mDropViewPos[1] + height);
+
+ float alphaPercent = alphaInterpolator == null ? percent :
+ alphaInterpolator.getInterpolation(percent);
+ float motionPercent = motionInterpolator == null ? percent :
+ motionInterpolator.getInterpolation(percent);
+
+ mDropViewPos[0] = from.left + (int) Math.round(((to.left - from.left) * motionPercent));
+ mDropViewPos[1] = from.top + (int) Math.round(((to.top - from.top) * motionPercent));
+ mDropViewScale = percent * finalScale + (1 - percent);
+ mDropViewAlpha = alphaPercent * finalAlpha + (1 - alphaPercent) * initialAlpha;
+ invalidate(mDropViewPos[0], mDropViewPos[1],
+ mDropViewPos[0] + width, mDropViewPos[1] + height);
+ }
+ });
+ mDropAnim.addListener(new AnimatorListenerAdapter() {
+ public void onAnimationEnd(Animator animation) {
+ if (onCompleteRunnable != null) {
+ onCompleteRunnable.run();
+ }
+ if (fadeOut) {
+ fadeOutDragView();
+ } else {
+ mDropView = null;
+ }
+ }
+ });
+ mDropAnim.start();
+ }
+
+ private void fadeOutDragView() {
+ mFadeOutAnim = new ValueAnimator();
+ mFadeOutAnim.setDuration(150);
+ mFadeOutAnim.setFloatValues(0f, 1f);
+ mFadeOutAnim.removeAllUpdateListeners();
+ mFadeOutAnim.addUpdateListener(new AnimatorUpdateListener() {
+ public void onAnimationUpdate(ValueAnimator animation) {
+ final float percent = (Float) animation.getAnimatedValue();
+ mDropViewAlpha = 1 - percent;
+ int width = mDropView.getMeasuredWidth();
+ int height = mDropView.getMeasuredHeight();
+ invalidate(mDropViewPos[0], mDropViewPos[1],
+ mDropViewPos[0] + width, mDropViewPos[1] + height);
+ }
+ });
+ mFadeOutAnim.addListener(new AnimatorListenerAdapter() {
+ public void onAnimationEnd(Animator animation) {
+ mDropView = null;
+ }
+ });
+ mFadeOutAnim.start();
+ }
+
+ @Override
+ protected void onViewAdded(View child) {
+ super.onViewAdded(child);
+ updateChildIndices();
+ }
+
+ @Override
+ protected void onViewRemoved(View child) {
+ super.onViewRemoved(child);
+ updateChildIndices();
+ }
+
+ private void updateChildIndices() {
+ if (mLauncher != null) {
+ mWorkspaceIndex = indexOfChild(mLauncher.getWorkspace());
+ mQsbIndex = indexOfChild(mLauncher.getSearchBar());
+ }
+ }
+
+ @Override
+ protected int getChildDrawingOrder(int childCount, int i) {
+ // We don't want to prioritize the workspace drawing on top of the other children in
+ // landscape for the overscroll event.
+ if (LauncherApplication.isScreenLandscape(getContext())) {
+ return super.getChildDrawingOrder(childCount, i);
+ }
+
+ if (mWorkspaceIndex == -1 || mQsbIndex == -1 ||
+ mLauncher.getWorkspace().isDrawingBackgroundGradient()) {
+ return i;
+ }
+
+ // This ensures that the workspace is drawn above the hotseat and qsb,
+ // except when the workspace is drawing a background gradient, in which
+ // case we want the workspace to stay behind these elements.
+ if (i == mQsbIndex) {
+ return mWorkspaceIndex;
+ } else if (i == mWorkspaceIndex) {
+ return mQsbIndex;
+ } else {
+ return i;
+ }
+ }
+
+ @Override
+ protected void dispatchDraw(Canvas canvas) {
+ super.dispatchDraw(canvas);
+ if (mDropView != null) {
+ // We are animating an item that was just dropped on the home screen.
+ // Render its View in the current animation position.
+ canvas.save(Canvas.MATRIX_SAVE_FLAG);
+ final int xPos = mDropViewPos[0] - mDropView.getScrollX();
+ final int yPos = mDropViewPos[1] - mDropView.getScrollY();
+ int width = mDropView.getMeasuredWidth();
+ int height = mDropView.getMeasuredHeight();
+ canvas.translate(xPos, yPos);
+ canvas.translate((1 - mDropViewScale) * width / 2, (1 - mDropViewScale) * height / 2);
+ canvas.scale(mDropViewScale, mDropViewScale);
+ mDropView.setAlpha(mDropViewAlpha);
+ mDropView.draw(canvas);
+ canvas.restore();
+ }
+ }
+}