| /* |
| * 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.android.launcher2; |
| |
| 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.android.launcher.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()) { |
| Folder currentFolder = mLauncher.getWorkspace().getOpenFolder(); |
| 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(); |
| } |
| } |
| } |