blob: 829ac20d754bccf7b88eb145805e01351616407c [file] [log] [blame]
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Joe Onoratoa5902522009-07-30 13:37:37 -070017package com.android.launcher2;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080018
Michael Jurka0280c3b2010-09-17 15:00:07 -070019import android.animation.Animator;
Chet Haaseb1254a62010-09-07 13:35:00 -070020import android.animation.AnimatorSet;
Michael Jurka0280c3b2010-09-17 15:00:07 -070021import android.animation.ObjectAnimator;
Patrick Dubroycd68ff52010-10-28 17:57:05 -070022import android.animation.TimeInterpolator;
23import android.animation.ValueAnimator;
24import android.animation.ValueAnimator.AnimatorUpdateListener;
Dianne Hackborn8f573952009-08-10 23:21:09 -070025import android.app.WallpaperManager;
Michael Jurkabed61d22012-02-14 22:51:29 -080026import android.appwidget.AppWidgetHostView;
Romain Guy629de3e2010-01-13 12:20:59 -080027import android.appwidget.AppWidgetProviderInfo;
Adam Powell495f2892010-04-16 16:40:55 -070028import android.content.ComponentName;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080029import android.content.Context;
30import android.content.Intent;
Winson Chung2efec4e2012-05-03 12:31:48 -070031import android.content.SharedPreferences;
Patrick Dubroy7247f632010-08-04 16:02:59 -070032import android.content.res.Resources;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080033import android.content.res.TypedArray;
Joe Onorato4be866d2010-10-10 11:26:02 -070034import android.graphics.Bitmap;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080035import android.graphics.Canvas;
Michael Jurkaa63c4522010-08-19 13:52:27 -070036import android.graphics.Matrix;
Winson Chungb8c69f32011-10-19 21:36:08 -070037import android.graphics.Point;
Winson Chung043f2af2012-03-01 16:09:54 -080038import android.graphics.PointF;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080039import android.graphics.Rect;
Joe Onorato4be866d2010-10-10 11:26:02 -070040import android.graphics.Region.Op;
The Android Open Source Projectf96811c2009-03-18 17:39:48 -070041import android.graphics.drawable.Drawable;
Joe Onorato956091b2010-02-19 12:47:40 -080042import android.os.IBinder;
Adam Powell495f2892010-04-16 16:40:55 -070043import android.os.Parcelable;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080044import android.util.AttributeSet;
Daniel Sandler291ad122010-05-24 16:03:53 -040045import android.util.Log;
Winson Chunga34abf82010-11-12 12:10:35 -080046import android.view.Display;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080047import android.view.MotionEvent;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080048import android.view.View;
Winson Chung6e314082011-01-27 16:46:51 -080049import android.view.ViewGroup;
Patrick Dubroycd68ff52010-10-28 17:57:05 -070050import android.view.animation.DecelerateInterpolator;
Winson Chunga6427b12011-07-27 10:53:39 -070051import android.widget.ImageView;
The Android Open Source Projectf96811c2009-03-18 17:39:48 -070052import android.widget.TextView;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080053
Adam Cohen66396872011-04-15 17:50:36 -070054import com.android.launcher.R;
Adam Cohen19072da2011-05-31 14:30:45 -070055import com.android.launcher2.FolderIcon.FolderRingAnimator;
Adam Cohen482ed822012-03-02 14:15:13 -080056import com.android.launcher2.LauncherSettings.Favorites;
Romain Guyedcce092010-03-04 13:03:17 -080057
Winson Chung2efec4e2012-05-03 12:31:48 -070058import java.net.URISyntaxException;
Adam Cohen716b51e2011-06-30 12:09:54 -070059import java.util.ArrayList;
60import java.util.HashSet;
Michael Jurka8bd65f52012-06-25 14:56:22 -070061import java.util.Iterator;
Winson Chung2efec4e2012-05-03 12:31:48 -070062import java.util.Set;
Adam Cohen716b51e2011-06-30 12:09:54 -070063
The Android Open Source Project31dd5032009-03-03 19:32:27 -080064/**
Michael Jurka0142d492010-08-25 17:46:15 -070065 * The workspace is a wide area with a wallpaper and a finite number of pages.
66 * Each page contains a number of icons, folders or widgets the user can
Winson Chungaafa03c2010-06-11 17:34:16 -070067 * interact with. A workspace is meant to be used with a fixed width only.
The Android Open Source Project31dd5032009-03-03 19:32:27 -080068 */
Michael Jurka0142d492010-08-25 17:46:15 -070069public class Workspace extends SmoothPagedView
Michael Jurkad74c9842011-07-10 12:44:21 -070070 implements DropTarget, DragSource, DragScroller, View.OnTouchListener,
Michael Jurka8b805b12012-04-18 14:23:14 -070071 DragController.DragListener, LauncherTransitionable, ViewGroup.OnHierarchyChangeListener {
Joe Onorato3a8820b2009-11-10 15:06:42 -080072 private static final String TAG = "Launcher.Workspace";
Michael Jurka0142d492010-08-25 17:46:15 -070073
Adam Cohenf34bab52010-09-30 14:11:56 -070074 // Y rotation to apply to the workspace screens
Adam Cohenb5ba0972011-09-07 18:02:31 -070075 private static final float WORKSPACE_OVERSCROLL_ROTATION = 24f;
Adam Cohena985e592010-09-09 11:23:48 -070076
Adam Cohen68d73932010-11-15 10:50:58 -080077 private static final int CHILDREN_OUTLINE_FADE_OUT_DELAY = 0;
78 private static final int CHILDREN_OUTLINE_FADE_OUT_DURATION = 375;
Winson Chung9171e6d2010-11-17 17:39:27 -080079 private static final int CHILDREN_OUTLINE_FADE_IN_DURATION = 100;
Adam Cohenf34bab52010-09-30 14:11:56 -070080
Winson Chungf135c6c2010-11-18 16:32:08 -080081 private static final int BACKGROUND_FADE_OUT_DURATION = 350;
Adam Cohened51cc92011-08-01 20:28:08 -070082 private static final int ADJACENT_SCREEN_DROP_DURATION = 300;
Adam Cohen265b9a62011-12-07 14:37:18 -080083 private static final int FLING_THRESHOLD_VELOCITY = 500;
Adam Cohened51cc92011-08-01 20:28:08 -070084
Winson Chung9171e6d2010-11-17 17:39:27 -080085 // These animators are used to fade the children's outlines
86 private ObjectAnimator mChildrenOutlineFadeInAnimation;
87 private ObjectAnimator mChildrenOutlineFadeOutAnimation;
88 private float mChildrenOutlineAlpha = 0;
89
90 // These properties refer to the background protection gradient used for AllApps and Customize
Michael Jurkae0f5a612011-02-07 16:45:41 -080091 private ValueAnimator mBackgroundFadeInAnimation;
92 private ValueAnimator mBackgroundFadeOutAnimation;
Winson Chung9171e6d2010-11-17 17:39:27 -080093 private Drawable mBackground;
Michael Jurka25356e72011-03-03 14:53:11 -080094 boolean mDrawBackground = true;
Adam Cohenf34bab52010-09-30 14:11:56 -070095 private float mBackgroundAlpha = 0;
Adam Cohen68d73932010-11-15 10:50:58 -080096 private float mOverScrollMaxBackgroundAlpha = 0.0f;
Adam Cohenf34bab52010-09-30 14:11:56 -070097
Adam Cohenbeff8c62011-08-31 17:46:01 -070098 private float mWallpaperScrollRatio = 1.0f;
99
Dianne Hackborn8f573952009-08-10 23:21:09 -0700100 private final WallpaperManager mWallpaperManager;
Michael Jurka9c6fbed2011-03-02 17:41:34 -0800101 private IBinder mWindowToken;
Michael Jurka16706982011-09-26 16:39:22 -0700102 private static final float WALLPAPER_SCREENS_SPAN = 2f;
Winson Chungaafa03c2010-06-11 17:34:16 -0700103
Michael Jurka0142d492010-08-25 17:46:15 -0700104 private int mDefaultPage;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800105
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800106 /**
107 * CellInfo for the cell that is currently being dragged
108 */
109 private CellLayout.CellInfo mDragInfo;
Winson Chungaafa03c2010-06-11 17:34:16 -0700110
Jeff Sharkey70864282009-04-07 21:08:40 -0700111 /**
112 * Target drop area calculated during last acceptDrop call.
113 */
Adam Cohenc0dcf592011-06-01 15:30:43 -0700114 private int[] mTargetCell = new int[2];
Adam Cohenc6cc61d2012-04-04 12:47:08 -0700115 private int mDragOverX = -1;
116 private int mDragOverY = -1;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800117
Adam Cohena897f392012-04-27 18:12:05 -0700118 static Rect mLandscapeCellLayoutMetrics = null;
119 static Rect mPortraitCellLayoutMetrics = null;
120
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700121 /**
122 * The CellLayout that is currently being dragged over
123 */
124 private CellLayout mDragTargetLayout = null;
Adam Cohenc6cc61d2012-04-04 12:47:08 -0700125 /**
126 * The CellLayout that we will show as glowing
127 */
128 private CellLayout mDragOverlappingLayout = null;
129
130 /**
131 * The CellLayout which will be dropped to
132 */
133 private CellLayout mDropToLayout = null;
134
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800135 private Launcher mLauncher;
Joe Onorato0589f0f2010-02-08 13:44:00 -0800136 private IconCache mIconCache;
Joe Onorato00acb122009-08-04 16:04:30 -0400137 private DragController mDragController;
Winson Chungaafa03c2010-06-11 17:34:16 -0700138
Michael Jurka4516c112010-10-07 15:13:47 -0700139 // These are temporary variables to prevent having to allocate a new object just to
140 // return an (x, y) value from helper functions. Do NOT use them to maintain other state.
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800141 private int[] mTempCell = new int[2];
Jeff Sharkey70864282009-04-07 21:08:40 -0700142 private int[] mTempEstimate = new int[2];
Adam Cohene3e27a82011-04-15 12:07:39 -0700143 private float[] mDragViewVisualCenter = new float[2];
Michael Jurkaa63c4522010-08-19 13:52:27 -0700144 private float[] mTempDragCoordinates = new float[2];
Michael Jurka4516c112010-10-07 15:13:47 -0700145 private float[] mTempCellLayoutCenterCoordinates = new float[2];
Michael Jurkaa63c4522010-08-19 13:52:27 -0700146 private float[] mTempDragBottomRightCoordinates = new float[2];
Michael Jurka0280c3b2010-09-17 15:00:07 -0700147 private Matrix mTempInverseMatrix = new Matrix();
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800148
Michael Jurkac2f7f472010-12-14 15:34:42 -0800149 private SpringLoadedDragController mSpringLoadedDragController;
Winson Chungb26f3d62011-06-02 10:49:29 -0700150 private float mSpringLoadedShrinkFactor;
Michael Jurkad3ef3062010-11-23 16:23:58 -0800151
Adam Cohend22015c2010-07-26 22:02:18 -0700152 private static final int DEFAULT_CELL_COUNT_X = 4;
153 private static final int DEFAULT_CELL_COUNT_Y = 4;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800154
Patrick Dubroy1262e362010-10-06 15:49:50 -0700155 // State variable that indicates whether the pages are small (ie when you're
Michael Jurkadee05892010-07-27 10:01:56 -0700156 // in all apps or customize mode)
Michael Jurkad74c9842011-07-10 12:44:21 -0700157
158 enum State { NORMAL, SPRING_LOADED, SMALL };
Adam Cohen7777d962011-08-18 18:58:38 -0700159 private State mState = State.NORMAL;
Michael Jurkad74c9842011-07-10 12:44:21 -0700160 private boolean mIsSwitchingState = false;
Michael Jurkad74c9842011-07-10 12:44:21 -0700161
Michael Jurkad74c9842011-07-10 12:44:21 -0700162 boolean mAnimatingViewIntoPlace = false;
163 boolean mIsDragOccuring = false;
164 boolean mChildrenLayersEnabled = true;
Michael Jurkadee05892010-07-27 10:01:56 -0700165
Patrick Dubroy54fa3b92010-11-17 12:18:45 -0800166 /** Is the user is dragging an item near the edge of a page? */
Patrick Dubroy1262e362010-10-06 15:49:50 -0700167 private boolean mInScrollArea = false;
168
Patrick Dubroy8e58e912010-10-14 13:21:48 -0700169 private final HolographicOutlineHelper mOutlineHelper = new HolographicOutlineHelper();
Joe Onorato4be866d2010-10-10 11:26:02 -0700170 private Bitmap mDragOutline = null;
Patrick Dubroy8e58e912010-10-14 13:21:48 -0700171 private final Rect mTempRect = new Rect();
172 private final int[] mTempXY = new int[2];
Michael Jurkad51f33a2012-06-28 15:35:26 -0700173 private int[] mTempVisiblePagesRange = new int[2];
Adam Cohen21b41102011-11-01 17:29:52 -0700174 private float mOverscrollFade = 0;
Michael Jurkab06d95f2012-04-02 06:26:53 -0700175 private boolean mOverscrollTransformsSet;
Michael Jurkaf8304f02012-04-26 13:33:26 -0700176 public static final int DRAG_BITMAP_PADDING = 2;
Michael Jurka869390b2012-05-06 15:55:19 -0700177 private boolean mWorkspaceFadeInAdjacentScreens;
Joe Onorato4be866d2010-10-10 11:26:02 -0700178
Michael Jurkac5b262c2011-01-12 20:24:50 -0800179 enum WallpaperVerticalOffset { TOP, MIDDLE, BOTTOM };
180 int mWallpaperWidth;
181 int mWallpaperHeight;
Michael Jurkaab1983f2011-01-18 15:50:17 -0800182 WallpaperOffsetInterpolator mWallpaperOffset;
Michael Jurkac5b262c2011-01-12 20:24:50 -0800183 boolean mUpdateWallpaperOffsetImmediately = false;
Adam Cohen26976d92011-03-22 15:33:33 -0700184 private Runnable mDelayedResizeRunnable;
Winson Chungf0c6ae02012-03-21 16:10:31 -0700185 private Runnable mDelayedSnapToPageRunnable;
Michael Jurka84f2ce72012-04-13 15:08:01 -0700186 private Point mDisplaySize = new Point();
Michael Jurka95515372012-02-29 14:13:01 -0800187 private boolean mIsStaticWallpaper;
Adam Cohencff6af82011-09-13 14:51:53 -0700188 private int mWallpaperTravelWidth;
Winson Chung8aad6102012-05-11 16:27:49 -0700189 private int mSpringLoadedPageSpacing;
Adam Cohen94309882012-06-08 16:24:56 -0700190 private int mCameraDistance;
Michael Jurkac5b262c2011-01-12 20:24:50 -0800191
Adam Cohen19072da2011-05-31 14:30:45 -0700192 // Variables relating to the creation of user folders by hovering shortcuts over shortcuts
Adam Cohen482ed822012-03-02 14:15:13 -0800193 private static final int FOLDER_CREATION_TIMEOUT = 0;
194 private static final int REORDER_TIMEOUT = 250;
Adam Cohen19072da2011-05-31 14:30:45 -0700195 private final Alarm mFolderCreationAlarm = new Alarm();
Adam Cohen482ed822012-03-02 14:15:13 -0800196 private final Alarm mReorderAlarm = new Alarm();
Adam Cohen19072da2011-05-31 14:30:45 -0700197 private FolderRingAnimator mDragFolderRingAnimator = null;
Adam Cohenc6cc61d2012-04-04 12:47:08 -0700198 private FolderIcon mDragOverFolderIcon = null;
Adam Cohen19072da2011-05-31 14:30:45 -0700199 private boolean mCreateUserFolderOnDrop = false;
Adam Cohenc6cc61d2012-04-04 12:47:08 -0700200 private boolean mAddToExistingFolderOnDrop = false;
201 private DropTarget.DragEnforcer mDragEnforcer;
Adam Cohen3aff81c2012-05-16 21:01:01 -0700202 private float mMaxDistanceForFolderCreation;
Adam Cohen073a46f2011-05-17 16:28:09 -0700203
Adam Cohenf8d28232011-02-01 21:47:00 -0800204 // Variables relating to touch disambiguation (scrolling workspace vs. scrolling a widget)
205 private float mXDown;
206 private float mYDown;
207 final static float START_DAMPING_TOUCH_SLOP_ANGLE = (float) Math.PI / 6;
208 final static float MAX_SWIPE_ANGLE = (float) Math.PI / 3;
209 final static float TOUCH_SLOP_DAMPING_FACTOR = 4;
210
Adam Cohened66b2b2012-01-23 17:28:51 -0800211 // Relating to the animation of items being dropped externally
Adam Cohend41fbf52012-02-16 23:53:59 -0800212 public static final int ANIMATE_INTO_POSITION_AND_DISAPPEAR = 0;
213 public static final int ANIMATE_INTO_POSITION_AND_REMAIN = 1;
214 public static final int ANIMATE_INTO_POSITION_AND_RESIZE = 2;
215 public static final int COMPLETE_TWO_STAGE_WIDGET_DROP_ANIMATION = 3;
216 public static final int CANCEL_TWO_STAGE_WIDGET_DROP_ANIMATION = 4;
Adam Cohened66b2b2012-01-23 17:28:51 -0800217
Adam Cohen482ed822012-03-02 14:15:13 -0800218 // Related to dragging, folder creation and reordering
219 private static final int DRAG_MODE_NONE = 0;
220 private static final int DRAG_MODE_CREATE_FOLDER = 1;
221 private static final int DRAG_MODE_ADD_TO_FOLDER = 2;
222 private static final int DRAG_MODE_REORDER = 3;
223 private int mDragMode = DRAG_MODE_NONE;
224 private int mLastReorderX = -1;
225 private int mLastReorderY = -1;
226
Adam Cohen4b285c52011-07-21 14:24:06 -0700227 // These variables are used for storing the initial and final values during workspace animations
Adam Cohened51cc92011-08-01 20:28:08 -0700228 private int mSavedScrollX;
229 private float mSavedRotationY;
230 private float mSavedTranslationX;
Adam Cohen4b285c52011-07-21 14:24:06 -0700231 private float mCurrentScaleX;
232 private float mCurrentScaleY;
233 private float mCurrentRotationY;
234 private float mCurrentTranslationX;
235 private float mCurrentTranslationY;
236 private float[] mOldTranslationXs;
237 private float[] mOldTranslationYs;
238 private float[] mOldScaleXs;
239 private float[] mOldScaleYs;
240 private float[] mOldBackgroundAlphas;
Adam Cohen4b285c52011-07-21 14:24:06 -0700241 private float[] mOldAlphas;
Adam Cohen4b285c52011-07-21 14:24:06 -0700242 private float[] mNewTranslationXs;
243 private float[] mNewTranslationYs;
244 private float[] mNewScaleXs;
245 private float[] mNewScaleYs;
246 private float[] mNewBackgroundAlphas;
Adam Cohen4b285c52011-07-21 14:24:06 -0700247 private float[] mNewAlphas;
248 private float[] mNewRotationYs;
Winson Chung70442722012-02-10 15:43:22 -0800249 private float mTransitionProgress;
Adam Cohen4b285c52011-07-21 14:24:06 -0700250
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800251 /**
252 * Used to inflate the Workspace from XML.
253 *
254 * @param context The application's context.
Michael Jurka0142d492010-08-25 17:46:15 -0700255 * @param attrs The attributes set containing the Workspace's customization values.
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800256 */
257 public Workspace(Context context, AttributeSet attrs) {
258 this(context, attrs, 0);
259 }
260
261 /**
262 * Used to inflate the Workspace from XML.
263 *
264 * @param context The application's context.
Michael Jurka0142d492010-08-25 17:46:15 -0700265 * @param attrs The attributes set containing the Workspace's customization values.
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800266 * @param defStyle Unused.
267 */
268 public Workspace(Context context, AttributeSet attrs, int defStyle) {
269 super(context, attrs, defStyle);
Michael Jurka0142d492010-08-25 17:46:15 -0700270 mContentIsRefreshable = false;
Michael Jurka5f1c5092010-09-03 14:15:02 -0700271
Adam Cohenc6cc61d2012-04-04 12:47:08 -0700272 mDragEnforcer = new DropTarget.DragEnforcer(context);
Winson Chungf0ea4d32011-06-06 14:27:16 -0700273 // With workspace, data is available straight from the get-go
274 setDataIsReady();
275
Michael Jurka8bc66c72012-06-21 08:36:45 -0700276 mLauncher = (Launcher) context;
Winson Chung867ca622012-02-21 15:48:35 -0800277 final Resources res = getResources();
Michael Jurka869390b2012-05-06 15:55:19 -0700278 mWorkspaceFadeInAdjacentScreens = res.getBoolean(R.bool.config_workspaceFadeAdjacentScreens);
279 mFadeInAdjacentScreens = false;
Dianne Hackborn8f573952009-08-10 23:21:09 -0700280 mWallpaperManager = WallpaperManager.getInstance(context);
Winson Chungaafa03c2010-06-11 17:34:16 -0700281
Michael Jurkaf6440da2011-04-05 14:50:34 -0700282 int cellCountX = DEFAULT_CELL_COUNT_X;
283 int cellCountY = DEFAULT_CELL_COUNT_Y;
284
Winson Chungaafa03c2010-06-11 17:34:16 -0700285 TypedArray a = context.obtainStyledAttributes(attrs,
286 R.styleable.Workspace, defStyle, 0);
Michael Jurkaf6440da2011-04-05 14:50:34 -0700287
288 if (LauncherApplication.isScreenLarge()) {
Michael Jurkaf61249b2011-05-27 16:27:15 -0700289 // Determine number of rows/columns dynamically
290 // TODO: This code currently fails on tablets with an aspect ratio < 1.3.
291 // Around that ratio we should make cells the same size in portrait and
292 // landscape
Michael Jurkaf6440da2011-04-05 14:50:34 -0700293 TypedArray actionBarSizeTypedArray =
294 context.obtainStyledAttributes(new int[] { android.R.attr.actionBarSize });
Michael Jurkaf61249b2011-05-27 16:27:15 -0700295 final float actionBarHeight = actionBarSizeTypedArray.getDimension(0, 0f);
Michael Jurka8bc66c72012-06-21 08:36:45 -0700296
297 Point minDims = new Point();
298 Point maxDims = new Point();
299 mLauncher.getWindowManager().getDefaultDisplay().getCurrentSizeRange(minDims, maxDims);
Michael Jurkaf6440da2011-04-05 14:50:34 -0700300
Michael Jurkaf61249b2011-05-27 16:27:15 -0700301 cellCountX = 1;
Michael Jurka8bc66c72012-06-21 08:36:45 -0700302 while (CellLayout.widthInPortrait(res, cellCountX + 1) <= minDims.x) {
Michael Jurkaf61249b2011-05-27 16:27:15 -0700303 cellCountX++;
Michael Jurkaf6440da2011-04-05 14:50:34 -0700304 }
Michael Jurkaf6440da2011-04-05 14:50:34 -0700305
Michael Jurkaf61249b2011-05-27 16:27:15 -0700306 cellCountY = 1;
307 while (actionBarHeight + CellLayout.heightInLandscape(res, cellCountY + 1)
Michael Jurka8bc66c72012-06-21 08:36:45 -0700308 <= minDims.y) {
Michael Jurkaf61249b2011-05-27 16:27:15 -0700309 cellCountY++;
Michael Jurkaf6440da2011-04-05 14:50:34 -0700310 }
Michael Jurkaf6440da2011-04-05 14:50:34 -0700311 }
312
Winson Chungb26f3d62011-06-02 10:49:29 -0700313 mSpringLoadedShrinkFactor =
314 res.getInteger(R.integer.config_workspaceSpringLoadShrinkPercentage) / 100.0f;
Winson Chung8aad6102012-05-11 16:27:49 -0700315 mSpringLoadedPageSpacing =
316 res.getDimensionPixelSize(R.dimen.workspace_spring_loaded_page_spacing);
Adam Cohen94309882012-06-08 16:24:56 -0700317 mCameraDistance = res.getInteger(R.integer.config_cameraDistance);
Winson Chungb26f3d62011-06-02 10:49:29 -0700318
Michael Jurkaf6440da2011-04-05 14:50:34 -0700319 // if the value is manually specified, use that instead
320 cellCountX = a.getInt(R.styleable.Workspace_cellCountX, cellCountX);
321 cellCountY = a.getInt(R.styleable.Workspace_cellCountY, cellCountY);
Michael Jurka0142d492010-08-25 17:46:15 -0700322 mDefaultPage = a.getInt(R.styleable.Workspace_defaultScreen, 1);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800323 a.recycle();
324
Michael Jurka8b805b12012-04-18 14:23:14 -0700325 setOnHierarchyChangeListener(this);
326
Adam Cohend22015c2010-07-26 22:02:18 -0700327 LauncherModel.updateWorkspaceLayoutCells(cellCountX, cellCountY);
Joe Onorato0d44e942009-11-16 18:20:51 -0800328 setHapticFeedbackEnabled(false);
Michael Jurka0142d492010-08-25 17:46:15 -0700329
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800330 initWorkspace();
Winson Chungc35afb22011-02-23 13:01:49 -0800331
332 // Disable multitouch across the workspace/all apps/customize tray
333 setMotionEventSplittingEnabled(true);
Svetoslav Ganov08055f62012-05-15 11:06:36 -0700334
335 // Unless otherwise specified this view is important for accessibility.
336 if (getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
337 setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
338 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800339 }
340
Michael Jurka038f9d82011-11-03 13:50:45 -0700341 // estimate the size of a widget with spans hSpan, vSpan. return MAX_VALUE for each
342 // dimension if unsuccessful
343 public int[] estimateItemSize(int hSpan, int vSpan,
Adam Cohend41fbf52012-02-16 23:53:59 -0800344 ItemInfo itemInfo, boolean springLoaded) {
Michael Jurka038f9d82011-11-03 13:50:45 -0700345 int[] size = new int[2];
346 if (getChildCount() > 0) {
347 CellLayout cl = (CellLayout) mLauncher.getWorkspace().getChildAt(0);
Adam Cohend41fbf52012-02-16 23:53:59 -0800348 Rect r = estimateItemPosition(cl, itemInfo, 0, 0, hSpan, vSpan);
349 size[0] = r.width();
350 size[1] = r.height();
Michael Jurka038f9d82011-11-03 13:50:45 -0700351 if (springLoaded) {
352 size[0] *= mSpringLoadedShrinkFactor;
353 size[1] *= mSpringLoadedShrinkFactor;
354 }
355 return size;
356 } else {
357 size[0] = Integer.MAX_VALUE;
358 size[1] = Integer.MAX_VALUE;
359 return size;
360 }
361 }
Adam Cohend41fbf52012-02-16 23:53:59 -0800362 public Rect estimateItemPosition(CellLayout cl, ItemInfo pendingInfo,
Michael Jurka038f9d82011-11-03 13:50:45 -0700363 int hCell, int vCell, int hSpan, int vSpan) {
Adam Cohend41fbf52012-02-16 23:53:59 -0800364 Rect r = new Rect();
Michael Jurka038f9d82011-11-03 13:50:45 -0700365 cl.cellToRect(hCell, vCell, hSpan, vSpan, r);
Michael Jurka038f9d82011-11-03 13:50:45 -0700366 return r;
367 }
368
Michael Jurkad74c9842011-07-10 12:44:21 -0700369 public void onDragStart(DragSource source, Object info, int dragAction) {
370 mIsDragOccuring = true;
Michael Jurka3a0469d2012-06-21 09:38:41 -0700371 updateChildrenLayersEnabled(false);
Winson Chung641d71d2012-04-26 15:58:01 -0700372 mLauncher.lockScreenOrientation();
Michael Jurkaa3d30ad2012-05-08 13:43:43 -0700373 setChildrenBackgroundAlphaMultipliers(1f);
Winson Chungf561bdf2012-05-03 11:20:19 -0700374 // Prevent any Un/InstallShortcutReceivers from updating the db while we are dragging
375 InstallShortcutReceiver.enableInstallQueue();
376 UninstallShortcutReceiver.enableUninstallQueue();
Michael Jurkad74c9842011-07-10 12:44:21 -0700377 }
378
379 public void onDragEnd() {
380 mIsDragOccuring = false;
Michael Jurka3a0469d2012-06-21 09:38:41 -0700381 updateChildrenLayersEnabled(false);
Winson Chung4b919f82012-05-01 10:44:08 -0700382 mLauncher.unlockScreenOrientation(false);
Winson Chungf561bdf2012-05-03 11:20:19 -0700383
384 // Re-enable any Un/InstallShortcutReceiver and now process any queued items
385 InstallShortcutReceiver.disableAndFlushInstallQueue(getContext());
386 UninstallShortcutReceiver.disableAndFlushUninstallQueue(getContext());
Michael Jurkad74c9842011-07-10 12:44:21 -0700387 }
388
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800389 /**
390 * Initializes various states for this workspace.
391 */
Michael Jurka0142d492010-08-25 17:46:15 -0700392 protected void initWorkspace() {
Joe Onorato0589f0f2010-02-08 13:44:00 -0800393 Context context = getContext();
Michael Jurka0142d492010-08-25 17:46:15 -0700394 mCurrentPage = mDefaultPage;
395 Launcher.setScreen(mCurrentPage);
Joe Onorato0589f0f2010-02-08 13:44:00 -0800396 LauncherApplication app = (LauncherApplication)context.getApplicationContext();
397 mIconCache = app.getIconCache();
Patrick Dubroycd68ff52010-10-28 17:57:05 -0700398 setWillNotDraw(false);
Adam Cohen7777d962011-08-18 18:58:38 -0700399 setChildrenDrawnWithCacheEnabled(true);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800400
Adam Cohen482ed822012-03-02 14:15:13 -0800401 final Resources res = getResources();
Winson Chungb4b7fa72010-11-18 14:38:53 -0800402 try {
Winson Chungfd3385f2011-06-15 19:51:24 -0700403 mBackground = res.getDrawable(R.drawable.apps_customize_bg);
Winson Chungb4b7fa72010-11-18 14:38:53 -0800404 } catch (Resources.NotFoundException e) {
405 // In this case, we will skip drawing background protection
406 }
Winson Chung9171e6d2010-11-17 17:39:27 -0800407
Michael Jurkaab1983f2011-01-18 15:50:17 -0800408 mWallpaperOffset = new WallpaperOffsetInterpolator();
Adam Cohencff6af82011-09-13 14:51:53 -0700409 Display display = mLauncher.getWindowManager().getDefaultDisplay();
Michael Jurka84f2ce72012-04-13 15:08:01 -0700410 display.getSize(mDisplaySize);
411 mWallpaperTravelWidth = (int) (mDisplaySize.x *
412 wallpaperTravelToScreenWidthRatio(mDisplaySize.x, mDisplaySize.y));
Adam Cohen265b9a62011-12-07 14:37:18 -0800413
Adam Cohen3aff81c2012-05-16 21:01:01 -0700414 mMaxDistanceForFolderCreation = (0.55f * res.getDimensionPixelSize(R.dimen.app_icon_size));
Adam Cohen265b9a62011-12-07 14:37:18 -0800415 mFlingThresholdVelocity = (int) (FLING_THRESHOLD_VELOCITY * mDensity);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800416 }
417
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800418 @Override
Adam Cohenf34bab52010-09-30 14:11:56 -0700419 protected int getScrollMode() {
Winson Chungb26f3d62011-06-02 10:49:29 -0700420 return SmoothPagedView.X_LARGE_MODE;
Adam Cohenf34bab52010-09-30 14:11:56 -0700421 }
422
Michael Jurka08ee7702011-08-11 16:53:35 -0700423 @Override
Michael Jurka8b805b12012-04-18 14:23:14 -0700424 public void onChildViewAdded(View parent, View child) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800425 if (!(child instanceof CellLayout)) {
426 throw new IllegalArgumentException("A Workspace can only have CellLayout children.");
427 }
Adam Cohen2801caf2011-05-13 20:57:39 -0700428 CellLayout cl = ((CellLayout) child);
429 cl.setOnInterceptTouchListener(this);
Adam Cohen2801caf2011-05-13 20:57:39 -0700430 cl.setClickable(true);
alanv51944f12012-05-07 17:31:32 -0700431 cl.setContentDescription(getContext().getString(
432 R.string.workspace_description_format, getChildCount()));
Michael Jurkae5fb0f22011-04-11 13:27:46 -0700433 }
Adam Cohen2801caf2011-05-13 20:57:39 -0700434
Michael Jurka8b805b12012-04-18 14:23:14 -0700435 @Override
436 public void onChildViewRemoved(View parent, View child) {
437 }
438
Michael Jurka920d7f42012-05-14 16:29:55 -0700439 protected boolean shouldDrawChild(View child) {
440 final CellLayout cl = (CellLayout) child;
441 return super.shouldDrawChild(child) &&
442 (cl.getShortcutsAndWidgets().getAlpha() > 0 ||
443 cl.getBackgroundAlpha() > 0);
444 }
445
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800446 /**
447 * @return The open folder on the current screen, or null if there is none
448 */
449 Folder getOpenFolder() {
Adam Cohen716b51e2011-06-30 12:09:54 -0700450 DragLayer dragLayer = mLauncher.getDragLayer();
Adam Cohen8e776a62011-06-28 18:10:06 -0700451 int count = dragLayer.getChildCount();
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800452 for (int i = 0; i < count; i++) {
Adam Cohen8e776a62011-06-28 18:10:06 -0700453 View child = dragLayer.getChildAt(i);
Winson Chungaafa03c2010-06-11 17:34:16 -0700454 if (child instanceof Folder) {
455 Folder folder = (Folder) child;
456 if (folder.getInfo().opened)
457 return folder;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800458 }
459 }
460 return null;
461 }
462
Patrick Dubroya0aa0122011-02-24 11:42:23 -0800463 boolean isTouchActive() {
464 return mTouchState != TOUCH_STATE_REST;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800465 }
466
467 /**
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800468 * Adds the specified child in the specified screen. The position and dimension of
469 * the child are defined by x, y, spanX and spanY.
470 *
471 * @param child The child to add in one of the workspace's screens.
472 * @param screen The screen in which to add the child.
473 * @param x The X position of the child in the screen's grid.
474 * @param y The Y position of the child in the screen's grid.
475 * @param spanX The number of cells spanned horizontally by the child.
476 * @param spanY The number of cells spanned vertically by the child.
477 */
Winson Chung3d503fb2011-07-13 17:25:49 -0700478 void addInScreen(View child, long container, int screen, int x, int y, int spanX, int spanY) {
479 addInScreen(child, container, screen, x, y, spanX, spanY, false);
Winson Chungaafa03c2010-06-11 17:34:16 -0700480 }
481
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800482 /**
483 * Adds the specified child in the specified screen. The position and dimension of
484 * the child are defined by x, y, spanX and spanY.
485 *
486 * @param child The child to add in one of the workspace's screens.
487 * @param screen The screen in which to add the child.
488 * @param x The X position of the child in the screen's grid.
489 * @param y The Y position of the child in the screen's grid.
490 * @param spanX The number of cells spanned horizontally by the child.
491 * @param spanY The number of cells spanned vertically by the child.
492 * @param insert When true, the child is inserted at the beginning of the children list.
493 */
Winson Chung3d503fb2011-07-13 17:25:49 -0700494 void addInScreen(View child, long container, int screen, int x, int y, int spanX, int spanY,
495 boolean insert) {
496 if (container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
497 if (screen < 0 || screen >= getChildCount()) {
498 Log.e(TAG, "The screen must be >= 0 and < " + getChildCount()
499 + " (was " + screen + "); skipping child");
500 return;
501 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800502 }
503
Winson Chung3d503fb2011-07-13 17:25:49 -0700504 final CellLayout layout;
505 if (container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
506 layout = mLauncher.getHotseat().getLayout();
Winson Chung4d279d92011-07-21 11:46:32 -0700507 child.setOnKeyListener(null);
Winson Chung3d503fb2011-07-13 17:25:49 -0700508
Adam Cohen099f60d2011-08-23 21:07:26 -0700509 // Hide folder title in the hotseat
510 if (child instanceof FolderIcon) {
511 ((FolderIcon) child).setTextVisible(false);
512 }
513
Winson Chung3d503fb2011-07-13 17:25:49 -0700514 if (screen < 0) {
515 screen = mLauncher.getHotseat().getOrderInHotseat(x, y);
516 } else {
517 // Note: We do this to ensure that the hotseat is always laid out in the orientation
518 // of the hotseat in order regardless of which orientation they were added
519 x = mLauncher.getHotseat().getCellXFromOrder(screen);
520 y = mLauncher.getHotseat().getCellYFromOrder(screen);
521 }
522 } else {
Adam Cohen099f60d2011-08-23 21:07:26 -0700523 // Show folder title if not in the hotseat
524 if (child instanceof FolderIcon) {
525 ((FolderIcon) child).setTextVisible(true);
526 }
527
Winson Chung3d503fb2011-07-13 17:25:49 -0700528 layout = (CellLayout) getChildAt(screen);
Adam Cohenac56cff2011-09-28 20:45:37 -0700529 child.setOnKeyListener(new IconKeyEventListener());
Winson Chung3d503fb2011-07-13 17:25:49 -0700530 }
531
Adam Cohened66b2b2012-01-23 17:28:51 -0800532 LayoutParams genericLp = child.getLayoutParams();
533 CellLayout.LayoutParams lp;
534 if (genericLp == null || !(genericLp instanceof CellLayout.LayoutParams)) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800535 lp = new CellLayout.LayoutParams(x, y, spanX, spanY);
536 } else {
Adam Cohened66b2b2012-01-23 17:28:51 -0800537 lp = (CellLayout.LayoutParams) genericLp;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800538 lp.cellX = x;
539 lp.cellY = y;
540 lp.cellHSpan = spanX;
541 lp.cellVSpan = spanY;
542 }
Winson Chungaafa03c2010-06-11 17:34:16 -0700543
Adam Cohen7f4eabe2011-04-21 16:19:16 -0700544 if (spanX < 0 && spanY < 0) {
545 lp.isLockedToGrid = false;
546 }
547
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700548 // Get the canonical child id to uniquely represent this view in this screen
Winson Chung3d503fb2011-07-13 17:25:49 -0700549 int childId = LauncherModel.getCellLayoutChildId(container, screen, x, y, spanX, spanY);
Michael Jurkaf3ca3ab2010-10-20 17:08:24 -0700550 boolean markCellsAsOccupied = !(child instanceof Folder);
Winson Chung3d503fb2011-07-13 17:25:49 -0700551 if (!layout.addViewToCellLayout(child, insert ? 0 : -1, childId, lp, markCellsAsOccupied)) {
Winson Chungaafa03c2010-06-11 17:34:16 -0700552 // TODO: This branch occurs when the workspace is adding views
553 // outside of the defined grid
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700554 // maybe we should be deleting these items from the LauncherModel?
Winson Chungaafa03c2010-06-11 17:34:16 -0700555 Log.w(TAG, "Failed to add to item at (" + lp.cellX + "," + lp.cellY + ") to CellLayout");
556 }
557
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800558 if (!(child instanceof Folder)) {
Joe Onorato0d44e942009-11-16 18:20:51 -0800559 child.setHapticFeedbackEnabled(false);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800560 child.setOnLongClickListener(mLongClickListener);
561 }
Joe Onorato00acb122009-08-04 16:04:30 -0400562 if (child instanceof DropTarget) {
Winson Chungaafa03c2010-06-11 17:34:16 -0700563 mDragController.addDropTarget((DropTarget) child);
Joe Onorato00acb122009-08-04 16:04:30 -0400564 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800565 }
566
Patrick Dubroyd0ce1ec2011-01-19 18:47:27 -0800567 /**
568 * Check if the point (x, y) hits a given page.
569 */
570 private boolean hitsPage(int index, float x, float y) {
571 final View page = getChildAt(index);
572 if (page != null) {
573 float[] localXY = { x, y };
574 mapPointFromSelfToChild(page, localXY);
575 return (localXY[0] >= 0 && localXY[0] < page.getWidth()
576 && localXY[1] >= 0 && localXY[1] < page.getHeight());
577 }
578 return false;
579 }
580
581 @Override
582 protected boolean hitsPreviousPage(float x, float y) {
583 // mNextPage is set to INVALID_PAGE whenever we are stationary.
584 // Calculating "next page" this way ensures that you scroll to whatever page you tap on
585 final int current = (mNextPage == INVALID_PAGE) ? mCurrentPage : mNextPage;
Michael Jurkab72094f2011-09-14 14:53:19 -0700586
587 // Only allow tap to next page on large devices, where there's significant margin outside
588 // the active workspace
589 return LauncherApplication.isScreenLarge() && hitsPage(current - 1, x, y);
Patrick Dubroyd0ce1ec2011-01-19 18:47:27 -0800590 }
591
592 @Override
593 protected boolean hitsNextPage(float x, float y) {
594 // mNextPage is set to INVALID_PAGE whenever we are stationary.
595 // Calculating "next page" this way ensures that you scroll to whatever page you tap on
596 final int current = (mNextPage == INVALID_PAGE) ? mCurrentPage : mNextPage;
Michael Jurkab72094f2011-09-14 14:53:19 -0700597
598 // Only allow tap to next page on large devices, where there's significant margin outside
599 // the active workspace
600 return LauncherApplication.isScreenLarge() && hitsPage(current + 1, x, y);
Patrick Dubroyd0ce1ec2011-01-19 18:47:27 -0800601 }
602
Patrick Dubroye708c522011-03-01 16:03:43 -0800603 /**
604 * Called directly from a CellLayout (not by the framework), after we've been added as a
605 * listener via setOnInterceptTouchEventListener(). This allows us to tell the CellLayout
606 * that it should intercept touch events, which is not something that is normally supported.
607 */
608 @Override
Michael Jurkadee05892010-07-27 10:01:56 -0700609 public boolean onTouch(View v, MotionEvent event) {
Winson Chung70442722012-02-10 15:43:22 -0800610 return (isSmall() || !isFinishedSwitchingState());
Patrick Dubroye708c522011-03-01 16:03:43 -0800611 }
612
Adam Cohenfc53cd22011-07-20 15:45:11 -0700613 public boolean isSwitchingState() {
614 return mIsSwitchingState;
615 }
616
Winson Chung70442722012-02-10 15:43:22 -0800617 /** This differs from isSwitchingState in that we take into account how far the transition
618 * has completed. */
Winson Chung9b0b2fe2012-02-24 13:03:34 -0800619 public boolean isFinishedSwitchingState() {
Winson Chung70442722012-02-10 15:43:22 -0800620 return !mIsSwitchingState || (mTransitionProgress > 0.5f);
621 }
622
Adam Cohended9f8d2010-11-03 13:25:16 -0700623 protected void onWindowVisibilityChanged (int visibility) {
624 mLauncher.onWindowVisibilityChanged(visibility);
625 }
626
Michael Jurka5f1c5092010-09-03 14:15:02 -0700627 @Override
628 public boolean dispatchUnhandledMove(View focused, int direction) {
Winson Chung70442722012-02-10 15:43:22 -0800629 if (isSmall() || !isFinishedSwitchingState()) {
Michael Jurka5f1c5092010-09-03 14:15:02 -0700630 // when the home screens are shrunken, shouldn't allow side-scrolling
631 return false;
632 }
633 return super.dispatchUnhandledMove(focused, direction);
634 }
635
636 @Override
637 public boolean onInterceptTouchEvent(MotionEvent ev) {
Michael Jurkad771c962011-08-09 15:00:48 -0700638 switch (ev.getAction() & MotionEvent.ACTION_MASK) {
639 case MotionEvent.ACTION_DOWN:
Adam Cohenf8d28232011-02-01 21:47:00 -0800640 mXDown = ev.getX();
641 mYDown = ev.getY();
Michael Jurkad771c962011-08-09 15:00:48 -0700642 break;
643 case MotionEvent.ACTION_POINTER_UP:
644 case MotionEvent.ACTION_UP:
645 if (mTouchState == TOUCH_STATE_REST) {
646 final CellLayout currentPage = (CellLayout) getChildAt(mCurrentPage);
647 if (!currentPage.lastDownOnOccupiedCell()) {
648 onWallpaperTap(ev);
649 }
650 }
Adam Cohenf8d28232011-02-01 21:47:00 -0800651 }
Michael Jurka5f1c5092010-09-03 14:15:02 -0700652 return super.onInterceptTouchEvent(ev);
653 }
654
Adam Cohen3d509322012-06-06 14:10:04 -0700655 protected void reinflateWidgetsIfNecessary() {
656 final int clCount = getChildCount();
657 for (int i = 0; i < clCount; i++) {
658 CellLayout cl = (CellLayout) getChildAt(i);
659 ShortcutAndWidgetContainer swc = cl.getShortcutsAndWidgets();
660 final int itemCount = swc.getChildCount();
661 for (int j = 0; j < itemCount; j++) {
662 View v = swc.getChildAt(j);
663
664 if (v.getTag() instanceof LauncherAppWidgetInfo) {
665 LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) v.getTag();
666 LauncherAppWidgetHostView lahv = (LauncherAppWidgetHostView) info.hostView;
667 if (lahv != null && lahv.orientationChangedSincedInflation()) {
668 mLauncher.removeAppWidget(info);
669 // Remove the current widget which is inflated with the wrong orientation
670 cl.removeView(lahv);
671 mLauncher.bindAppWidget(info);
672 }
673 }
674 }
675 }
676 }
677
Michael Jurka1adf5392010-10-18 18:10:22 -0700678 @Override
679 protected void determineScrollingStart(MotionEvent ev) {
Winson Chung70442722012-02-10 15:43:22 -0800680 if (isSmall()) return;
681 if (!isFinishedSwitchingState()) return;
Adam Cohenf8d28232011-02-01 21:47:00 -0800682
Winson Chung70442722012-02-10 15:43:22 -0800683 float deltaX = Math.abs(ev.getX() - mXDown);
684 float deltaY = Math.abs(ev.getY() - mYDown);
Adam Cohenf8d28232011-02-01 21:47:00 -0800685
Winson Chung70442722012-02-10 15:43:22 -0800686 if (Float.compare(deltaX, 0f) == 0) return;
Adam Cohenf8d28232011-02-01 21:47:00 -0800687
Winson Chung70442722012-02-10 15:43:22 -0800688 float slope = deltaY / deltaX;
689 float theta = (float) Math.atan(slope);
Adam Cohenf8d28232011-02-01 21:47:00 -0800690
Winson Chung70442722012-02-10 15:43:22 -0800691 if (deltaX > mTouchSlop || deltaY > mTouchSlop) {
692 cancelCurrentPageLongPress();
693 }
694
695 if (theta > MAX_SWIPE_ANGLE) {
696 // Above MAX_SWIPE_ANGLE, we don't want to ever start scrolling the workspace
697 return;
698 } else if (theta > START_DAMPING_TOUCH_SLOP_ANGLE) {
699 // Above START_DAMPING_TOUCH_SLOP_ANGLE and below MAX_SWIPE_ANGLE, we want to
700 // increase the touch slop to make it harder to begin scrolling the workspace. This
701 // results in vertically scrolling widgets to more easily. The higher the angle, the
702 // more we increase touch slop.
703 theta -= START_DAMPING_TOUCH_SLOP_ANGLE;
704 float extraRatio = (float)
705 Math.sqrt((theta / (MAX_SWIPE_ANGLE - START_DAMPING_TOUCH_SLOP_ANGLE)));
706 super.determineScrollingStart(ev, 1 + TOUCH_SLOP_DAMPING_FACTOR * extraRatio);
707 } else {
708 // Below START_DAMPING_TOUCH_SLOP_ANGLE, we don't do anything special
709 super.determineScrollingStart(ev);
Adam Cohenf8d28232011-02-01 21:47:00 -0800710 }
Michael Jurka1adf5392010-10-18 18:10:22 -0700711 }
712
Winson Chung007c6982011-06-14 13:27:53 -0700713 @Override
714 protected boolean isScrollingIndicatorEnabled() {
Winson Chung48846472012-03-27 15:38:05 -0700715 return super.isScrollingIndicatorEnabled() && (mState != State.SPRING_LOADED);
Winson Chung007c6982011-06-14 13:27:53 -0700716 }
717
Patrick Dubroy1262e362010-10-06 15:49:50 -0700718 protected void onPageBeginMoving() {
Winson Chung007c6982011-06-14 13:27:53 -0700719 super.onPageBeginMoving();
720
Michael Jurkad74c9842011-07-10 12:44:21 -0700721 if (isHardwareAccelerated()) {
Michael Jurka3a0469d2012-06-21 09:38:41 -0700722 updateChildrenLayersEnabled(false);
Michael Jurka0142d492010-08-25 17:46:15 -0700723 } else {
Michael Jurkad74c9842011-07-10 12:44:21 -0700724 if (mNextPage != INVALID_PAGE) {
725 // we're snapping to a particular screen
726 enableChildrenCache(mCurrentPage, mNextPage);
727 } else {
728 // this is when user is actively dragging a particular screen, they might
729 // swipe it either left or right (but we won't advance by more than one screen)
730 enableChildrenCache(mCurrentPage - 1, mCurrentPage + 1);
731 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800732 }
Winson Chung007c6982011-06-14 13:27:53 -0700733
734 // Only show page outlines as we pan if we are on large screen
735 if (LauncherApplication.isScreenLarge()) {
736 showOutlines();
Michael Jurka95515372012-02-29 14:13:01 -0800737 mIsStaticWallpaper = mWallpaperManager.getWallpaperInfo() == null;
Winson Chung007c6982011-06-14 13:27:53 -0700738 }
Winson Chung1afedc32012-01-23 16:14:56 -0800739
Winson Chung70442722012-02-10 15:43:22 -0800740 // If we are not fading in adjacent screens, we still need to restore the alpha in case the
741 // user scrolls while we are transitioning (should not affect dispatchDraw optimizations)
Michael Jurka869390b2012-05-06 15:55:19 -0700742 if (!mWorkspaceFadeInAdjacentScreens) {
Winson Chung70442722012-02-10 15:43:22 -0800743 for (int i = 0; i < getChildCount(); ++i) {
Michael Jurkaa52570f2012-03-20 03:18:20 -0700744 ((CellLayout) getPageAt(i)).setShortcutAndWidgetAlpha(1f);
Winson Chung70442722012-02-10 15:43:22 -0800745 }
746 }
747
Winson Chung1afedc32012-01-23 16:14:56 -0800748 // Show the scroll indicator as you pan the page
749 showScrollingIndicator(false);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800750 }
751
Patrick Dubroy1262e362010-10-06 15:49:50 -0700752 protected void onPageEndMoving() {
Winson Chung007c6982011-06-14 13:27:53 -0700753 super.onPageEndMoving();
754
Michael Jurkad74c9842011-07-10 12:44:21 -0700755 if (isHardwareAccelerated()) {
Michael Jurka3a0469d2012-06-21 09:38:41 -0700756 updateChildrenLayersEnabled(false);
Michael Jurkad74c9842011-07-10 12:44:21 -0700757 } else {
758 clearChildrenCache();
759 }
760
Winson Chung3bc21c32012-01-20 13:59:18 -0800761
762 if (mDragController.isDragging()) {
763 if (isSmall()) {
764 // If we are in springloaded mode, then force an event to check if the current touch
765 // is under a new page (to scroll to)
766 mDragController.forceMoveEvent();
767 }
768 } else {
769 // If we are not mid-dragging, hide the page outlines if we are on a large screen
Winson Chung007c6982011-06-14 13:27:53 -0700770 if (LauncherApplication.isScreenLarge()) {
771 hideOutlines();
772 }
Winson Chung1afedc32012-01-23 16:14:56 -0800773
774 // Hide the scroll indicator as you pan the page
775 if (!mDragController.isDragging()) {
776 hideScrollingIndicator(false);
777 }
Patrick Dubroy1262e362010-10-06 15:49:50 -0700778 }
Adam Cohen68d73932010-11-15 10:50:58 -0800779 mOverScrollMaxBackgroundAlpha = 0.0f;
Adam Cohen26976d92011-03-22 15:33:33 -0700780
781 if (mDelayedResizeRunnable != null) {
782 mDelayedResizeRunnable.run();
783 mDelayedResizeRunnable = null;
784 }
Winson Chungf0c6ae02012-03-21 16:10:31 -0700785
786 if (mDelayedSnapToPageRunnable != null) {
787 mDelayedSnapToPageRunnable.run();
788 mDelayedSnapToPageRunnable = null;
789 }
Michael Jurka0142d492010-08-25 17:46:15 -0700790 }
791
792 @Override
793 protected void notifyPageSwitchListener() {
794 super.notifyPageSwitchListener();
Michael Jurka0142d492010-08-25 17:46:15 -0700795 Launcher.setScreen(mCurrentPage);
796 };
797
Michael Jurkac5b262c2011-01-12 20:24:50 -0800798 // As a ratio of screen height, the total distance we want the parallax effect to span
Michael Jurkac5b262c2011-01-12 20:24:50 -0800799 // horizontally
800 private float wallpaperTravelToScreenWidthRatio(int width, int height) {
801 float aspectRatio = width / (float) height;
802
803 // At an aspect ratio of 16/10, the wallpaper parallax effect should span 1.5 * screen width
804 // At an aspect ratio of 10/16, the wallpaper parallax effect should span 1.2 * screen width
805 // We will use these two data points to extrapolate how much the wallpaper parallax effect
806 // to span (ie travel) at any aspect ratio:
807
808 final float ASPECT_RATIO_LANDSCAPE = 16/10f;
809 final float ASPECT_RATIO_PORTRAIT = 10/16f;
810 final float WALLPAPER_WIDTH_TO_SCREEN_RATIO_LANDSCAPE = 1.5f;
811 final float WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT = 1.2f;
812
813 // To find out the desired width at different aspect ratios, we use the following two
814 // formulas, where the coefficient on x is the aspect ratio (width/height):
815 // (16/10)x + y = 1.5
816 // (10/16)x + y = 1.2
817 // We solve for x and y and end up with a final formula:
818 final float x =
819 (WALLPAPER_WIDTH_TO_SCREEN_RATIO_LANDSCAPE - WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT) /
820 (ASPECT_RATIO_LANDSCAPE - ASPECT_RATIO_PORTRAIT);
821 final float y = WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT - x * ASPECT_RATIO_PORTRAIT;
822 return x * aspectRatio + y;
823 }
824
825 // The range of scroll values for Workspace
826 private int getScrollRange() {
827 return getChildOffset(getChildCount() - 1) - getChildOffset(0);
828 }
829
830 protected void setWallpaperDimension() {
Michael Jurka9f5331c2012-06-20 14:02:10 -0700831 Point minDims = new Point();
832 Point maxDims = new Point();
833 mLauncher.getWindowManager().getDefaultDisplay().getCurrentSizeRange(minDims, maxDims);
834
835 final int maxDim = Math.max(maxDims.x, maxDims.y);
836 final int minDim = Math.min(minDims.x, minDims.y);
Michael Jurkac5b262c2011-01-12 20:24:50 -0800837
838 // We need to ensure that there is enough extra space in the wallpaper for the intended
839 // parallax effects
Michael Jurkaa6471802011-09-22 14:39:16 -0700840 if (LauncherApplication.isScreenLarge()) {
841 mWallpaperWidth = (int) (maxDim * wallpaperTravelToScreenWidthRatio(maxDim, minDim));
Michael Jurka193080b2011-10-28 16:08:53 -0700842 mWallpaperHeight = maxDim;
Michael Jurkaa6471802011-09-22 14:39:16 -0700843 } else {
Michael Jurka16706982011-09-26 16:39:22 -0700844 mWallpaperWidth = Math.max((int) (minDim * WALLPAPER_SCREENS_SPAN), maxDim);
Michael Jurkaa6471802011-09-22 14:39:16 -0700845 mWallpaperHeight = maxDim;
846 }
Winson Chungf7640c82011-02-28 13:47:29 -0800847 new Thread("setWallpaperDimension") {
848 public void run() {
849 mWallpaperManager.suggestDesiredDimensions(mWallpaperWidth, mWallpaperHeight);
850 }
851 }.start();
Michael Jurkac5b262c2011-01-12 20:24:50 -0800852 }
853
Michael Jurkaab1983f2011-01-18 15:50:17 -0800854 private float wallpaperOffsetForCurrentScroll() {
Michael Jurkaab1983f2011-01-18 15:50:17 -0800855 // Set wallpaper offset steps (1 / (number of screens - 1))
Michael Jurka193080b2011-10-28 16:08:53 -0700856 mWallpaperManager.setWallpaperOffsetSteps(1.0f / (getChildCount() - 1), 1.0f);
Michael Jurkaab1983f2011-01-18 15:50:17 -0800857
Michael Jurka193080b2011-10-28 16:08:53 -0700858 // For the purposes of computing the scrollRange and overScrollOffset, we assume
859 // that mLayoutScale is 1. This means that when we're in spring-loaded mode,
Adam Cohenbeff8c62011-08-31 17:46:01 -0700860 // there's no discrepancy between the wallpaper offset for a given page.
861 float layoutScale = mLayoutScale;
862 mLayoutScale = 1f;
Michael Jurka09d6eb02011-01-28 16:05:09 -0800863 int scrollRange = getScrollRange();
Michael Jurka09d6eb02011-01-28 16:05:09 -0800864
Adam Cohenbeff8c62011-08-31 17:46:01 -0700865 // Again, we adjust the wallpaper offset to be consistent between values of mLayoutScale
Michael Jurka8b805b12012-04-18 14:23:14 -0700866 float adjustedScrollX = Math.max(0, Math.min(getScrollX(), mMaxScrollX));
Adam Cohenb5ba0972011-09-07 18:02:31 -0700867 adjustedScrollX *= mWallpaperScrollRatio;
Adam Cohenbeff8c62011-08-31 17:46:01 -0700868 mLayoutScale = layoutScale;
869
Michael Jurkaab1983f2011-01-18 15:50:17 -0800870 float scrollProgress =
Michael Jurka193080b2011-10-28 16:08:53 -0700871 adjustedScrollX / (float) scrollRange;
Michael Jurka95515372012-02-29 14:13:01 -0800872
873 if (LauncherApplication.isScreenLarge() && mIsStaticWallpaper) {
874 // The wallpaper travel width is how far, from left to right, the wallpaper will move
875 // at this orientation. On tablets in portrait mode we don't move all the way to the
876 // edges of the wallpaper, or otherwise the parallax effect would be too strong.
877 int wallpaperTravelWidth = Math.min(mWallpaperTravelWidth, mWallpaperWidth);
878
879 float offsetInDips = wallpaperTravelWidth * scrollProgress +
880 (mWallpaperWidth - wallpaperTravelWidth) / 2; // center it
881 float offset = offsetInDips / (float) mWallpaperWidth;
882 return offset;
883 } else {
884 return scrollProgress;
885 }
Michael Jurkaab1983f2011-01-18 15:50:17 -0800886 }
Michael Jurka95515372012-02-29 14:13:01 -0800887
Michael Jurkaab1983f2011-01-18 15:50:17 -0800888 private void syncWallpaperOffsetWithScroll() {
Winson Chungb46a2d12011-04-22 14:13:05 -0700889 final boolean enableWallpaperEffects = isHardwareAccelerated();
890 if (enableWallpaperEffects) {
Michael Jurkaab1983f2011-01-18 15:50:17 -0800891 mWallpaperOffset.setFinalX(wallpaperOffsetForCurrentScroll());
Michael Jurkac5b262c2011-01-12 20:24:50 -0800892 }
893 }
894
895 public void updateWallpaperOffsetImmediately() {
896 mUpdateWallpaperOffsetImmediately = true;
897 }
898
Michael Jurkaab1983f2011-01-18 15:50:17 -0800899 private void updateWallpaperOffsets() {
900 boolean updateNow = false;
901 boolean keepUpdating = true;
902 if (mUpdateWallpaperOffsetImmediately) {
903 updateNow = true;
904 keepUpdating = false;
905 mWallpaperOffset.jumpToFinal();
906 mUpdateWallpaperOffsetImmediately = false;
Michael Jurkac5b262c2011-01-12 20:24:50 -0800907 } else {
Michael Jurkaab1983f2011-01-18 15:50:17 -0800908 updateNow = keepUpdating = mWallpaperOffset.computeScrollOffset();
Michael Jurkac5b262c2011-01-12 20:24:50 -0800909 }
Michael Jurkaab1983f2011-01-18 15:50:17 -0800910 if (updateNow) {
Michael Jurka9c6fbed2011-03-02 17:41:34 -0800911 if (mWindowToken != null) {
912 mWallpaperManager.setWallpaperOffsets(mWindowToken,
Michael Jurkaab1983f2011-01-18 15:50:17 -0800913 mWallpaperOffset.getCurrX(), mWallpaperOffset.getCurrY());
914 }
Michael Jurkac5b262c2011-01-12 20:24:50 -0800915 }
Michael Jurkaab1983f2011-01-18 15:50:17 -0800916 if (keepUpdating) {
Michael Jurka7372c592012-01-16 04:21:35 -0800917 invalidate();
Michael Jurkac5b262c2011-01-12 20:24:50 -0800918 }
Michael Jurkaab1983f2011-01-18 15:50:17 -0800919 }
920
Adam Cohenbeff8c62011-08-31 17:46:01 -0700921 @Override
922 protected void updateCurrentPageScroll() {
923 super.updateCurrentPageScroll();
Adam Cohen5037a0b2011-09-01 13:10:40 -0700924 computeWallpaperScrollRatio(mCurrentPage);
Adam Cohenbeff8c62011-08-31 17:46:01 -0700925 }
926
927 @Override
928 protected void snapToPage(int whichPage) {
929 super.snapToPage(whichPage);
Adam Cohen5037a0b2011-09-01 13:10:40 -0700930 computeWallpaperScrollRatio(whichPage);
Adam Cohenbeff8c62011-08-31 17:46:01 -0700931 }
932
Winson Chungf0c6ae02012-03-21 16:10:31 -0700933 @Override
934 protected void snapToPage(int whichPage, int duration) {
935 super.snapToPage(whichPage, duration);
936 computeWallpaperScrollRatio(whichPage);
937 }
938
939 protected void snapToPage(int whichPage, Runnable r) {
940 if (mDelayedSnapToPageRunnable != null) {
941 mDelayedSnapToPageRunnable.run();
942 }
943 mDelayedSnapToPageRunnable = r;
944 snapToPage(whichPage, SLOW_PAGE_SNAP_ANIMATION_DURATION);
945 }
946
Adam Cohen5037a0b2011-09-01 13:10:40 -0700947 private void computeWallpaperScrollRatio(int page) {
Adam Cohenbeff8c62011-08-31 17:46:01 -0700948 // Here, we determine what the desired scroll would be with and without a layout scale,
949 // and compute a ratio between the two. This allows us to adjust the wallpaper offset
950 // as though there is no layout scale.
951 float layoutScale = mLayoutScale;
Adam Cohen5037a0b2011-09-01 13:10:40 -0700952 int scaled = getChildOffset(page) - getRelativeChildOffset(page);
Adam Cohenbeff8c62011-08-31 17:46:01 -0700953 mLayoutScale = 1.0f;
Adam Cohen5037a0b2011-09-01 13:10:40 -0700954 float unscaled = getChildOffset(page) - getRelativeChildOffset(page);
Adam Cohenbeff8c62011-08-31 17:46:01 -0700955 mLayoutScale = layoutScale;
956 if (scaled > 0) {
957 mWallpaperScrollRatio = (1.0f * unscaled) / scaled;
958 } else {
959 mWallpaperScrollRatio = 1f;
960 }
961 }
962
Michael Jurkaab1983f2011-01-18 15:50:17 -0800963 class WallpaperOffsetInterpolator {
964 float mFinalHorizontalWallpaperOffset = 0.0f;
965 float mFinalVerticalWallpaperOffset = 0.5f;
966 float mHorizontalWallpaperOffset = 0.0f;
967 float mVerticalWallpaperOffset = 0.5f;
968 long mLastWallpaperOffsetUpdateTime;
Michael Jurkaca5b8362011-01-27 13:23:26 -0800969 boolean mIsMovingFast;
970 boolean mOverrideHorizontalCatchupConstant;
971 float mHorizontalCatchupConstant = 0.35f;
972 float mVerticalCatchupConstant = 0.35f;
Michael Jurkaab1983f2011-01-18 15:50:17 -0800973
974 public WallpaperOffsetInterpolator() {
975 }
976
Michael Jurkaca5b8362011-01-27 13:23:26 -0800977 public void setOverrideHorizontalCatchupConstant(boolean override) {
978 mOverrideHorizontalCatchupConstant = override;
979 }
980
981 public void setHorizontalCatchupConstant(float f) {
982 mHorizontalCatchupConstant = f;
983 }
984
985 public void setVerticalCatchupConstant(float f) {
986 mVerticalCatchupConstant = f;
987 }
988
Michael Jurkaab1983f2011-01-18 15:50:17 -0800989 public boolean computeScrollOffset() {
990 if (Float.compare(mHorizontalWallpaperOffset, mFinalHorizontalWallpaperOffset) == 0 &&
991 Float.compare(mVerticalWallpaperOffset, mFinalVerticalWallpaperOffset) == 0) {
Michael Jurkaca5b8362011-01-27 13:23:26 -0800992 mIsMovingFast = false;
Michael Jurkaab1983f2011-01-18 15:50:17 -0800993 return false;
994 }
Michael Jurka84f2ce72012-04-13 15:08:01 -0700995 boolean isLandscape = mDisplaySize.x > mDisplaySize.y;
Michael Jurkaab1983f2011-01-18 15:50:17 -0800996
997 long currentTime = System.currentTimeMillis();
998 long timeSinceLastUpdate = currentTime - mLastWallpaperOffsetUpdateTime;
999 timeSinceLastUpdate = Math.min((long) (1000/30f), timeSinceLastUpdate);
1000 timeSinceLastUpdate = Math.max(1L, timeSinceLastUpdate);
Michael Jurkaca5b8362011-01-27 13:23:26 -08001001
1002 float xdiff = Math.abs(mFinalHorizontalWallpaperOffset - mHorizontalWallpaperOffset);
1003 if (!mIsMovingFast && xdiff > 0.07) {
1004 mIsMovingFast = true;
1005 }
1006
1007 float fractionToCatchUpIn1MsHorizontal;
1008 if (mOverrideHorizontalCatchupConstant) {
1009 fractionToCatchUpIn1MsHorizontal = mHorizontalCatchupConstant;
1010 } else if (mIsMovingFast) {
1011 fractionToCatchUpIn1MsHorizontal = isLandscape ? 0.5f : 0.75f;
1012 } else {
1013 // slow
1014 fractionToCatchUpIn1MsHorizontal = isLandscape ? 0.27f : 0.5f;
1015 }
1016 float fractionToCatchUpIn1MsVertical = mVerticalCatchupConstant;
1017
Michael Jurkaca5b8362011-01-27 13:23:26 -08001018 fractionToCatchUpIn1MsHorizontal /= 33f;
1019 fractionToCatchUpIn1MsVertical /= 33f;
Michael Jurkaab1983f2011-01-18 15:50:17 -08001020
1021 final float UPDATE_THRESHOLD = 0.00001f;
1022 float hOffsetDelta = mFinalHorizontalWallpaperOffset - mHorizontalWallpaperOffset;
1023 float vOffsetDelta = mFinalVerticalWallpaperOffset - mVerticalWallpaperOffset;
Michael Jurkaca5b8362011-01-27 13:23:26 -08001024 boolean jumpToFinalValue = Math.abs(hOffsetDelta) < UPDATE_THRESHOLD &&
1025 Math.abs(vOffsetDelta) < UPDATE_THRESHOLD;
Michael Jurkaa6471802011-09-22 14:39:16 -07001026
1027 // Don't have any lag between workspace and wallpaper on non-large devices
1028 if (!LauncherApplication.isScreenLarge() || jumpToFinalValue) {
Michael Jurkaab1983f2011-01-18 15:50:17 -08001029 mHorizontalWallpaperOffset = mFinalHorizontalWallpaperOffset;
1030 mVerticalWallpaperOffset = mFinalVerticalWallpaperOffset;
1031 } else {
1032 float percentToCatchUpVertical =
Michael Jurkaca5b8362011-01-27 13:23:26 -08001033 Math.min(1.0f, timeSinceLastUpdate * fractionToCatchUpIn1MsVertical);
Michael Jurkaab1983f2011-01-18 15:50:17 -08001034 float percentToCatchUpHorizontal =
Michael Jurkaca5b8362011-01-27 13:23:26 -08001035 Math.min(1.0f, timeSinceLastUpdate * fractionToCatchUpIn1MsHorizontal);
Michael Jurkaab1983f2011-01-18 15:50:17 -08001036 mHorizontalWallpaperOffset += percentToCatchUpHorizontal * hOffsetDelta;
1037 mVerticalWallpaperOffset += percentToCatchUpVertical * vOffsetDelta;
1038 }
Michael Jurkaca5b8362011-01-27 13:23:26 -08001039
Michael Jurkaab1983f2011-01-18 15:50:17 -08001040 mLastWallpaperOffsetUpdateTime = System.currentTimeMillis();
1041 return true;
1042 }
1043
1044 public float getCurrX() {
1045 return mHorizontalWallpaperOffset;
1046 }
1047
1048 public float getFinalX() {
1049 return mFinalHorizontalWallpaperOffset;
1050 }
1051
1052 public float getCurrY() {
1053 return mVerticalWallpaperOffset;
1054 }
1055
1056 public float getFinalY() {
1057 return mFinalVerticalWallpaperOffset;
1058 }
1059
1060 public void setFinalX(float x) {
1061 mFinalHorizontalWallpaperOffset = Math.max(0f, Math.min(x, 1.0f));
1062 }
1063
1064 public void setFinalY(float y) {
1065 mFinalVerticalWallpaperOffset = Math.max(0f, Math.min(y, 1.0f));
1066 }
1067
1068 public void jumpToFinal() {
1069 mHorizontalWallpaperOffset = mFinalHorizontalWallpaperOffset;
1070 mVerticalWallpaperOffset = mFinalVerticalWallpaperOffset;
1071 }
Dianne Hackborn8f573952009-08-10 23:21:09 -07001072 }
Winson Chungaafa03c2010-06-11 17:34:16 -07001073
Michael Jurka340c5f32010-10-21 16:49:19 -07001074 @Override
1075 public void computeScroll() {
1076 super.computeScroll();
Adam Cohenbeff8c62011-08-31 17:46:01 -07001077 syncWallpaperOffsetWithScroll();
Michael Jurka340c5f32010-10-21 16:49:19 -07001078 }
1079
Patrick Dubroy94f78a52011-02-28 17:39:16 -08001080 void showOutlines() {
Michael Jurkad74c9842011-07-10 12:44:21 -07001081 if (!isSmall() && !mIsSwitchingState) {
Winson Chung9171e6d2010-11-17 17:39:27 -08001082 if (mChildrenOutlineFadeOutAnimation != null) mChildrenOutlineFadeOutAnimation.cancel();
1083 if (mChildrenOutlineFadeInAnimation != null) mChildrenOutlineFadeInAnimation.cancel();
Michael Jurka2ecf9952012-06-18 12:52:28 -07001084 mChildrenOutlineFadeInAnimation = LauncherAnimUtils.ofFloat(this, "childrenOutlineAlpha", 1.0f);
Winson Chung9171e6d2010-11-17 17:39:27 -08001085 mChildrenOutlineFadeInAnimation.setDuration(CHILDREN_OUTLINE_FADE_IN_DURATION);
1086 mChildrenOutlineFadeInAnimation.start();
Michael Jurka3e7c7632010-10-02 16:01:03 -07001087 }
Adam Cohenf34bab52010-09-30 14:11:56 -07001088 }
1089
Patrick Dubroy94f78a52011-02-28 17:39:16 -08001090 void hideOutlines() {
Michael Jurkad74c9842011-07-10 12:44:21 -07001091 if (!isSmall() && !mIsSwitchingState) {
Winson Chung9171e6d2010-11-17 17:39:27 -08001092 if (mChildrenOutlineFadeInAnimation != null) mChildrenOutlineFadeInAnimation.cancel();
1093 if (mChildrenOutlineFadeOutAnimation != null) mChildrenOutlineFadeOutAnimation.cancel();
Michael Jurka2ecf9952012-06-18 12:52:28 -07001094 mChildrenOutlineFadeOutAnimation = LauncherAnimUtils.ofFloat(this, "childrenOutlineAlpha", 0.0f);
Winson Chung9171e6d2010-11-17 17:39:27 -08001095 mChildrenOutlineFadeOutAnimation.setDuration(CHILDREN_OUTLINE_FADE_OUT_DURATION);
1096 mChildrenOutlineFadeOutAnimation.setStartDelay(CHILDREN_OUTLINE_FADE_OUT_DELAY);
1097 mChildrenOutlineFadeOutAnimation.start();
Michael Jurka3e7c7632010-10-02 16:01:03 -07001098 }
Adam Cohenf34bab52010-09-30 14:11:56 -07001099 }
1100
Patrick Dubroy94f78a52011-02-28 17:39:16 -08001101 public void showOutlinesTemporarily() {
1102 if (!mIsPageMoving && !isTouchActive()) {
1103 snapToPage(mCurrentPage);
1104 }
1105 }
1106
Winson Chung9171e6d2010-11-17 17:39:27 -08001107 public void setChildrenOutlineAlpha(float alpha) {
1108 mChildrenOutlineAlpha = alpha;
Adam Cohenf34bab52010-09-30 14:11:56 -07001109 for (int i = 0; i < getChildCount(); i++) {
1110 CellLayout cl = (CellLayout) getChildAt(i);
1111 cl.setBackgroundAlpha(alpha);
1112 }
1113 }
1114
Winson Chung9171e6d2010-11-17 17:39:27 -08001115 public float getChildrenOutlineAlpha() {
1116 return mChildrenOutlineAlpha;
1117 }
1118
Michael Jurka9c6fbed2011-03-02 17:41:34 -08001119 void disableBackground() {
1120 mDrawBackground = false;
1121 }
1122 void enableBackground() {
1123 mDrawBackground = true;
1124 }
1125
Michael Jurka7bdb25a2011-08-03 15:16:44 -07001126 private void animateBackgroundGradient(float finalAlpha, boolean animated) {
Winson Chungb4b7fa72010-11-18 14:38:53 -08001127 if (mBackground == null) return;
Michael Jurkab9e14972011-07-25 17:57:40 -07001128 if (mBackgroundFadeInAnimation != null) {
1129 mBackgroundFadeInAnimation.cancel();
1130 mBackgroundFadeInAnimation = null;
1131 }
1132 if (mBackgroundFadeOutAnimation != null) {
1133 mBackgroundFadeOutAnimation.cancel();
1134 mBackgroundFadeOutAnimation = null;
1135 }
Michael Jurka7bdb25a2011-08-03 15:16:44 -07001136 float startAlpha = getBackgroundAlpha();
1137 if (finalAlpha != startAlpha) {
1138 if (animated) {
Michael Jurka2ecf9952012-06-18 12:52:28 -07001139 mBackgroundFadeOutAnimation = LauncherAnimUtils.ofFloat(startAlpha, finalAlpha);
Michael Jurka7bdb25a2011-08-03 15:16:44 -07001140 mBackgroundFadeOutAnimation.addUpdateListener(new AnimatorUpdateListener() {
1141 public void onAnimationUpdate(ValueAnimator animation) {
1142 setBackgroundAlpha(((Float) animation.getAnimatedValue()).floatValue());
1143 }
1144 });
1145 mBackgroundFadeOutAnimation.setInterpolator(new DecelerateInterpolator(1.5f));
1146 mBackgroundFadeOutAnimation.setDuration(BACKGROUND_FADE_OUT_DURATION);
1147 mBackgroundFadeOutAnimation.start();
1148 } else {
1149 setBackgroundAlpha(finalAlpha);
1150 }
Michael Jurkab9e14972011-07-25 17:57:40 -07001151 }
Winson Chung9171e6d2010-11-17 17:39:27 -08001152 }
1153
1154 public void setBackgroundAlpha(float alpha) {
Michael Jurka9c6fbed2011-03-02 17:41:34 -08001155 if (alpha != mBackgroundAlpha) {
1156 mBackgroundAlpha = alpha;
1157 invalidate();
1158 }
Winson Chung9171e6d2010-11-17 17:39:27 -08001159 }
1160
Adam Cohenf34bab52010-09-30 14:11:56 -07001161 public float getBackgroundAlpha() {
1162 return mBackgroundAlpha;
1163 }
1164
Adam Cohen68d73932010-11-15 10:50:58 -08001165 float backgroundAlphaInterpolator(float r) {
1166 float pivotA = 0.1f;
1167 float pivotB = 0.4f;
1168 if (r < pivotA) {
1169 return 0;
1170 } else if (r > pivotB) {
1171 return 1.0f;
1172 } else {
1173 return (r - pivotA)/(pivotB - pivotA);
1174 }
1175 }
1176
1177 float overScrollBackgroundAlphaInterpolator(float r) {
Adam Cohene0f66b52010-11-23 15:06:07 -08001178 float threshold = 0.08f;
Adam Cohen68d73932010-11-15 10:50:58 -08001179
1180 if (r > mOverScrollMaxBackgroundAlpha) {
1181 mOverScrollMaxBackgroundAlpha = r;
1182 } else if (r < mOverScrollMaxBackgroundAlpha) {
1183 r = mOverScrollMaxBackgroundAlpha;
1184 }
1185
1186 return Math.min(r / threshold, 1.0f);
1187 }
1188
Michael Jurkaa3d30ad2012-05-08 13:43:43 -07001189 private void updatePageAlphaValues(int screenCenter) {
Michael Jurka869390b2012-05-06 15:55:19 -07001190 boolean isInOverscroll = mOverScrollX < 0 || mOverScrollX > mMaxScrollX;
1191 if (mWorkspaceFadeInAdjacentScreens &&
1192 mState == State.NORMAL &&
1193 !mIsSwitchingState &&
1194 !isInOverscroll) {
1195 for (int i = 0; i < getChildCount(); i++) {
1196 CellLayout child = (CellLayout) getChildAt(i);
1197 if (child != null) {
1198 float scrollProgress = getScrollProgress(screenCenter, child, i);
Adam Cohen73894962011-10-31 13:17:17 -07001199 float alpha = 1 - Math.abs(scrollProgress);
Michael Jurka869390b2012-05-06 15:55:19 -07001200 child.getShortcutsAndWidgets().setAlpha(alpha);
Michael Jurkaa3d30ad2012-05-08 13:43:43 -07001201 if (!mIsDragOccuring) {
1202 child.setBackgroundAlphaMultiplier(
1203 backgroundAlphaInterpolator(Math.abs(scrollProgress)));
1204 } else {
1205 child.setBackgroundAlphaMultiplier(1f);
1206 }
Adam Cohen73894962011-10-31 13:17:17 -07001207 }
Adam Cohenf34bab52010-09-30 14:11:56 -07001208 }
1209 }
Michael Jurkaa3d30ad2012-05-08 13:43:43 -07001210 }
1211
1212 private void setChildrenBackgroundAlphaMultipliers(float a) {
1213 for (int i = 0; i < getChildCount(); i++) {
1214 CellLayout child = (CellLayout) getChildAt(i);
1215 child.setBackgroundAlphaMultiplier(a);
1216 }
1217 }
1218
1219 @Override
1220 protected void screenScrolled(int screenCenter) {
1221 super.screenScrolled(screenCenter);
1222
1223 updatePageAlphaValues(screenCenter);
Michael Jurkad51f33a2012-06-28 15:35:26 -07001224 enableHwLayersOnVisiblePages();
Adam Cohenf34bab52010-09-30 14:11:56 -07001225
Adam Cohenebea84d2011-11-09 17:20:41 -08001226 if (mOverScrollX < 0 || mOverScrollX > mMaxScrollX) {
1227 int index = mOverScrollX < 0 ? 0 : getChildCount() - 1;
Adam Cohenb5ba0972011-09-07 18:02:31 -07001228 CellLayout cl = (CellLayout) getChildAt(index);
1229 float scrollProgress = getScrollProgress(screenCenter, cl, index);
1230 cl.setOverScrollAmount(Math.abs(scrollProgress), index == 0);
Adam Cohenb5ba0972011-09-07 18:02:31 -07001231 float rotation = - WORKSPACE_OVERSCROLL_ROTATION * scrollProgress;
Adam Cohenb5ba0972011-09-07 18:02:31 -07001232 cl.setRotationY(rotation);
Adam Cohen21b41102011-11-01 17:29:52 -07001233 setFadeForOverScroll(Math.abs(scrollProgress));
Michael Jurkab06d95f2012-04-02 06:26:53 -07001234 if (!mOverscrollTransformsSet) {
1235 mOverscrollTransformsSet = true;
Adam Cohen94309882012-06-08 16:24:56 -07001236 cl.setCameraDistance(mDensity * mCameraDistance);
Michael Jurkab06d95f2012-04-02 06:26:53 -07001237 cl.setPivotX(cl.getMeasuredWidth() * (index == 0 ? 0.75f : 0.25f));
1238 cl.setPivotY(cl.getMeasuredHeight() * 0.5f);
1239 cl.setOverscrollTransformsDirty(true);
1240 }
Adam Cohenb5ba0972011-09-07 18:02:31 -07001241 } else {
Adam Cohen21b41102011-11-01 17:29:52 -07001242 if (mOverscrollFade != 0) {
1243 setFadeForOverScroll(0);
1244 }
Michael Jurkab06d95f2012-04-02 06:26:53 -07001245 if (mOverscrollTransformsSet) {
1246 mOverscrollTransformsSet = false;
Adam Cohenebea84d2011-11-09 17:20:41 -08001247 ((CellLayout) getChildAt(0)).resetOverscrollTransforms();
1248 ((CellLayout) getChildAt(getChildCount() - 1)).resetOverscrollTransforms();
Adam Cohen7842d7f2011-09-12 15:28:15 -07001249 }
Adam Cohenb5ba0972011-09-07 18:02:31 -07001250 }
1251 }
1252
1253 @Override
Adam Cohenb5ba0972011-09-07 18:02:31 -07001254 protected void overScroll(float amount) {
Michael Jurka869390b2012-05-06 15:55:19 -07001255 acceleratedOverScroll(amount);
Adam Cohenb5ba0972011-09-07 18:02:31 -07001256 }
1257
Joe Onorato00acb122009-08-04 16:04:30 -04001258 protected void onAttachedToWindow() {
1259 super.onAttachedToWindow();
Michael Jurka9c6fbed2011-03-02 17:41:34 -08001260 mWindowToken = getWindowToken();
Joe Onorato956091b2010-02-19 12:47:40 -08001261 computeScroll();
Michael Jurka9c6fbed2011-03-02 17:41:34 -08001262 mDragController.setWindowToken(mWindowToken);
1263 }
1264
1265 protected void onDetachedFromWindow() {
1266 mWindowToken = null;
Joe Onorato00acb122009-08-04 16:04:30 -04001267 }
1268
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001269 @Override
Michael Jurka28750fb2010-09-24 17:43:49 -07001270 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
Michael Jurkac5b262c2011-01-12 20:24:50 -08001271 if (mFirstLayout && mCurrentPage >= 0 && mCurrentPage < getChildCount()) {
1272 mUpdateWallpaperOffsetImmediately = true;
1273 }
Michael Jurka0142d492010-08-25 17:46:15 -07001274 super.onLayout(changed, left, top, right, bottom);
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001275 }
1276
1277 @Override
Winson Chung9171e6d2010-11-17 17:39:27 -08001278 protected void onDraw(Canvas canvas) {
Michael Jurkaab1983f2011-01-18 15:50:17 -08001279 updateWallpaperOffsets();
Michael Jurkac5b262c2011-01-12 20:24:50 -08001280
Winson Chung9171e6d2010-11-17 17:39:27 -08001281 // Draw the background gradient if necessary
Michael Jurka9c6fbed2011-03-02 17:41:34 -08001282 if (mBackground != null && mBackgroundAlpha > 0.0f && mDrawBackground) {
Winson Chung8d006d52010-11-29 15:55:29 -08001283 int alpha = (int) (mBackgroundAlpha * 255);
Winson Chungf0ea4d32011-06-06 14:27:16 -07001284 mBackground.setAlpha(alpha);
Michael Jurka8b805b12012-04-18 14:23:14 -07001285 mBackground.setBounds(getScrollX(), 0, getScrollX() + getMeasuredWidth(),
Winson Chungf0ea4d32011-06-06 14:27:16 -07001286 getMeasuredHeight());
1287 mBackground.draw(canvas);
Winson Chung9171e6d2010-11-17 17:39:27 -08001288 }
Adam Cohen073a46f2011-05-17 16:28:09 -07001289
Winson Chung9171e6d2010-11-17 17:39:27 -08001290 super.onDraw(canvas);
1291 }
1292
Adam Cohen21b41102011-11-01 17:29:52 -07001293 boolean isDrawingBackgroundGradient() {
1294 return (mBackground != null && mBackgroundAlpha > 0.0f && mDrawBackground);
1295 }
1296
Michael Jurkadfab7f02011-11-18 13:01:04 -08001297 @Override
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001298 protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
Joe Onorato67886212009-09-14 19:05:05 -04001299 if (!mLauncher.isAllAppsVisible()) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001300 final Folder openFolder = getOpenFolder();
1301 if (openFolder != null) {
1302 return openFolder.requestFocus(direction, previouslyFocusedRect);
1303 } else {
Michael Jurka0142d492010-08-25 17:46:15 -07001304 return super.onRequestFocusInDescendants(direction, previouslyFocusedRect);
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001305 }
1306 }
1307 return false;
1308 }
1309
1310 @Override
Winson Chung97d85d22011-04-13 11:27:36 -07001311 public int getDescendantFocusability() {
Michael Jurkad74c9842011-07-10 12:44:21 -07001312 if (isSmall()) {
Winson Chung97d85d22011-04-13 11:27:36 -07001313 return ViewGroup.FOCUS_BLOCK_DESCENDANTS;
1314 }
1315 return super.getDescendantFocusability();
1316 }
1317
1318 @Override
Romain Guyc2e24c02009-06-01 16:11:41 -07001319 public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
Joe Onorato67886212009-09-14 19:05:05 -04001320 if (!mLauncher.isAllAppsVisible()) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001321 final Folder openFolder = getOpenFolder();
Michael Jurka0142d492010-08-25 17:46:15 -07001322 if (openFolder != null) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001323 openFolder.addFocusables(views, direction);
Michael Jurka0142d492010-08-25 17:46:15 -07001324 } else {
1325 super.addFocusables(views, direction, focusableMode);
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001326 }
1327 }
1328 }
1329
Michael Jurkad74c9842011-07-10 12:44:21 -07001330 public boolean isSmall() {
Adam Cohen3384c7b2011-07-17 15:48:21 -07001331 return mState == State.SMALL || mState == State.SPRING_LOADED;
Michael Jurkad74c9842011-07-10 12:44:21 -07001332 }
1333
Michael Jurka0142d492010-08-25 17:46:15 -07001334 void enableChildrenCache(int fromPage, int toPage) {
1335 if (fromPage > toPage) {
1336 final int temp = fromPage;
1337 fromPage = toPage;
1338 toPage = temp;
Mike Cleron3a2b3f22009-11-05 17:17:42 -08001339 }
Winson Chungaafa03c2010-06-11 17:34:16 -07001340
Michael Jurkadee05892010-07-27 10:01:56 -07001341 final int screenCount = getChildCount();
Adam Powellfea5d022010-04-29 11:42:45 -07001342
Michael Jurka0142d492010-08-25 17:46:15 -07001343 fromPage = Math.max(fromPage, 0);
1344 toPage = Math.min(toPage, screenCount - 1);
Adam Powellfea5d022010-04-29 11:42:45 -07001345
Michael Jurka0142d492010-08-25 17:46:15 -07001346 for (int i = fromPage; i <= toPage; i++) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001347 final CellLayout layout = (CellLayout) getChildAt(i);
1348 layout.setChildrenDrawnWithCacheEnabled(true);
1349 layout.setChildrenDrawingCacheEnabled(true);
1350 }
1351 }
1352
1353 void clearChildrenCache() {
Michael Jurkadee05892010-07-27 10:01:56 -07001354 final int screenCount = getChildCount();
1355 for (int i = 0; i < screenCount; i++) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001356 final CellLayout layout = (CellLayout) getChildAt(i);
1357 layout.setChildrenDrawnWithCacheEnabled(false);
Adam Cohen8182e5b2011-08-01 15:43:31 -07001358 // In software mode, we don't want the items to continue to be drawn into bitmaps
1359 if (!isHardwareAccelerated()) {
1360 layout.setChildrenDrawingCacheEnabled(false);
1361 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001362 }
1363 }
1364
Michael Jurka3a0469d2012-06-21 09:38:41 -07001365
1366 private void updateChildrenLayersEnabled(boolean force) {
Adam Cohen19f37922012-03-21 11:59:11 -07001367 boolean small = mState == State.SMALL || mIsSwitchingState;
Michael Jurka3a0469d2012-06-21 09:38:41 -07001368 boolean enableChildrenLayers = force || small || mAnimatingViewIntoPlace || isPageMoving();
Michael Jurkad74c9842011-07-10 12:44:21 -07001369
1370 if (enableChildrenLayers != mChildrenLayersEnabled) {
1371 mChildrenLayersEnabled = enableChildrenLayers;
Michael Jurkad51f33a2012-06-28 15:35:26 -07001372 if (mChildrenLayersEnabled) {
1373 enableHwLayersOnVisiblePages();
1374 } else {
1375 for (int i = 0; i < getPageCount(); i++) {
1376 final CellLayout cl = (CellLayout) getChildAt(i);
1377 cl.disableHardwareLayers();
1378 }
1379 }
1380 }
1381 }
1382
1383 private void enableHwLayersOnVisiblePages() {
1384 if (mChildrenLayersEnabled) {
1385 final int screenCount = getChildCount();
1386 getVisiblePages(mTempVisiblePagesRange);
1387 int leftScreen = mTempVisiblePagesRange[0];
1388 int rightScreen = mTempVisiblePagesRange[1];
1389 if (leftScreen == rightScreen) {
1390 // make sure we're caching at least two pages always
1391 if (rightScreen < screenCount - 1) {
1392 rightScreen++;
1393 } else if (leftScreen > 0) {
1394 leftScreen--;
1395 }
1396 }
1397 for (int i = 0; i < screenCount; i++) {
1398 final CellLayout layout = (CellLayout) getChildAt(i);
1399 if (!(leftScreen <= i && i <= rightScreen && shouldDrawChild(layout))) {
1400 layout.disableHardwareLayers();
1401 }
1402 }
1403 for (int i = 0; i < screenCount; i++) {
1404 final CellLayout layout = (CellLayout) getChildAt(i);
1405 if (leftScreen <= i && i <= rightScreen && shouldDrawChild(layout)) {
1406 layout.enableHardwareLayers();
1407 }
Michael Jurkad74c9842011-07-10 12:44:21 -07001408 }
Michael Jurkace7e05f2011-02-01 22:02:35 -08001409 }
Michael Jurkace7e05f2011-02-01 22:02:35 -08001410 }
1411
Michael Jurka3a0469d2012-06-21 09:38:41 -07001412 public void buildPageHardwareLayers() {
1413 // force layers to be enabled just for the call to buildLayer
1414 updateChildrenLayersEnabled(true);
1415 if (getWindowToken() != null) {
1416 final int childCount = getChildCount();
1417 for (int i = 0; i < childCount; i++) {
1418 CellLayout cl = (CellLayout) getChildAt(i);
Michael Jurkad51f33a2012-06-28 15:35:26 -07001419 cl.buildHardwareLayer();
Michael Jurka3a0469d2012-06-21 09:38:41 -07001420 }
1421 }
1422 updateChildrenLayersEnabled(false);
1423 }
1424
Jeff Brown1d0867c2010-12-02 18:27:39 -08001425 protected void onWallpaperTap(MotionEvent ev) {
1426 final int[] position = mTempCell;
1427 getLocationOnScreen(position);
1428
1429 int pointerIndex = ev.getActionIndex();
1430 position[0] += (int) ev.getX(pointerIndex);
1431 position[1] += (int) ev.getY(pointerIndex);
1432
1433 mWallpaperManager.sendWallpaperCommand(getWindowToken(),
1434 ev.getAction() == MotionEvent.ACTION_UP
1435 ? WallpaperManager.COMMAND_TAP : WallpaperManager.COMMAND_SECONDARY_TAP,
1436 position[0], position[1], 0, null);
1437 }
1438
Adam Cohen61033d32010-11-15 18:29:44 -08001439 /*
1440 * This interpolator emulates the rate at which the perceived scale of an object changes
1441 * as its distance from a camera increases. When this interpolator is applied to a scale
1442 * animation on a view, it evokes the sense that the object is shrinking due to moving away
Andrew Flynn0dca1ec2012-02-29 13:33:22 -08001443 * from the camera.
Adam Cohen61033d32010-11-15 18:29:44 -08001444 */
1445 static class ZInterpolator implements TimeInterpolator {
1446 private float focalLength;
1447
1448 public ZInterpolator(float foc) {
1449 focalLength = foc;
1450 }
1451
Adam Coheneed565d2010-11-15 11:30:05 -08001452 public float getInterpolation(float input) {
1453 return (1.0f - focalLength / (focalLength + input)) /
Adam Cohen61033d32010-11-15 18:29:44 -08001454 (1.0f - focalLength / (focalLength + 1.0f));
Adam Cohencbbaf982010-11-12 14:50:33 -08001455 }
1456 }
1457
Adam Cohen61033d32010-11-15 18:29:44 -08001458 /*
1459 * The exact reverse of ZInterpolator.
1460 */
1461 static class InverseZInterpolator implements TimeInterpolator {
1462 private ZInterpolator zInterpolator;
1463 public InverseZInterpolator(float foc) {
1464 zInterpolator = new ZInterpolator(foc);
1465 }
Adam Cohencbbaf982010-11-12 14:50:33 -08001466 public float getInterpolation(float input) {
Adam Cohen61033d32010-11-15 18:29:44 -08001467 return 1 - zInterpolator.getInterpolation(1 - input);
Adam Cohencbbaf982010-11-12 14:50:33 -08001468 }
1469 }
1470
Adam Cohen61033d32010-11-15 18:29:44 -08001471 /*
1472 * ZInterpolator compounded with an ease-out.
1473 */
1474 static class ZoomOutInterpolator implements TimeInterpolator {
Adam Cohenb64d36e2011-10-17 21:48:02 -07001475 private final DecelerateInterpolator decelerate = new DecelerateInterpolator(0.75f);
1476 private final ZInterpolator zInterpolator = new ZInterpolator(0.13f);
Adam Cohen61033d32010-11-15 18:29:44 -08001477
1478 public float getInterpolation(float input) {
1479 return decelerate.getInterpolation(zInterpolator.getInterpolation(input));
1480 }
1481 }
1482
1483 /*
1484 * InvereZInterpolator compounded with an ease-out.
1485 */
1486 static class ZoomInInterpolator implements TimeInterpolator {
1487 private final InverseZInterpolator inverseZInterpolator = new InverseZInterpolator(0.35f);
1488 private final DecelerateInterpolator decelerate = new DecelerateInterpolator(3.0f);
1489
1490 public float getInterpolation(float input) {
1491 return decelerate.getInterpolation(inverseZInterpolator.getInterpolation(input));
1492 }
1493 }
1494
Adam Cohen61033d32010-11-15 18:29:44 -08001495 private final ZoomInInterpolator mZoomInInterpolator = new ZoomInInterpolator();
Michael Jurka3e7c7632010-10-02 16:01:03 -07001496
Michael Jurka3e7c7632010-10-02 16:01:03 -07001497 /*
Adam Cohen66396872011-04-15 17:50:36 -07001498 *
1499 * We call these methods (onDragStartedWithItemSpans/onDragStartedWithSize) whenever we
1500 * start a drag in Launcher, regardless of whether the drag has ever entered the Workspace
1501 *
1502 * These methods mark the appropriate pages as accepting drops (which alters their visual
1503 * appearance).
1504 *
1505 */
1506 public void onDragStartedWithItem(View v) {
Adam Cohen66396872011-04-15 17:50:36 -07001507 final Canvas canvas = new Canvas();
1508
Adam Cohen66396872011-04-15 17:50:36 -07001509 // The outline is used to visualize where the item will land if dropped
Adam Cohend41fbf52012-02-16 23:53:59 -08001510 mDragOutline = createDragOutline(v, canvas, DRAG_BITMAP_PADDING);
Adam Cohen66396872011-04-15 17:50:36 -07001511 }
1512
Michael Jurka8c3339b2012-06-14 16:18:21 -07001513 public void onDragStartedWithItem(PendingAddItemInfo info, Bitmap b, boolean clipAlpha) {
Michael Jurkad3ef3062010-11-23 16:23:58 -08001514 final Canvas canvas = new Canvas();
1515
Michael Jurka038f9d82011-11-03 13:50:45 -07001516 int[] size = estimateItemSize(info.spanX, info.spanY, info, false);
Adam Cohen66396872011-04-15 17:50:36 -07001517
Michael Jurkad3ef3062010-11-23 16:23:58 -08001518 // The outline is used to visualize where the item will land if dropped
Adam Cohend41fbf52012-02-16 23:53:59 -08001519 mDragOutline = createDragOutline(b, canvas, DRAG_BITMAP_PADDING, size[0],
Michael Jurka8c3339b2012-06-14 16:18:21 -07001520 size[1], clipAlpha);
Michael Jurka3e7c7632010-10-02 16:01:03 -07001521 }
1522
Patrick Dubroy758a9232011-03-03 19:54:56 -08001523 public void exitWidgetResizeMode() {
Adam Cohen716b51e2011-06-30 12:09:54 -07001524 DragLayer dragLayer = mLauncher.getDragLayer();
Adam Cohen67882692011-03-11 15:29:03 -08001525 dragLayer.clearAllResizeFrames();
Patrick Dubroy758a9232011-03-03 19:54:56 -08001526 }
1527
Adam Cohen4b285c52011-07-21 14:24:06 -07001528 private void initAnimationArrays() {
1529 final int childCount = getChildCount();
1530 if (mOldTranslationXs != null) return;
1531 mOldTranslationXs = new float[childCount];
1532 mOldTranslationYs = new float[childCount];
1533 mOldScaleXs = new float[childCount];
1534 mOldScaleYs = new float[childCount];
1535 mOldBackgroundAlphas = new float[childCount];
Adam Cohen4b285c52011-07-21 14:24:06 -07001536 mOldAlphas = new float[childCount];
Adam Cohen4b285c52011-07-21 14:24:06 -07001537 mNewTranslationXs = new float[childCount];
1538 mNewTranslationYs = new float[childCount];
1539 mNewScaleXs = new float[childCount];
1540 mNewScaleYs = new float[childCount];
1541 mNewBackgroundAlphas = new float[childCount];
Adam Cohen4b285c52011-07-21 14:24:06 -07001542 mNewAlphas = new float[childCount];
1543 mNewRotationYs = new float[childCount];
1544 }
1545
Michael Jurka2a4b1a82011-12-07 14:00:02 -08001546 Animator getChangeStateAnimation(final State state, boolean animated) {
1547 return getChangeStateAnimation(state, animated, 0);
Adam Cohen7777d962011-08-18 18:58:38 -07001548 }
1549
Michael Jurka2a4b1a82011-12-07 14:00:02 -08001550 Animator getChangeStateAnimation(final State state, boolean animated, int delay) {
Michael Jurkabdf78552011-10-31 14:34:25 -07001551 if (mState == state) {
Michael Jurka2a4b1a82011-12-07 14:00:02 -08001552 return null;
Michael Jurka99633da2011-07-27 22:40:17 -07001553 }
1554
Winson Chung1b7c1d32011-10-25 12:09:38 -07001555 // Initialize animation arrays for the first time if necessary
1556 initAnimationArrays();
1557
Michael Jurka2ecf9952012-06-18 12:52:28 -07001558 AnimatorSet anim = animated ? LauncherAnimUtils.createAnimatorSet() : null;
Adam Lesinski6b879f02010-11-04 16:15:23 -07001559
Adam Cohen7777d962011-08-18 18:58:38 -07001560 // Stop any scrolling, move to the current page right away
Winson Chung360e63f2012-04-27 13:48:05 -07001561 setCurrentPage(getNextPage());
Winson Chungde1af762011-07-21 16:44:07 -07001562
Winson Chung1b7c1d32011-10-25 12:09:38 -07001563 final State oldState = mState;
1564 final boolean oldStateIsNormal = (oldState == State.NORMAL);
Michael Jurka4ff7d792012-04-02 03:46:50 -07001565 final boolean oldStateIsSpringLoaded = (oldState == State.SPRING_LOADED);
Winson Chung1b7c1d32011-10-25 12:09:38 -07001566 final boolean oldStateIsSmall = (oldState == State.SMALL);
Adam Cohen7777d962011-08-18 18:58:38 -07001567 mState = state;
Winson Chung1b7c1d32011-10-25 12:09:38 -07001568 final boolean stateIsNormal = (state == State.NORMAL);
1569 final boolean stateIsSpringLoaded = (state == State.SPRING_LOADED);
1570 final boolean stateIsSmall = (state == State.SMALL);
1571 float finalScaleFactor = 1.0f;
1572 float finalBackgroundAlpha = stateIsSpringLoaded ? 1.0f : 0f;
1573 float translationX = 0;
1574 float translationY = 0;
Adam Cohen7777d962011-08-18 18:58:38 -07001575 boolean zoomIn = true;
Adam Cohenbeff8c62011-08-31 17:46:01 -07001576
Adam Cohen7777d962011-08-18 18:58:38 -07001577 if (state != State.NORMAL) {
Winson Chung1b7c1d32011-10-25 12:09:38 -07001578 finalScaleFactor = mSpringLoadedShrinkFactor - (stateIsSmall ? 0.1f : 0);
Winson Chung8aad6102012-05-11 16:27:49 -07001579 setPageSpacing(mSpringLoadedPageSpacing);
Winson Chung1b7c1d32011-10-25 12:09:38 -07001580 if (oldStateIsNormal && stateIsSmall) {
Adam Cohen7777d962011-08-18 18:58:38 -07001581 zoomIn = false;
Adam Cohen7777d962011-08-18 18:58:38 -07001582 setLayoutScale(finalScaleFactor);
Michael Jurka3a0469d2012-06-21 09:38:41 -07001583 updateChildrenLayersEnabled(false);
Michael Jurkaca5b8362011-01-27 13:23:26 -08001584 } else {
Adam Cohencff6af82011-09-13 14:51:53 -07001585 finalBackgroundAlpha = 1.0f;
Adam Cohen7777d962011-08-18 18:58:38 -07001586 setLayoutScale(finalScaleFactor);
1587 }
1588 } else {
Winson Chung8aad6102012-05-11 16:27:49 -07001589 setPageSpacing(PagedView.AUTOMATIC_PAGE_SPACING);
Adam Cohen7777d962011-08-18 18:58:38 -07001590 setLayoutScale(1.0f);
Adam Cohen7777d962011-08-18 18:58:38 -07001591 }
1592
Andrew Flynn0dca1ec2012-02-29 13:33:22 -08001593 final int duration = zoomIn ?
Adam Cohen7777d962011-08-18 18:58:38 -07001594 getResources().getInteger(R.integer.config_workspaceUnshrinkTime) :
1595 getResources().getInteger(R.integer.config_appsCustomizeWorkspaceShrinkTime);
Winson Chung1b7c1d32011-10-25 12:09:38 -07001596 for (int i = 0; i < getChildCount(); i++) {
1597 final CellLayout cl = (CellLayout) getChildAt(i);
Michael Jurka869390b2012-05-06 15:55:19 -07001598 float finalAlpha = (!mWorkspaceFadeInAdjacentScreens || stateIsSpringLoaded ||
Winson Chung1b7c1d32011-10-25 12:09:38 -07001599 (i == mCurrentPage)) ? 1f : 0f;
Michael Jurka869390b2012-05-06 15:55:19 -07001600 float currentAlpha = cl.getShortcutsAndWidgets().getAlpha();
1601 float initialAlpha = currentAlpha;
Adam Cohen7777d962011-08-18 18:58:38 -07001602
Winson Chung1b7c1d32011-10-25 12:09:38 -07001603 // Determine the pages alpha during the state transition
1604 if ((oldStateIsSmall && stateIsNormal) ||
1605 (oldStateIsNormal && stateIsSmall)) {
1606 // To/from workspace - only show the current page unless the transition is not
Michael Jurka4ff7d792012-04-02 03:46:50 -07001607 // animated and the animation end callback below doesn't run;
1608 // or, if we're in spring-loaded mode
1609 if (i == mCurrentPage || !animated || oldStateIsSpringLoaded) {
Winson Chung1b7c1d32011-10-25 12:09:38 -07001610 finalAlpha = 1f;
Winson Chung1b7c1d32011-10-25 12:09:38 -07001611 } else {
1612 initialAlpha = 0f;
1613 finalAlpha = 0f;
1614 }
Adam Cohen7777d962011-08-18 18:58:38 -07001615 }
1616
Winson Chung1b7c1d32011-10-25 12:09:38 -07001617 mOldAlphas[i] = initialAlpha;
1618 mNewAlphas[i] = finalAlpha;
Adam Cohen7777d962011-08-18 18:58:38 -07001619 if (animated) {
1620 mOldTranslationXs[i] = cl.getTranslationX();
1621 mOldTranslationYs[i] = cl.getTranslationY();
1622 mOldScaleXs[i] = cl.getScaleX();
1623 mOldScaleYs[i] = cl.getScaleY();
1624 mOldBackgroundAlphas[i] = cl.getBackgroundAlpha();
Adam Cohen7777d962011-08-18 18:58:38 -07001625
1626 mNewTranslationXs[i] = translationX;
1627 mNewTranslationYs[i] = translationY;
1628 mNewScaleXs[i] = finalScaleFactor;
1629 mNewScaleYs[i] = finalScaleFactor;
1630 mNewBackgroundAlphas[i] = finalBackgroundAlpha;
Adam Cohen7777d962011-08-18 18:58:38 -07001631 } else {
1632 cl.setTranslationX(translationX);
1633 cl.setTranslationY(translationY);
1634 cl.setScaleX(finalScaleFactor);
1635 cl.setScaleY(finalScaleFactor);
Winson Chung1b7c1d32011-10-25 12:09:38 -07001636 cl.setBackgroundAlpha(finalBackgroundAlpha);
Michael Jurkaa52570f2012-03-20 03:18:20 -07001637 cl.setShortcutAndWidgetAlpha(finalAlpha);
Adam Cohen7777d962011-08-18 18:58:38 -07001638 }
Michael Jurkadee05892010-07-27 10:01:56 -07001639 }
Winson Chung8d006d52010-11-29 15:55:29 -08001640
Adam Cohen7777d962011-08-18 18:58:38 -07001641 if (animated) {
Michael Jurka7407d2a2011-12-12 21:48:38 -08001642 for (int index = 0; index < getChildCount(); index++) {
1643 final int i = index;
1644 final CellLayout cl = (CellLayout) getChildAt(i);
Michael Jurka869390b2012-05-06 15:55:19 -07001645 float currentAlpha = cl.getShortcutsAndWidgets().getAlpha();
Michael Jurka2a4b1a82011-12-07 14:00:02 -08001646 if (mOldAlphas[i] == 0 && mNewAlphas[i] == 0) {
Michael Jurka7372c592012-01-16 04:21:35 -08001647 cl.setTranslationX(mNewTranslationXs[i]);
1648 cl.setTranslationY(mNewTranslationYs[i]);
1649 cl.setScaleX(mNewScaleXs[i]);
1650 cl.setScaleY(mNewScaleYs[i]);
1651 cl.setBackgroundAlpha(mNewBackgroundAlphas[i]);
Michael Jurkaa52570f2012-03-20 03:18:20 -07001652 cl.setShortcutAndWidgetAlpha(mNewAlphas[i]);
Michael Jurka7372c592012-01-16 04:21:35 -08001653 cl.setRotationY(mNewRotationYs[i]);
Michael Jurka7407d2a2011-12-12 21:48:38 -08001654 } else {
1655 LauncherViewPropertyAnimator a = new LauncherViewPropertyAnimator(cl);
1656 a.translationX(mNewTranslationXs[i])
1657 .translationY(mNewTranslationYs[i])
1658 .scaleX(mNewScaleXs[i])
1659 .scaleY(mNewScaleYs[i])
1660 .setDuration(duration)
1661 .setInterpolator(mZoomInInterpolator);
Michael Jurka7407d2a2011-12-12 21:48:38 -08001662 anim.play(a);
Michael Jurkaa52570f2012-03-20 03:18:20 -07001663
Michael Jurka869390b2012-05-06 15:55:19 -07001664 if (mOldAlphas[i] != mNewAlphas[i] || currentAlpha != mNewAlphas[i]) {
Michael Jurka6c8a5792012-03-22 05:24:37 -07001665 LauncherViewPropertyAnimator alphaAnim =
1666 new LauncherViewPropertyAnimator(cl.getShortcutsAndWidgets());
Michael Jurkaa52570f2012-03-20 03:18:20 -07001667 alphaAnim.alpha(mNewAlphas[i])
1668 .setDuration(duration)
1669 .setInterpolator(mZoomInInterpolator);
1670 anim.play(alphaAnim);
1671 }
Michael Jurka7407d2a2011-12-12 21:48:38 -08001672 if (mOldBackgroundAlphas[i] != 0 ||
Michael Jurka869390b2012-05-06 15:55:19 -07001673 mNewBackgroundAlphas[i] != 0) {
Michael Jurka2ecf9952012-06-18 12:52:28 -07001674 ValueAnimator bgAnim = LauncherAnimUtils.ofFloat(0f, 1f).setDuration(duration);
Michael Jurka7407d2a2011-12-12 21:48:38 -08001675 bgAnim.setInterpolator(mZoomInInterpolator);
1676 bgAnim.addUpdateListener(new LauncherAnimatorUpdateListener() {
1677 public void onAnimationUpdate(float a, float b) {
Michael Jurka7372c592012-01-16 04:21:35 -08001678 cl.setBackgroundAlpha(
Michael Jurka7407d2a2011-12-12 21:48:38 -08001679 a * mOldBackgroundAlphas[i] +
1680 b * mNewBackgroundAlphas[i]);
Michael Jurka7407d2a2011-12-12 21:48:38 -08001681 }
1682 });
1683 anim.play(bgAnim);
1684 }
Michael Jurka2a4b1a82011-12-07 14:00:02 -08001685 }
1686 }
Michael Jurkab99d1af2012-04-25 17:28:27 -07001687 buildPageHardwareLayers();
Michael Jurka2a4b1a82011-12-07 14:00:02 -08001688 anim.setStartDelay(delay);
Adam Cohen7777d962011-08-18 18:58:38 -07001689 }
1690
Winson Chung1b7c1d32011-10-25 12:09:38 -07001691 if (stateIsSpringLoaded) {
Michael Jurka7bdb25a2011-08-03 15:16:44 -07001692 // Right now we're covered by Apps Customize
1693 // Show the background gradient immediately, so the gradient will
1694 // be showing once AppsCustomize disappears
1695 animateBackgroundGradient(getResources().getInteger(
1696 R.integer.config_appsCustomizeSpringLoadedBgAlpha) / 100f, false);
1697 } else {
1698 // Fade the background gradient away
1699 animateBackgroundGradient(0f, true);
1700 }
Michael Jurka2a4b1a82011-12-07 14:00:02 -08001701 return anim;
Michael Jurkadee05892010-07-27 10:01:56 -07001702 }
1703
Michael Jurkabed61d22012-02-14 22:51:29 -08001704 @Override
Michael Jurkaa35e35a2012-04-26 15:04:28 -07001705 public void onLauncherTransitionPrepare(Launcher l, boolean animated, boolean toWorkspace) {
Michael Jurkabed61d22012-02-14 22:51:29 -08001706 mIsSwitchingState = true;
Michael Jurka72db6d72012-03-23 08:06:02 -07001707 cancelScrollingIndicatorAnimations();
Michael Jurkabed61d22012-02-14 22:51:29 -08001708 }
1709
1710 @Override
Michael Jurkaa35e35a2012-04-26 15:04:28 -07001711 public void onLauncherTransitionStart(Launcher l, boolean animated, boolean toWorkspace) {
1712 }
1713
1714 @Override
Winson Chung70442722012-02-10 15:43:22 -08001715 public void onLauncherTransitionStep(Launcher l, float t) {
1716 mTransitionProgress = t;
1717 }
1718
1719 @Override
Michael Jurkabed61d22012-02-14 22:51:29 -08001720 public void onLauncherTransitionEnd(Launcher l, boolean animated, boolean toWorkspace) {
1721 mIsSwitchingState = false;
1722 mWallpaperOffset.setOverrideHorizontalCatchupConstant(false);
Michael Jurka3a0469d2012-06-21 09:38:41 -07001723 updateChildrenLayersEnabled(false);
Michael Jurkabed61d22012-02-14 22:51:29 -08001724 // The code in getChangeStateAnimation to determine initialAlpha and finalAlpha will ensure
1725 // ensure that only the current page is visible during (and subsequently, after) the
1726 // transition animation. If fade adjacent pages is disabled, then re-enable the page
1727 // visibility after the transition animation.
Michael Jurka869390b2012-05-06 15:55:19 -07001728 if (!mWorkspaceFadeInAdjacentScreens) {
Michael Jurkabed61d22012-02-14 22:51:29 -08001729 for (int i = 0; i < getChildCount(); i++) {
1730 final CellLayout cl = (CellLayout) getChildAt(i);
Michael Jurkaa52570f2012-03-20 03:18:20 -07001731 cl.setShortcutAndWidgetAlpha(1f);
Michael Jurkabed61d22012-02-14 22:51:29 -08001732 }
1733 }
1734 }
1735
1736 @Override
1737 public View getContent() {
1738 return this;
1739 }
1740
Joe Onorato4be866d2010-10-10 11:26:02 -07001741 /**
1742 * Draw the View v into the given Canvas.
1743 *
1744 * @param v the view to draw
1745 * @param destCanvas the canvas to draw on
1746 * @param padding the horizontal and vertical padding to use when drawing
1747 */
Adam Cohenac8c8762011-07-13 11:15:27 -07001748 private void drawDragView(View v, Canvas destCanvas, int padding, boolean pruneToDrawable) {
Joe Onorato4be866d2010-10-10 11:26:02 -07001749 final Rect clipRect = mTempRect;
1750 v.getDrawingRect(clipRect);
1751
Adam Cohen099f60d2011-08-23 21:07:26 -07001752 boolean textVisible = false;
1753
Adam Cohenac8c8762011-07-13 11:15:27 -07001754 destCanvas.save();
1755 if (v instanceof TextView && pruneToDrawable) {
1756 Drawable d = ((TextView) v).getCompoundDrawables()[1];
1757 clipRect.set(0, 0, d.getIntrinsicWidth() + padding, d.getIntrinsicHeight() + padding);
1758 destCanvas.translate(padding / 2, padding / 2);
1759 d.draw(destCanvas);
1760 } else {
1761 if (v instanceof FolderIcon) {
Adam Cohen099f60d2011-08-23 21:07:26 -07001762 // For FolderIcons the text can bleed into the icon area, and so we need to
1763 // hide the text completely (which can't be achieved by clipping).
1764 if (((FolderIcon) v).getTextVisible()) {
1765 ((FolderIcon) v).setTextVisible(false);
1766 textVisible = true;
1767 }
Adam Cohenac8c8762011-07-13 11:15:27 -07001768 } else if (v instanceof BubbleTextView) {
1769 final BubbleTextView tv = (BubbleTextView) v;
1770 clipRect.bottom = tv.getExtendedPaddingTop() - (int) BubbleTextView.PADDING_V +
1771 tv.getLayout().getLineTop(0);
1772 } else if (v instanceof TextView) {
1773 final TextView tv = (TextView) v;
1774 clipRect.bottom = tv.getExtendedPaddingTop() - tv.getCompoundDrawablePadding() +
1775 tv.getLayout().getLineTop(0);
1776 }
1777 destCanvas.translate(-v.getScrollX() + padding / 2, -v.getScrollY() + padding / 2);
1778 destCanvas.clipRect(clipRect, Op.REPLACE);
1779 v.draw(destCanvas);
Adam Cohen099f60d2011-08-23 21:07:26 -07001780
1781 // Restore text visibility of FolderIcon if necessary
1782 if (textVisible) {
1783 ((FolderIcon) v).setTextVisible(true);
1784 }
Adam Cohenac8c8762011-07-13 11:15:27 -07001785 }
1786 destCanvas.restore();
1787 }
1788
1789 /**
1790 * Returns a new bitmap to show when the given View is being dragged around.
1791 * Responsibility for the bitmap is transferred to the caller.
1792 */
1793 public Bitmap createDragBitmap(View v, Canvas canvas, int padding) {
Adam Cohenac8c8762011-07-13 11:15:27 -07001794 Bitmap b;
1795
1796 if (v instanceof TextView) {
1797 Drawable d = ((TextView) v).getCompoundDrawables()[1];
1798 b = Bitmap.createBitmap(d.getIntrinsicWidth() + padding,
1799 d.getIntrinsicHeight() + padding, Bitmap.Config.ARGB_8888);
1800 } else {
1801 b = Bitmap.createBitmap(
1802 v.getWidth() + padding, v.getHeight() + padding, Bitmap.Config.ARGB_8888);
Joe Onorato4be866d2010-10-10 11:26:02 -07001803 }
1804
Adam Cohenac8c8762011-07-13 11:15:27 -07001805 canvas.setBitmap(b);
1806 drawDragView(v, canvas, padding, true);
Adam Cohenaaf473c2011-08-03 12:02:47 -07001807 canvas.setBitmap(null);
Joe Onorato4be866d2010-10-10 11:26:02 -07001808
Adam Cohenac8c8762011-07-13 11:15:27 -07001809 return b;
Joe Onorato4be866d2010-10-10 11:26:02 -07001810 }
1811
1812 /**
1813 * Returns a new bitmap to be used as the object outline, e.g. to visualize the drop location.
1814 * Responsibility for the bitmap is transferred to the caller.
1815 */
1816 private Bitmap createDragOutline(View v, Canvas canvas, int padding) {
Winson Chungea359c62011-08-03 17:06:35 -07001817 final int outlineColor = getResources().getColor(android.R.color.holo_blue_light);
Joe Onorato4be866d2010-10-10 11:26:02 -07001818 final Bitmap b = Bitmap.createBitmap(
1819 v.getWidth() + padding, v.getHeight() + padding, Bitmap.Config.ARGB_8888);
1820
1821 canvas.setBitmap(b);
Winson Chungb8c69f32011-10-19 21:36:08 -07001822 drawDragView(v, canvas, padding, true);
Adam Cohen5bb50bd2010-12-03 11:39:55 -08001823 mOutlineHelper.applyMediumExpensiveOutlineWithBlur(b, canvas, outlineColor, outlineColor);
Adam Cohenaaf473c2011-08-03 12:02:47 -07001824 canvas.setBitmap(null);
Joe Onorato4be866d2010-10-10 11:26:02 -07001825 return b;
1826 }
1827
1828 /**
Michael Jurkad3ef3062010-11-23 16:23:58 -08001829 * Returns a new bitmap to be used as the object outline, e.g. to visualize the drop location.
1830 * Responsibility for the bitmap is transferred to the caller.
1831 */
Peter Ng8db70002011-10-25 15:40:08 -07001832 private Bitmap createDragOutline(Bitmap orig, Canvas canvas, int padding, int w, int h,
Michael Jurka8c3339b2012-06-14 16:18:21 -07001833 boolean clipAlpha) {
Winson Chungea359c62011-08-03 17:06:35 -07001834 final int outlineColor = getResources().getColor(android.R.color.holo_blue_light);
Michael Jurkaf12c75c2011-01-25 22:41:40 -08001835 final Bitmap b = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
Michael Jurkad3ef3062010-11-23 16:23:58 -08001836 canvas.setBitmap(b);
Michael Jurkaf12c75c2011-01-25 22:41:40 -08001837
1838 Rect src = new Rect(0, 0, orig.getWidth(), orig.getHeight());
1839 float scaleFactor = Math.min((w - padding) / (float) orig.getWidth(),
1840 (h - padding) / (float) orig.getHeight());
1841 int scaledWidth = (int) (scaleFactor * orig.getWidth());
1842 int scaledHeight = (int) (scaleFactor * orig.getHeight());
1843 Rect dst = new Rect(0, 0, scaledWidth, scaledHeight);
1844
1845 // center the image
1846 dst.offset((w - scaledWidth) / 2, (h - scaledHeight) / 2);
1847
Winson Chung1120e032011-11-22 16:11:31 -08001848 canvas.drawBitmap(orig, src, dst, null);
Peter Ng8db70002011-10-25 15:40:08 -07001849 mOutlineHelper.applyMediumExpensiveOutlineWithBlur(b, canvas, outlineColor, outlineColor,
Michael Jurka8c3339b2012-06-14 16:18:21 -07001850 clipAlpha);
Adam Cohenaaf473c2011-08-03 12:02:47 -07001851 canvas.setBitmap(null);
Michael Jurkad3ef3062010-11-23 16:23:58 -08001852
1853 return b;
1854 }
1855
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001856 void startDrag(CellLayout.CellInfo cellInfo) {
1857 View child = cellInfo.cell;
Winson Chungaafa03c2010-06-11 17:34:16 -07001858
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001859 // Make sure the drag was started by a long press as opposed to a long click.
Bjorn Bringert7984c942009-12-09 15:38:25 +00001860 if (!child.isInTouchMode()) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001861 return;
1862 }
Winson Chungaafa03c2010-06-11 17:34:16 -07001863
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001864 mDragInfo = cellInfo;
Adam Cohend41fbf52012-02-16 23:53:59 -08001865 child.setVisibility(INVISIBLE);
Adam Cohen482ed822012-03-02 14:15:13 -08001866 CellLayout layout = (CellLayout) child.getParent().getParent();
1867 layout.prepareChildForDrag(child);
Joe Onorato4be866d2010-10-10 11:26:02 -07001868
1869 child.clearFocus();
1870 child.setPressed(false);
1871
1872 final Canvas canvas = new Canvas();
1873
1874 // The outline is used to visualize where the item will land if dropped
Adam Cohend41fbf52012-02-16 23:53:59 -08001875 mDragOutline = createDragOutline(child, canvas, DRAG_BITMAP_PADDING);
Adam Cohenac8c8762011-07-13 11:15:27 -07001876 beginDragShared(child, this);
1877 }
1878
1879 public void beginDragShared(View child, DragSource source) {
Winson Chungb8c69f32011-10-19 21:36:08 -07001880 Resources r = getResources();
1881
Joe Onorato4be866d2010-10-10 11:26:02 -07001882 // The drag bitmap follows the touch point around on the screen
Adam Cohend41fbf52012-02-16 23:53:59 -08001883 final Bitmap b = createDragBitmap(child, new Canvas(), DRAG_BITMAP_PADDING);
Joe Onorato4be866d2010-10-10 11:26:02 -07001884
1885 final int bmpWidth = b.getWidth();
Winson Chungeecf02d2012-03-02 17:14:58 -08001886 final int bmpHeight = b.getHeight();
Adam Cohene3e27a82011-04-15 12:07:39 -07001887
Adam Cohen8dfcba42011-07-07 16:38:18 -07001888 mLauncher.getDragLayer().getLocationInDragLayer(child, mTempXY);
Winson Chungeecf02d2012-03-02 17:14:58 -08001889 int dragLayerX =
1890 Math.round(mTempXY[0] - (bmpWidth - child.getScaleX() * child.getWidth()) / 2);
1891 int dragLayerY =
1892 Math.round(mTempXY[1] - (bmpHeight - child.getScaleY() * bmpHeight) / 2
1893 - DRAG_BITMAP_PADDING / 2);
Adam Cohene3e27a82011-04-15 12:07:39 -07001894
Winson Chungb8c69f32011-10-19 21:36:08 -07001895 Point dragVisualizeOffset = null;
Adam Cohene3e27a82011-04-15 12:07:39 -07001896 Rect dragRect = null;
Winson Chungb8c69f32011-10-19 21:36:08 -07001897 if (child instanceof BubbleTextView || child instanceof PagedViewIcon) {
1898 int iconSize = r.getDimensionPixelSize(R.dimen.app_icon_size);
1899 int iconPaddingTop = r.getDimensionPixelSize(R.dimen.app_icon_padding_top);
Adam Cohene3e27a82011-04-15 12:07:39 -07001900 int top = child.getPaddingTop();
1901 int left = (bmpWidth - iconSize) / 2;
1902 int right = left + iconSize;
1903 int bottom = top + iconSize;
Adam Cohenfc53cd22011-07-20 15:45:11 -07001904 dragLayerY += top;
Winson Chungb8c69f32011-10-19 21:36:08 -07001905 // Note: The drag region is used to calculate drag layer offsets, but the
1906 // dragVisualizeOffset in addition to the dragRect (the size) to position the outline.
Adam Cohend41fbf52012-02-16 23:53:59 -08001907 dragVisualizeOffset = new Point(-DRAG_BITMAP_PADDING / 2,
1908 iconPaddingTop - DRAG_BITMAP_PADDING / 2);
Adam Cohene3e27a82011-04-15 12:07:39 -07001909 dragRect = new Rect(left, top, right, bottom);
Adam Cohen0e4857c2011-06-30 17:05:14 -07001910 } else if (child instanceof FolderIcon) {
Winson Chungb8c69f32011-10-19 21:36:08 -07001911 int previewSize = r.getDimensionPixelSize(R.dimen.folder_preview_size);
Adam Cohen0e4857c2011-06-30 17:05:14 -07001912 dragRect = new Rect(0, 0, child.getWidth(), previewSize);
Adam Cohene3e27a82011-04-15 12:07:39 -07001913 }
1914
Winson Chung1e9cbfe2011-09-30 16:52:26 -07001915 // Clear the pressed state if necessary
1916 if (child instanceof BubbleTextView) {
1917 BubbleTextView icon = (BubbleTextView) child;
1918 icon.clearPressedOrFocusedBackground();
1919 }
1920
Adam Cohenac8c8762011-07-13 11:15:27 -07001921 mDragController.startDrag(b, dragLayerX, dragLayerY, source, child.getTag(),
Winson Chungeecf02d2012-03-02 17:14:58 -08001922 DragController.DRAG_ACTION_MOVE, dragVisualizeOffset, dragRect, child.getScaleX());
Joe Onorato4be866d2010-10-10 11:26:02 -07001923 b.recycle();
Winson Chung1afedc32012-01-23 16:14:56 -08001924
1925 // Show the scrolling indicator when you pick up an item
1926 showScrollingIndicator(false);
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001927 }
1928
Winson Chung3d503fb2011-07-13 17:25:49 -07001929 void addApplicationShortcut(ShortcutInfo info, CellLayout target, long container, int screen,
1930 int cellX, int cellY, boolean insertAtFirst, int intersectX, int intersectY) {
1931 View view = mLauncher.createShortcut(R.layout.application, target, (ShortcutInfo) info);
Michael Jurka0280c3b2010-09-17 15:00:07 -07001932
1933 final int[] cellXY = new int[2];
Winson Chung3d503fb2011-07-13 17:25:49 -07001934 target.findCellForSpanThatIntersects(cellXY, 1, 1, intersectX, intersectY);
1935 addInScreen(view, container, screen, cellXY[0], cellXY[1], 1, 1, insertAtFirst);
1936 LauncherModel.addOrMoveItemInDatabase(mLauncher, info, container, screen, cellXY[0],
1937 cellXY[1]);
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001938 }
1939
Adam Cohen4b285c52011-07-21 14:24:06 -07001940 public boolean transitionStateShouldAllowDrop() {
Adam Cohen1b36dc32012-02-13 19:27:37 -08001941 return ((!isSwitchingState() || mTransitionProgress > 0.5f) && mState != State.SMALL);
Adam Cohen4b285c52011-07-21 14:24:06 -07001942 }
1943
Patrick Dubroycd68ff52010-10-28 17:57:05 -07001944 /**
1945 * {@inheritDoc}
1946 */
Adam Cohencb3382b2011-05-24 14:07:08 -07001947 public boolean acceptDrop(DragObject d) {
Patrick Dubroycd68ff52010-10-28 17:57:05 -07001948 // If it's an external drop (e.g. from All Apps), check if it should be accepted
Adam Cohenc6cc61d2012-04-04 12:47:08 -07001949 CellLayout dropTargetLayout = mDropToLayout;
Adam Cohencb3382b2011-05-24 14:07:08 -07001950 if (d.dragSource != this) {
Patrick Dubroycd68ff52010-10-28 17:57:05 -07001951 // Don't accept the drop if we're not over a screen at time of drop
Adam Cohenc6cc61d2012-04-04 12:47:08 -07001952 if (dropTargetLayout == null) {
Patrick Dubroycd68ff52010-10-28 17:57:05 -07001953 return false;
1954 }
Adam Cohen4b285c52011-07-21 14:24:06 -07001955 if (!transitionStateShouldAllowDrop()) return false;
Patrick Dubroycd68ff52010-10-28 17:57:05 -07001956
Adam Cohena65beee2011-06-27 21:32:23 -07001957 mDragViewVisualCenter = getDragViewVisualCenter(d.x, d.y, d.xOffset, d.yOffset,
1958 d.dragView, mDragViewVisualCenter);
1959
Adam Cohen2e9f4fb2011-08-30 22:46:55 -07001960 // We want the point to be mapped to the dragTarget.
Adam Cohenc6cc61d2012-04-04 12:47:08 -07001961 if (mLauncher.isHotseatLayout(dropTargetLayout)) {
Adam Cohen2e9f4fb2011-08-30 22:46:55 -07001962 mapPointFromSelfToSibling(mLauncher.getHotseat(), mDragViewVisualCenter);
1963 } else {
Adam Cohenc6cc61d2012-04-04 12:47:08 -07001964 mapPointFromSelfToChild(dropTargetLayout, mDragViewVisualCenter, null);
Adam Cohen2e9f4fb2011-08-30 22:46:55 -07001965 }
1966
Winson Chung557d6ed2011-07-08 15:34:52 -07001967 int spanX = 1;
1968 int spanY = 1;
Winson Chung557d6ed2011-07-08 15:34:52 -07001969 if (mDragInfo != null) {
1970 final CellLayout.CellInfo dragCellInfo = mDragInfo;
1971 spanX = dragCellInfo.spanX;
1972 spanY = dragCellInfo.spanY;
Winson Chung557d6ed2011-07-08 15:34:52 -07001973 } else {
1974 final ItemInfo dragInfo = (ItemInfo) d.dragInfo;
1975 spanX = dragInfo.spanX;
1976 spanY = dragInfo.spanY;
1977 }
Patrick Dubroycd68ff52010-10-28 17:57:05 -07001978
Adam Cohend41fbf52012-02-16 23:53:59 -08001979 int minSpanX = spanX;
1980 int minSpanY = spanY;
1981 if (d.dragInfo instanceof PendingAddWidgetInfo) {
1982 minSpanX = ((PendingAddWidgetInfo) d.dragInfo).minSpanX;
1983 minSpanY = ((PendingAddWidgetInfo) d.dragInfo).minSpanY;
1984 }
Adam Cohen482ed822012-03-02 14:15:13 -08001985
Adam Cohena65beee2011-06-27 21:32:23 -07001986 mTargetCell = findNearestArea((int) mDragViewVisualCenter[0],
Adam Cohenc6cc61d2012-04-04 12:47:08 -07001987 (int) mDragViewVisualCenter[1], minSpanX, minSpanY, dropTargetLayout,
Adam Cohenf0777b92012-02-28 14:02:45 -08001988 mTargetCell);
Adam Cohenc6cc61d2012-04-04 12:47:08 -07001989 float distance = dropTargetLayout.getDistanceFromCell(mDragViewVisualCenter[0],
Adam Cohen482ed822012-03-02 14:15:13 -08001990 mDragViewVisualCenter[1], mTargetCell);
Adam Cohenc6cc61d2012-04-04 12:47:08 -07001991 if (willCreateUserFolder((ItemInfo) d.dragInfo, dropTargetLayout,
Adam Cohen482ed822012-03-02 14:15:13 -08001992 mTargetCell, distance, true)) {
Adam Cohena65beee2011-06-27 21:32:23 -07001993 return true;
1994 }
Adam Cohenc6cc61d2012-04-04 12:47:08 -07001995 if (willAddToExistingUserFolder((ItemInfo) d.dragInfo, dropTargetLayout,
Adam Cohen482ed822012-03-02 14:15:13 -08001996 mTargetCell, distance)) {
Adam Cohena65beee2011-06-27 21:32:23 -07001997 return true;
1998 }
1999
Adam Cohen482ed822012-03-02 14:15:13 -08002000 int[] resultSpan = new int[2];
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002001 mTargetCell = dropTargetLayout.createArea((int) mDragViewVisualCenter[0],
Adam Cohen482ed822012-03-02 14:15:13 -08002002 (int) mDragViewVisualCenter[1], minSpanX, minSpanY, spanX, spanY,
2003 null, mTargetCell, resultSpan, CellLayout.MODE_ACCEPT_DROP);
2004 boolean foundCell = mTargetCell[0] >= 0 && mTargetCell[1] >= 0;
2005
Patrick Dubroycd68ff52010-10-28 17:57:05 -07002006 // Don't accept the drop if there's no room for the item
Adam Cohen482ed822012-03-02 14:15:13 -08002007 if (!foundCell) {
Winson Chung96ef4092011-11-22 12:25:14 -08002008 // Don't show the message if we are dropping on the AllApps button and the hotseat
2009 // is full
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002010 boolean isHotseat = mLauncher.isHotseatLayout(dropTargetLayout);
Winson Chung93eef082012-03-23 15:59:27 -07002011 if (mTargetCell != null && isHotseat) {
Winson Chung96ef4092011-11-22 12:25:14 -08002012 Hotseat hotseat = mLauncher.getHotseat();
Andrew Flynn0dca1ec2012-02-29 13:33:22 -08002013 if (hotseat.isAllAppsButtonRank(
Winson Chung96ef4092011-11-22 12:25:14 -08002014 hotseat.getOrderInHotseat(mTargetCell[0], mTargetCell[1]))) {
2015 return false;
2016 }
2017 }
2018
Winson Chung93eef082012-03-23 15:59:27 -07002019 mLauncher.showOutOfSpaceMessage(isHotseat);
Patrick Dubroycd68ff52010-10-28 17:57:05 -07002020 return false;
2021 }
2022 }
2023 return true;
2024 }
2025
Adam Cohen482ed822012-03-02 14:15:13 -08002026 boolean willCreateUserFolder(ItemInfo info, CellLayout target, int[] targetCell, float
2027 distance, boolean considerTimeout) {
2028 if (distance > mMaxDistanceForFolderCreation) return false;
Adam Cohena65beee2011-06-27 21:32:23 -07002029 View dropOverView = target.getChildAt(targetCell[0], targetCell[1]);
2030
Adam Cohen19f37922012-03-21 11:59:11 -07002031 if (dropOverView != null) {
2032 CellLayout.LayoutParams lp = (CellLayout.LayoutParams) dropOverView.getLayoutParams();
2033 if (lp.useTmpCoords && (lp.tmpCellX != lp.cellX || lp.tmpCellY != lp.tmpCellY)) {
2034 return false;
2035 }
2036 }
2037
Winson Chung3d503fb2011-07-13 17:25:49 -07002038 boolean hasntMoved = false;
2039 if (mDragInfo != null) {
Adam Cohen482ed822012-03-02 14:15:13 -08002040 hasntMoved = dropOverView == mDragInfo.cell;
Winson Chung3d503fb2011-07-13 17:25:49 -07002041 }
Adam Cohene0310962011-04-18 16:15:31 -07002042
Adam Cohena65beee2011-06-27 21:32:23 -07002043 if (dropOverView == null || hasntMoved || (considerTimeout && !mCreateUserFolderOnDrop)) {
2044 return false;
2045 }
Adam Cohene0310962011-04-18 16:15:31 -07002046
Adam Cohena65beee2011-06-27 21:32:23 -07002047 boolean aboveShortcut = (dropOverView.getTag() instanceof ShortcutInfo);
Adam Cohene0310962011-04-18 16:15:31 -07002048 boolean willBecomeShortcut =
Adam Cohenc0dcf592011-06-01 15:30:43 -07002049 (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
2050 info.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT);
Adam Cohene0310962011-04-18 16:15:31 -07002051
2052 return (aboveShortcut && willBecomeShortcut);
2053 }
2054
Adam Cohen482ed822012-03-02 14:15:13 -08002055 boolean willAddToExistingUserFolder(Object dragInfo, CellLayout target, int[] targetCell,
2056 float distance) {
2057 if (distance > mMaxDistanceForFolderCreation) return false;
Adam Cohena65beee2011-06-27 21:32:23 -07002058 View dropOverView = target.getChildAt(targetCell[0], targetCell[1]);
Adam Cohen19f37922012-03-21 11:59:11 -07002059
2060 if (dropOverView != null) {
2061 CellLayout.LayoutParams lp = (CellLayout.LayoutParams) dropOverView.getLayoutParams();
2062 if (lp.useTmpCoords && (lp.tmpCellX != lp.cellX || lp.tmpCellY != lp.tmpCellY)) {
2063 return false;
2064 }
2065 }
2066
Adam Cohena65beee2011-06-27 21:32:23 -07002067 if (dropOverView instanceof FolderIcon) {
2068 FolderIcon fi = (FolderIcon) dropOverView;
2069 if (fi.acceptDrop(dragInfo)) {
2070 return true;
2071 }
2072 }
2073 return false;
2074 }
2075
Winson Chung3d503fb2011-07-13 17:25:49 -07002076 boolean createUserFolderIfNecessary(View newView, long container, CellLayout target,
Adam Cohen482ed822012-03-02 14:15:13 -08002077 int[] targetCell, float distance, boolean external, DragView dragView,
2078 Runnable postAnimationRunnable) {
2079 if (distance > mMaxDistanceForFolderCreation) return false;
Adam Cohenc0dcf592011-06-01 15:30:43 -07002080 View v = target.getChildAt(targetCell[0], targetCell[1]);
Adam Cohen19f37922012-03-21 11:59:11 -07002081
Winson Chungec9a0a42011-07-20 20:42:13 -07002082 boolean hasntMoved = false;
2083 if (mDragInfo != null) {
2084 CellLayout cellParent = getParentCellLayoutForView(mDragInfo.cell);
2085 hasntMoved = (mDragInfo.cellX == targetCell[0] &&
2086 mDragInfo.cellY == targetCell[1]) && (cellParent == target);
2087 }
Adam Cohen10b17372011-04-15 14:21:25 -07002088
Adam Cohen19072da2011-05-31 14:30:45 -07002089 if (v == null || hasntMoved || !mCreateUserFolderOnDrop) return false;
2090 mCreateUserFolderOnDrop = false;
Adam Cohenc0dcf592011-06-01 15:30:43 -07002091 final int screen = (targetCell == null) ? mDragInfo.screen : indexOfChild(target);
Adam Cohen10b17372011-04-15 14:21:25 -07002092
2093 boolean aboveShortcut = (v.getTag() instanceof ShortcutInfo);
2094 boolean willBecomeShortcut = (newView.getTag() instanceof ShortcutInfo);
2095
2096 if (aboveShortcut && willBecomeShortcut) {
2097 ShortcutInfo sourceInfo = (ShortcutInfo) newView.getTag();
2098 ShortcutInfo destInfo = (ShortcutInfo) v.getTag();
2099 // if the drag started here, we need to remove it from the workspace
2100 if (!external) {
Winson Chung3d503fb2011-07-13 17:25:49 -07002101 getParentCellLayoutForView(mDragInfo.cell).removeView(mDragInfo.cell);
Adam Cohen10b17372011-04-15 14:21:25 -07002102 }
2103
Adam Cohend0445262011-07-04 23:53:22 -07002104 Rect folderLocation = new Rect();
Adam Cohenac8c8762011-07-13 11:15:27 -07002105 float scale = mLauncher.getDragLayer().getDescendantRectRelativeToSelf(v, folderLocation);
Adam Cohen10b17372011-04-15 14:21:25 -07002106 target.removeView(v);
Adam Cohend0445262011-07-04 23:53:22 -07002107
Winson Chung3d503fb2011-07-13 17:25:49 -07002108 FolderIcon fi =
2109 mLauncher.addFolder(target, container, screen, targetCell[0], targetCell[1]);
Adam Cohena9cf38f2011-05-02 15:36:58 -07002110 destInfo.cellX = -1;
2111 destInfo.cellY = -1;
2112 sourceInfo.cellX = -1;
2113 sourceInfo.cellY = -1;
Adam Cohend0445262011-07-04 23:53:22 -07002114
Adam Cohen558baaf2011-08-15 15:22:57 -07002115 // If the dragView is null, we can't animate
2116 boolean animate = dragView != null;
2117 if (animate) {
2118 fi.performCreateAnimation(destInfo, v, sourceInfo, dragView, folderLocation, scale,
2119 postAnimationRunnable);
2120 } else {
2121 fi.addItem(destInfo);
2122 fi.addItem(sourceInfo);
2123 }
Adam Cohen10b17372011-04-15 14:21:25 -07002124 return true;
2125 }
2126 return false;
2127 }
2128
Adam Cohena65beee2011-06-27 21:32:23 -07002129 boolean addToExistingFolderIfNecessary(View newView, CellLayout target, int[] targetCell,
Adam Cohen482ed822012-03-02 14:15:13 -08002130 float distance, DragObject d, boolean external) {
2131 if (distance > mMaxDistanceForFolderCreation) return false;
2132
Adam Cohena65beee2011-06-27 21:32:23 -07002133 View dropOverView = target.getChildAt(targetCell[0], targetCell[1]);
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002134 if (!mAddToExistingFolderOnDrop) return false;
2135 mAddToExistingFolderOnDrop = false;
Adam Cohen19f37922012-03-21 11:59:11 -07002136
Adam Cohenc0dcf592011-06-01 15:30:43 -07002137 if (dropOverView instanceof FolderIcon) {
2138 FolderIcon fi = (FolderIcon) dropOverView;
Adam Cohen3e8f8112011-07-02 18:03:00 -07002139 if (fi.acceptDrop(d.dragInfo)) {
2140 fi.onDrop(d);
Adam Cohenc0dcf592011-06-01 15:30:43 -07002141
2142 // if the drag started here, we need to remove it from the workspace
2143 if (!external) {
Winson Chung3d503fb2011-07-13 17:25:49 -07002144 getParentCellLayoutForView(mDragInfo.cell).removeView(mDragInfo.cell);
Adam Cohenc0dcf592011-06-01 15:30:43 -07002145 }
2146 return true;
2147 }
2148 }
2149 return false;
2150 }
2151
Adam Cohend41fbf52012-02-16 23:53:59 -08002152 public void onDrop(final DragObject d) {
Adam Cohencb3382b2011-05-24 14:07:08 -07002153 mDragViewVisualCenter = getDragViewVisualCenter(d.x, d.y, d.xOffset, d.yOffset, d.dragView,
Adam Cohene3e27a82011-04-15 12:07:39 -07002154 mDragViewVisualCenter);
2155
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002156 CellLayout dropTargetLayout = mDropToLayout;
2157
Adam Cohene3e27a82011-04-15 12:07:39 -07002158 // We want the point to be mapped to the dragTarget.
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002159 if (dropTargetLayout != null) {
2160 if (mLauncher.isHotseatLayout(dropTargetLayout)) {
Winson Chung3d503fb2011-07-13 17:25:49 -07002161 mapPointFromSelfToSibling(mLauncher.getHotseat(), mDragViewVisualCenter);
2162 } else {
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002163 mapPointFromSelfToChild(dropTargetLayout, mDragViewVisualCenter, null);
Winson Chung3d503fb2011-07-13 17:25:49 -07002164 }
Adam Cohenba781612011-05-09 14:37:39 -07002165 }
Michael Jurkac6ee42e2010-09-30 12:04:50 -07002166
Adam Cohened51cc92011-08-01 20:28:08 -07002167 int snapScreen = -1;
Adam Cohend41fbf52012-02-16 23:53:59 -08002168 boolean resizeOnDrop = false;
Adam Cohencb3382b2011-05-24 14:07:08 -07002169 if (d.dragSource != this) {
Adam Cohene3e27a82011-04-15 12:07:39 -07002170 final int[] touchXY = new int[] { (int) mDragViewVisualCenter[0],
2171 (int) mDragViewVisualCenter[1] };
Adam Cohen3e8f8112011-07-02 18:03:00 -07002172 onDropExternal(touchXY, d.dragInfo, dropTargetLayout, false, d);
Patrick Dubroyce34a972010-10-19 10:34:32 -07002173 } else if (mDragInfo != null) {
Patrick Dubroyce34a972010-10-19 10:34:32 -07002174 final View cell = mDragInfo.cell;
Patrick Dubroy54fa3b92010-11-17 12:18:45 -08002175
Adam Cohend41fbf52012-02-16 23:53:59 -08002176 Runnable resizeRunnable = null;
Winson Chungea359c62011-08-03 17:06:35 -07002177 if (dropTargetLayout != null) {
Winson Chung3d503fb2011-07-13 17:25:49 -07002178 // Move internally
Winson Chung40e882b2011-07-21 19:01:11 -07002179 boolean hasMovedLayouts = (getParentCellLayoutForView(cell) != dropTargetLayout);
2180 boolean hasMovedIntoHotseat = mLauncher.isHotseatLayout(dropTargetLayout);
2181 long container = hasMovedIntoHotseat ?
Winson Chung3d503fb2011-07-13 17:25:49 -07002182 LauncherSettings.Favorites.CONTAINER_HOTSEAT :
2183 LauncherSettings.Favorites.CONTAINER_DESKTOP;
2184 int screen = (mTargetCell[0] < 0) ?
2185 mDragInfo.screen : indexOfChild(dropTargetLayout);
Adam Cohenc0dcf592011-06-01 15:30:43 -07002186 int spanX = mDragInfo != null ? mDragInfo.spanX : 1;
2187 int spanY = mDragInfo != null ? mDragInfo.spanY : 1;
2188 // First we find the cell nearest to point at which the item is
2189 // dropped, without any consideration to whether there is an item there.
Adam Cohen482ed822012-03-02 14:15:13 -08002190
Adam Cohenc0dcf592011-06-01 15:30:43 -07002191 mTargetCell = findNearestArea((int) mDragViewVisualCenter[0], (int)
2192 mDragViewVisualCenter[1], spanX, spanY, dropTargetLayout, mTargetCell);
Adam Cohen482ed822012-03-02 14:15:13 -08002193 float distance = dropTargetLayout.getDistanceFromCell(mDragViewVisualCenter[0],
2194 mDragViewVisualCenter[1], mTargetCell);
2195
Adam Cohenc0dcf592011-06-01 15:30:43 -07002196 // If the item being dropped is a shortcut and the nearest drop
Adam Cohen76078c42011-06-09 15:06:52 -07002197 // cell also contains a shortcut, then create a folder with the two shortcuts.
Winson Chung1c4cf4a2011-07-29 14:49:10 -07002198 if (!mInScrollArea && createUserFolderIfNecessary(cell, container,
Adam Cohen482ed822012-03-02 14:15:13 -08002199 dropTargetLayout, mTargetCell, distance, false, d.dragView, null)) {
Adam Cohenc0dcf592011-06-01 15:30:43 -07002200 return;
2201 }
2202
Adam Cohen482ed822012-03-02 14:15:13 -08002203 if (addToExistingFolderIfNecessary(cell, dropTargetLayout, mTargetCell,
2204 distance, d, false)) {
Adam Cohendf035382011-04-11 17:22:04 -07002205 return;
2206 }
2207
2208 // Aside from the special case where we're dropping a shortcut onto a shortcut,
2209 // we need to find the nearest cell location that is vacant
Adam Cohend41fbf52012-02-16 23:53:59 -08002210 ItemInfo item = (ItemInfo) d.dragInfo;
2211 int minSpanX = item.spanX;
2212 int minSpanY = item.spanY;
2213 if (item.minSpanX > 0 && item.minSpanY > 0) {
2214 minSpanX = item.minSpanX;
2215 minSpanY = item.minSpanY;
2216 }
Adam Cohen482ed822012-03-02 14:15:13 -08002217
Adam Cohend41fbf52012-02-16 23:53:59 -08002218 int[] resultSpan = new int[2];
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002219 mTargetCell = dropTargetLayout.createArea((int) mDragViewVisualCenter[0],
Adam Cohen482ed822012-03-02 14:15:13 -08002220 (int) mDragViewVisualCenter[1], minSpanX, minSpanY, spanX, spanY, cell,
2221 mTargetCell, resultSpan, CellLayout.MODE_ON_DROP);
2222
Adam Cohend41fbf52012-02-16 23:53:59 -08002223 boolean foundCell = mTargetCell[0] >= 0 && mTargetCell[1] >= 0;
2224 if (foundCell && (resultSpan[0] != item.spanX || resultSpan[1] != item.spanY)) {
2225 resizeOnDrop = true;
2226 item.spanX = resultSpan[0];
2227 item.spanY = resultSpan[1];
Adam Cohen7bdfc972012-05-22 16:50:35 -07002228 AppWidgetHostView awhv = (AppWidgetHostView) cell;
2229 AppWidgetResizeFrame.updateWidgetSizeRanges(awhv, mLauncher, resultSpan[0],
2230 resultSpan[1]);
Adam Cohend41fbf52012-02-16 23:53:59 -08002231 }
Adam Cohendf035382011-04-11 17:22:04 -07002232
Michael Jurka7cfc2822011-08-02 20:19:24 -07002233 if (mCurrentPage != screen && !hasMovedIntoHotseat) {
Adam Cohened51cc92011-08-01 20:28:08 -07002234 snapScreen = screen;
Patrick Dubroy54fa3b92010-11-17 12:18:45 -08002235 snapToPage(screen);
2236 }
2237
Adam Cohend41fbf52012-02-16 23:53:59 -08002238 if (foundCell) {
2239 final ItemInfo info = (ItemInfo) cell.getTag();
Winson Chung40e882b2011-07-21 19:01:11 -07002240 if (hasMovedLayouts) {
Patrick Dubroy94383362010-10-29 15:03:24 -07002241 // Reparent the view
Winson Chung3d503fb2011-07-13 17:25:49 -07002242 getParentCellLayoutForView(cell).removeView(cell);
2243 addInScreen(cell, container, screen, mTargetCell[0], mTargetCell[1],
Adam Cohend41fbf52012-02-16 23:53:59 -08002244 info.spanX, info.spanY);
Patrick Dubroy94383362010-10-29 15:03:24 -07002245 }
2246
2247 // update the item's position after drop
Patrick Dubroy94383362010-10-29 15:03:24 -07002248 CellLayout.LayoutParams lp = (CellLayout.LayoutParams) cell.getLayoutParams();
Adam Cohen19f37922012-03-21 11:59:11 -07002249 lp.cellX = lp.tmpCellX = mTargetCell[0];
2250 lp.cellY = lp.tmpCellY = mTargetCell[1];
Adam Cohend41fbf52012-02-16 23:53:59 -08002251 lp.cellHSpan = item.spanX;
2252 lp.cellVSpan = item.spanY;
Adam Cohen19f37922012-03-21 11:59:11 -07002253 lp.isLockedToGrid = true;
Winson Chung3d503fb2011-07-13 17:25:49 -07002254 cell.setId(LauncherModel.getCellLayoutChildId(container, mDragInfo.screen,
Patrick Dubroy94383362010-10-29 15:03:24 -07002255 mTargetCell[0], mTargetCell[1], mDragInfo.spanX, mDragInfo.spanY));
2256
Winson Chung3d503fb2011-07-13 17:25:49 -07002257 if (container != LauncherSettings.Favorites.CONTAINER_HOTSEAT &&
2258 cell instanceof LauncherAppWidgetHostView) {
Adam Cohend4844c32011-02-18 19:25:06 -08002259 final CellLayout cellLayout = dropTargetLayout;
2260 // We post this call so that the widget has a chance to be placed
2261 // in its final location
2262
2263 final LauncherAppWidgetHostView hostView = (LauncherAppWidgetHostView) cell;
2264 AppWidgetProviderInfo pinfo = hostView.getAppWidgetInfo();
Adam Cohenc0a5df92012-04-02 16:53:26 -07002265 if (pinfo != null &&
2266 pinfo.resizeMode != AppWidgetProviderInfo.RESIZE_NONE) {
Adam Cohend41fbf52012-02-16 23:53:59 -08002267 final Runnable addResizeFrame = new Runnable() {
Adam Cohend4844c32011-02-18 19:25:06 -08002268 public void run() {
Adam Cohen716b51e2011-06-30 12:09:54 -07002269 DragLayer dragLayer = mLauncher.getDragLayer();
Adam Cohenc0dcf592011-06-01 15:30:43 -07002270 dragLayer.addResizeFrame(info, hostView, cellLayout);
Adam Cohend4844c32011-02-18 19:25:06 -08002271 }
Adam Cohen26976d92011-03-22 15:33:33 -07002272 };
Adam Cohend41fbf52012-02-16 23:53:59 -08002273 resizeRunnable = (new Runnable() {
Adam Cohen26976d92011-03-22 15:33:33 -07002274 public void run() {
2275 if (!isPageMoving()) {
Adam Cohend41fbf52012-02-16 23:53:59 -08002276 addResizeFrame.run();
Adam Cohen26976d92011-03-22 15:33:33 -07002277 } else {
Adam Cohend41fbf52012-02-16 23:53:59 -08002278 mDelayedResizeRunnable = addResizeFrame;
Adam Cohen26976d92011-03-22 15:33:33 -07002279 }
2280 }
Adam Cohend4844c32011-02-18 19:25:06 -08002281 });
2282 }
2283 }
2284
Winson Chung3d503fb2011-07-13 17:25:49 -07002285 LauncherModel.moveItemInDatabase(mLauncher, info, container, screen, lp.cellX,
2286 lp.cellY);
Adam Cohend41fbf52012-02-16 23:53:59 -08002287 } else {
2288 // If we can't find a drop location, we return the item to its original position
2289 CellLayout.LayoutParams lp = (CellLayout.LayoutParams) cell.getLayoutParams();
2290 mTargetCell[0] = lp.cellX;
2291 mTargetCell[1] = lp.cellY;
Adam Cohenf1dcdf62012-05-10 16:51:52 -07002292 CellLayout layout = (CellLayout) cell.getParent().getParent();
2293 layout.markCellsAsOccupiedForView(cell);
Patrick Dubroycd68ff52010-10-28 17:57:05 -07002294 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -08002295 }
Patrick Dubroyce34a972010-10-19 10:34:32 -07002296
Michael Jurka8c920dd2011-01-20 14:16:56 -08002297 final CellLayout parent = (CellLayout) cell.getParent().getParent();
Adam Cohend41fbf52012-02-16 23:53:59 -08002298 final Runnable finalResizeRunnable = resizeRunnable;
Patrick Dubroyce34a972010-10-19 10:34:32 -07002299 // Prepare it to be animated into its new position
2300 // This must be called after the view has been re-parented
Adam Cohend41fbf52012-02-16 23:53:59 -08002301 final Runnable onCompleteRunnable = new Runnable() {
Michael Jurkad74c9842011-07-10 12:44:21 -07002302 @Override
2303 public void run() {
2304 mAnimatingViewIntoPlace = false;
Michael Jurka3a0469d2012-06-21 09:38:41 -07002305 updateChildrenLayersEnabled(false);
Adam Cohend41fbf52012-02-16 23:53:59 -08002306 if (finalResizeRunnable != null) {
2307 finalResizeRunnable.run();
2308 }
Michael Jurkad74c9842011-07-10 12:44:21 -07002309 }
2310 };
2311 mAnimatingViewIntoPlace = true;
Adam Cohenfc53cd22011-07-20 15:45:11 -07002312 if (d.dragView.hasDrawn()) {
Adam Cohend41fbf52012-02-16 23:53:59 -08002313 final ItemInfo info = (ItemInfo) cell.getTag();
2314 if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET) {
2315 int animationType = resizeOnDrop ? ANIMATE_INTO_POSITION_AND_RESIZE :
2316 ANIMATE_INTO_POSITION_AND_DISAPPEAR;
2317 animateWidgetDrop(info, parent, d.dragView,
2318 onCompleteRunnable, animationType, cell, false);
2319 } else {
Adam Cohen85b467b2012-02-29 15:38:46 -08002320 int duration = snapScreen < 0 ? -1 : ADJACENT_SCREEN_DROP_DURATION;
2321 mLauncher.getDragLayer().animateViewIntoPosition(d.dragView, cell, duration,
2322 onCompleteRunnable, this);
Adam Cohend41fbf52012-02-16 23:53:59 -08002323 }
Adam Cohenfc53cd22011-07-20 15:45:11 -07002324 } else {
Winson Chung7bd1bbb2012-02-13 18:29:29 -08002325 d.deferDragViewCleanupPostAnimation = false;
Adam Cohenfc53cd22011-07-20 15:45:11 -07002326 cell.setVisibility(VISIBLE);
2327 }
Adam Cohen716b51e2011-06-30 12:09:54 -07002328 parent.onDropChild(cell);
The Android Open Source Project31dd5032009-03-03 19:32:27 -08002329 }
2330 }
2331
Adam Cohened51cc92011-08-01 20:28:08 -07002332 public void setFinalScrollForPageChange(int screen) {
2333 if (screen >= 0) {
2334 mSavedScrollX = getScrollX();
2335 CellLayout cl = (CellLayout) getChildAt(screen);
2336 mSavedTranslationX = cl.getTranslationX();
2337 mSavedRotationY = cl.getRotationY();
2338 final int newX = getChildOffset(screen) - getRelativeChildOffset(screen);
2339 setScrollX(newX);
2340 cl.setTranslationX(0f);
2341 cl.setRotationY(0f);
2342 }
2343 }
2344
2345 public void resetFinalScrollForPageChange(int screen) {
2346 if (screen >= 0) {
2347 CellLayout cl = (CellLayout) getChildAt(screen);
2348 setScrollX(mSavedScrollX);
2349 cl.setTranslationX(mSavedTranslationX);
2350 cl.setRotationY(mSavedRotationY);
2351 }
2352 }
2353
Adam Cohen76078c42011-06-09 15:06:52 -07002354 public void getViewLocationRelativeToSelf(View v, int[] location) {
Adam Cohen8dfcba42011-07-07 16:38:18 -07002355 getLocationInWindow(location);
Adam Cohene3e27a82011-04-15 12:07:39 -07002356 int x = location[0];
2357 int y = location[1];
2358
Adam Cohen8dfcba42011-07-07 16:38:18 -07002359 v.getLocationInWindow(location);
Adam Cohene3e27a82011-04-15 12:07:39 -07002360 int vX = location[0];
2361 int vY = location[1];
2362
2363 location[0] = vX - x;
2364 location[1] = vY - y;
2365 }
2366
Adam Cohencb3382b2011-05-24 14:07:08 -07002367 public void onDragEnter(DragObject d) {
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002368 mDragEnforcer.onDragEnter();
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002369 mCreateUserFolderOnDrop = false;
2370 mAddToExistingFolderOnDrop = false;
2371
2372 mDropToLayout = null;
2373 CellLayout layout = getCurrentDropLayout();
2374 setCurrentDropLayout(layout);
2375 setCurrentDragOverlappingLayout(layout);
Winson Chungb26f3d62011-06-02 10:49:29 -07002376
Winson Chungc07918d2011-07-01 15:35:26 -07002377 // Because we don't have space in the Phone UI (the CellLayouts run to the edge) we
2378 // don't need to show the outlines
2379 if (LauncherApplication.isScreenLarge()) {
2380 showOutlines();
Michael Jurkad718d6a2010-10-14 15:35:17 -07002381 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -08002382 }
2383
Adam Cohena897f392012-04-27 18:12:05 -07002384 static Rect getCellLayoutMetrics(Launcher launcher, int orientation) {
2385 Resources res = launcher.getResources();
2386 Display display = launcher.getWindowManager().getDefaultDisplay();
2387 Point smallestSize = new Point();
2388 Point largestSize = new Point();
2389 display.getCurrentSizeRange(smallestSize, largestSize);
2390 if (orientation == CellLayout.LANDSCAPE) {
2391 if (mLandscapeCellLayoutMetrics == null) {
2392 int paddingLeft = res.getDimensionPixelSize(R.dimen.workspace_left_padding_land);
2393 int paddingRight = res.getDimensionPixelSize(R.dimen.workspace_right_padding_land);
2394 int paddingTop = res.getDimensionPixelSize(R.dimen.workspace_top_padding_land);
2395 int paddingBottom = res.getDimensionPixelSize(R.dimen.workspace_bottom_padding_land);
2396 int width = largestSize.x - paddingLeft - paddingRight;
2397 int height = smallestSize.y - paddingTop - paddingBottom;
2398 mLandscapeCellLayoutMetrics = new Rect();
2399 CellLayout.getMetrics(mLandscapeCellLayoutMetrics, res,
2400 width, height, LauncherModel.getCellCountX(), LauncherModel.getCellCountY(),
2401 orientation);
2402 }
2403 return mLandscapeCellLayoutMetrics;
2404 } else if (orientation == CellLayout.PORTRAIT) {
2405 if (mPortraitCellLayoutMetrics == null) {
2406 int paddingLeft = res.getDimensionPixelSize(R.dimen.workspace_left_padding_land);
2407 int paddingRight = res.getDimensionPixelSize(R.dimen.workspace_right_padding_land);
2408 int paddingTop = res.getDimensionPixelSize(R.dimen.workspace_top_padding_land);
2409 int paddingBottom = res.getDimensionPixelSize(R.dimen.workspace_bottom_padding_land);
2410 int width = smallestSize.x - paddingLeft - paddingRight;
2411 int height = largestSize.y - paddingTop - paddingBottom;
2412 mPortraitCellLayoutMetrics = new Rect();
2413 CellLayout.getMetrics(mPortraitCellLayoutMetrics, res,
2414 width, height, LauncherModel.getCellCountX(), LauncherModel.getCellCountY(),
2415 orientation);
2416 }
2417 return mPortraitCellLayoutMetrics;
2418 }
2419 return null;
2420 }
2421
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002422 public void onDragExit(DragObject d) {
2423 mDragEnforcer.onDragExit();
Winson Chungc07918d2011-07-01 15:35:26 -07002424
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002425 // Here we store the final page that will be dropped to, if the workspace in fact
2426 // receives the drop
2427 if (mInScrollArea) {
Winson Chungcc1cfe42012-06-18 15:09:17 -07002428 if (isPageMoving()) {
2429 // If the user drops while the page is scrolling, we should use that page as the
2430 // destination instead of the page that is being hovered over.
2431 mDropToLayout = (CellLayout) getPageAt(getNextPage());
2432 } else {
2433 mDropToLayout = mDragOverlappingLayout;
2434 }
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002435 } else {
2436 mDropToLayout = mDragTargetLayout;
2437 }
2438
2439 if (mDragMode == DRAG_MODE_CREATE_FOLDER) {
2440 mCreateUserFolderOnDrop = true;
2441 } else if (mDragMode == DRAG_MODE_ADD_TO_FOLDER) {
2442 mAddToExistingFolderOnDrop = true;
Adam Cohen482ed822012-03-02 14:15:13 -08002443 }
2444
Winson Chungc07918d2011-07-01 15:35:26 -07002445 // Reset the scroll area and previous drag target
2446 onResetScrollArea();
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002447 setCurrentDropLayout(null);
2448 setCurrentDragOverlappingLayout(null);
Winson Chungc07918d2011-07-01 15:35:26 -07002449
Adam Cohen74c28d12011-11-18 14:17:11 -08002450 mSpringLoadedDragController.cancel();
Winson Chungc07918d2011-07-01 15:35:26 -07002451
2452 if (!mIsPageMoving) {
2453 hideOutlines();
2454 }
2455 }
2456
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002457 void setCurrentDropLayout(CellLayout layout) {
2458 if (mDragTargetLayout != null) {
2459 mDragTargetLayout.revertTempState();
2460 mDragTargetLayout.onDragExit();
2461 }
2462 mDragTargetLayout = layout;
2463 if (mDragTargetLayout != null) {
2464 mDragTargetLayout.onDragEnter();
2465 }
2466 cleanupReorder(true);
2467 cleanupFolderCreation();
2468 setCurrentDropOverCell(-1, -1);
2469 }
2470
2471 void setCurrentDragOverlappingLayout(CellLayout layout) {
2472 if (mDragOverlappingLayout != null) {
2473 mDragOverlappingLayout.setIsDragOverlapping(false);
2474 }
2475 mDragOverlappingLayout = layout;
2476 if (mDragOverlappingLayout != null) {
2477 mDragOverlappingLayout.setIsDragOverlapping(true);
2478 }
2479 invalidate();
2480 }
2481
2482 void setCurrentDropOverCell(int x, int y) {
2483 if (x != mDragOverX || y != mDragOverY) {
2484 mDragOverX = x;
2485 mDragOverY = y;
2486 setDragMode(DRAG_MODE_NONE);
2487 }
2488 }
2489
2490 void setDragMode(int dragMode) {
2491 if (dragMode != mDragMode) {
2492 if (dragMode == DRAG_MODE_NONE) {
2493 cleanupAddToFolder();
2494 // We don't want to cancel the re-order alarm every time the target cell changes
2495 // as this feels to slow / unresponsive.
2496 cleanupReorder(false);
2497 cleanupFolderCreation();
2498 } else if (dragMode == DRAG_MODE_ADD_TO_FOLDER) {
2499 cleanupReorder(true);
2500 cleanupFolderCreation();
2501 } else if (dragMode == DRAG_MODE_CREATE_FOLDER) {
2502 cleanupAddToFolder();
2503 cleanupReorder(true);
2504 } else if (dragMode == DRAG_MODE_REORDER) {
2505 cleanupAddToFolder();
2506 cleanupFolderCreation();
2507 }
2508 mDragMode = dragMode;
2509 }
2510 }
2511
2512 private void cleanupFolderCreation() {
2513 if (mDragFolderRingAnimator != null) {
2514 mDragFolderRingAnimator.animateToNaturalState();
2515 }
2516 mFolderCreationAlarm.cancelAlarm();
2517 }
2518
2519 private void cleanupAddToFolder() {
2520 if (mDragOverFolderIcon != null) {
2521 mDragOverFolderIcon.onDragExit(null);
2522 mDragOverFolderIcon = null;
2523 }
2524 }
2525
2526 private void cleanupReorder(boolean cancelAlarm) {
2527 // Any pending reorders are canceled
2528 if (cancelAlarm) {
2529 mReorderAlarm.cancelAlarm();
2530 }
2531 mLastReorderX = -1;
2532 mLastReorderY = -1;
Winson Chungc07918d2011-07-01 15:35:26 -07002533 }
2534
Adam Cohencb3382b2011-05-24 14:07:08 -07002535 public DropTarget getDropTargetDelegate(DragObject d) {
Patrick Dubroy440c3602010-07-13 17:50:32 -07002536 return null;
2537 }
2538
Michael Jurka4516c112010-10-07 15:13:47 -07002539 /*
2540 *
2541 * Convert the 2D coordinate xy from the parent View's coordinate space to this CellLayout's
2542 * coordinate space. The argument xy is modified with the return result.
2543 *
2544 */
2545 void mapPointFromSelfToChild(View v, float[] xy) {
2546 mapPointFromSelfToChild(v, xy, null);
2547 }
2548
2549 /*
2550 *
2551 * Convert the 2D coordinate xy from the parent View's coordinate space to this CellLayout's
2552 * coordinate space. The argument xy is modified with the return result.
2553 *
2554 * if cachedInverseMatrix is not null, this method will just use that matrix instead of
Michael Jurkad718d6a2010-10-14 15:35:17 -07002555 * computing it itself; we use this to avoid redundant matrix inversions in
Michael Jurka4516c112010-10-07 15:13:47 -07002556 * findMatchingPageForDragOver
2557 *
2558 */
2559 void mapPointFromSelfToChild(View v, float[] xy, Matrix cachedInverseMatrix) {
2560 if (cachedInverseMatrix == null) {
2561 v.getMatrix().invert(mTempInverseMatrix);
2562 cachedInverseMatrix = mTempInverseMatrix;
2563 }
Michael Jurka8b805b12012-04-18 14:23:14 -07002564 int scrollX = getScrollX();
Winson Chung3bc21c32012-01-20 13:59:18 -08002565 if (mNextPage != INVALID_PAGE) {
2566 scrollX = mScroller.getFinalX();
2567 }
2568 xy[0] = xy[0] + scrollX - v.getLeft();
Michael Jurka8b805b12012-04-18 14:23:14 -07002569 xy[1] = xy[1] + getScrollY() - v.getTop();
Michael Jurka4516c112010-10-07 15:13:47 -07002570 cachedInverseMatrix.mapPoints(xy);
2571 }
2572
2573 /*
Winson Chung3d503fb2011-07-13 17:25:49 -07002574 * Maps a point from the Workspace's coordinate system to another sibling view's. (Workspace
2575 * covers the full screen)
2576 */
2577 void mapPointFromSelfToSibling(View v, float[] xy) {
2578 xy[0] = xy[0] - v.getLeft();
2579 xy[1] = xy[1] - v.getTop();
2580 }
2581
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002582 void mapPointFromSelfToHotseatLayout(Hotseat hotseat, float[] xy) {
2583 xy[0] = xy[0] - hotseat.getLeft() - hotseat.getLayout().getLeft();
2584 xy[1] = xy[1] - hotseat.getTop() - hotseat.getLayout().getTop();
2585 }
2586
Winson Chung3d503fb2011-07-13 17:25:49 -07002587 /*
Michael Jurka4516c112010-10-07 15:13:47 -07002588 *
2589 * Convert the 2D coordinate xy from this CellLayout's coordinate space to
2590 * the parent View's coordinate space. The argument xy is modified with the return result.
2591 *
2592 */
2593 void mapPointFromChildToSelf(View v, float[] xy) {
2594 v.getMatrix().mapPoints(xy);
Michael Jurka8b805b12012-04-18 14:23:14 -07002595 int scrollX = getScrollX();
Winson Chung3bc21c32012-01-20 13:59:18 -08002596 if (mNextPage != INVALID_PAGE) {
2597 scrollX = mScroller.getFinalX();
2598 }
2599 xy[0] -= (scrollX - v.getLeft());
Michael Jurka8b805b12012-04-18 14:23:14 -07002600 xy[1] -= (getScrollY() - v.getTop());
Michael Jurka4516c112010-10-07 15:13:47 -07002601 }
2602
Adam Cohene3e27a82011-04-15 12:07:39 -07002603 static private float squaredDistance(float[] point1, float[] point2) {
Michael Jurka4516c112010-10-07 15:13:47 -07002604 float distanceX = point1[0] - point2[0];
2605 float distanceY = point2[1] - point2[1];
2606 return distanceX * distanceX + distanceY * distanceY;
Adam Cohene3e27a82011-04-15 12:07:39 -07002607 }
Michael Jurka0280c3b2010-09-17 15:00:07 -07002608
Michael Jurka4516c112010-10-07 15:13:47 -07002609 /*
2610 *
2611 * Returns true if the passed CellLayout cl overlaps with dragView
2612 *
2613 */
2614 boolean overlaps(CellLayout cl, DragView dragView,
2615 int dragViewX, int dragViewY, Matrix cachedInverseMatrix) {
2616 // Transform the coordinates of the item being dragged to the CellLayout's coordinates
2617 final float[] draggedItemTopLeft = mTempDragCoordinates;
Michael Jurkaf12c75c2011-01-25 22:41:40 -08002618 draggedItemTopLeft[0] = dragViewX;
2619 draggedItemTopLeft[1] = dragViewY;
Michael Jurka4516c112010-10-07 15:13:47 -07002620 final float[] draggedItemBottomRight = mTempDragBottomRightCoordinates;
Michael Jurkaf12c75c2011-01-25 22:41:40 -08002621 draggedItemBottomRight[0] = draggedItemTopLeft[0] + dragView.getDragRegionWidth();
2622 draggedItemBottomRight[1] = draggedItemTopLeft[1] + dragView.getDragRegionHeight();
Michael Jurkaa63c4522010-08-19 13:52:27 -07002623
Michael Jurka4516c112010-10-07 15:13:47 -07002624 // Transform the dragged item's top left coordinates
2625 // to the CellLayout's local coordinates
2626 mapPointFromSelfToChild(cl, draggedItemTopLeft, cachedInverseMatrix);
2627 float overlapRegionLeft = Math.max(0f, draggedItemTopLeft[0]);
2628 float overlapRegionTop = Math.max(0f, draggedItemTopLeft[1]);
2629
2630 if (overlapRegionLeft <= cl.getWidth() && overlapRegionTop >= 0) {
2631 // Transform the dragged item's bottom right coordinates
2632 // to the CellLayout's local coordinates
2633 mapPointFromSelfToChild(cl, draggedItemBottomRight, cachedInverseMatrix);
2634 float overlapRegionRight = Math.min(cl.getWidth(), draggedItemBottomRight[0]);
2635 float overlapRegionBottom = Math.min(cl.getHeight(), draggedItemBottomRight[1]);
2636
2637 if (overlapRegionRight >= 0 && overlapRegionBottom <= cl.getHeight()) {
2638 float overlap = (overlapRegionRight - overlapRegionLeft) *
2639 (overlapRegionBottom - overlapRegionTop);
2640 if (overlap > 0) {
2641 return true;
2642 }
2643 }
2644 }
2645 return false;
2646 }
2647
2648 /*
2649 *
2650 * This method returns the CellLayout that is currently being dragged to. In order to drag
2651 * to a CellLayout, either the touch point must be directly over the CellLayout, or as a second
2652 * strategy, we see if the dragView is overlapping any CellLayout and choose the closest one
2653 *
2654 * Return null if no CellLayout is currently being dragged over
2655 *
2656 */
2657 private CellLayout findMatchingPageForDragOver(
Adam Cohen00618752011-07-20 12:06:04 -07002658 DragView dragView, float originX, float originY, boolean exact) {
Michael Jurka4516c112010-10-07 15:13:47 -07002659 // We loop through all the screens (ie CellLayouts) and see which ones overlap
2660 // with the item being dragged and then choose the one that's closest to the touch point
Michael Jurkaa63c4522010-08-19 13:52:27 -07002661 final int screenCount = getChildCount();
2662 CellLayout bestMatchingScreen = null;
Michael Jurka0280c3b2010-09-17 15:00:07 -07002663 float smallestDistSoFar = Float.MAX_VALUE;
Michael Jurka4516c112010-10-07 15:13:47 -07002664
Michael Jurkaa63c4522010-08-19 13:52:27 -07002665 for (int i = 0; i < screenCount; i++) {
Winson Chung3d503fb2011-07-13 17:25:49 -07002666 CellLayout cl = (CellLayout) getChildAt(i);
Michael Jurkaa63c4522010-08-19 13:52:27 -07002667
Adam Cohen00618752011-07-20 12:06:04 -07002668 final float[] touchXy = {originX, originY};
Michael Jurka4516c112010-10-07 15:13:47 -07002669 // Transform the touch coordinates to the CellLayout's local coordinates
2670 // If the touch point is within the bounds of the cell layout, we can return immediately
Michael Jurka0280c3b2010-09-17 15:00:07 -07002671 cl.getMatrix().invert(mTempInverseMatrix);
Michael Jurka4516c112010-10-07 15:13:47 -07002672 mapPointFromSelfToChild(cl, touchXy, mTempInverseMatrix);
Michael Jurkaa63c4522010-08-19 13:52:27 -07002673
Michael Jurka4516c112010-10-07 15:13:47 -07002674 if (touchXy[0] >= 0 && touchXy[0] <= cl.getWidth() &&
2675 touchXy[1] >= 0 && touchXy[1] <= cl.getHeight()) {
2676 return cl;
2677 }
Michael Jurkaa63c4522010-08-19 13:52:27 -07002678
Winson Chung96ef4092011-11-22 12:25:14 -08002679 if (!exact) {
Michael Jurka4516c112010-10-07 15:13:47 -07002680 // Get the center of the cell layout in screen coordinates
2681 final float[] cellLayoutCenter = mTempCellLayoutCenterCoordinates;
2682 cellLayoutCenter[0] = cl.getWidth()/2;
2683 cellLayoutCenter[1] = cl.getHeight()/2;
2684 mapPointFromChildToSelf(cl, cellLayoutCenter);
Michael Jurka0280c3b2010-09-17 15:00:07 -07002685
Adam Cohen00618752011-07-20 12:06:04 -07002686 touchXy[0] = originX;
2687 touchXy[1] = originY;
Michael Jurka0280c3b2010-09-17 15:00:07 -07002688
Michael Jurka4516c112010-10-07 15:13:47 -07002689 // Calculate the distance between the center of the CellLayout
2690 // and the touch point
2691 float dist = squaredDistance(touchXy, cellLayoutCenter);
2692
2693 if (dist < smallestDistSoFar) {
Michael Jurka0280c3b2010-09-17 15:00:07 -07002694 smallestDistSoFar = dist;
Michael Jurkaa63c4522010-08-19 13:52:27 -07002695 bestMatchingScreen = cl;
Michael Jurkaa63c4522010-08-19 13:52:27 -07002696 }
Michael Jurka4516c112010-10-07 15:13:47 -07002697 }
Michael Jurkaa63c4522010-08-19 13:52:27 -07002698 }
Michael Jurkaa63c4522010-08-19 13:52:27 -07002699 return bestMatchingScreen;
2700 }
2701
Adam Cohene3e27a82011-04-15 12:07:39 -07002702 // This is used to compute the visual center of the dragView. This point is then
2703 // used to visualize drop locations and determine where to drop an item. The idea is that
2704 // the visual center represents the user's interpretation of where the item is, and hence
2705 // is the appropriate point to use when determining drop location.
2706 private float[] getDragViewVisualCenter(int x, int y, int xOffset, int yOffset,
2707 DragView dragView, float[] recycle) {
2708 float res[];
2709 if (recycle == null) {
2710 res = new float[2];
2711 } else {
2712 res = recycle;
2713 }
2714
2715 // First off, the drag view has been shifted in a way that is not represented in the
2716 // x and y values or the x/yOffsets. Here we account for that shift.
2717 x += getResources().getDimensionPixelSize(R.dimen.dragViewOffsetX);
2718 y += getResources().getDimensionPixelSize(R.dimen.dragViewOffsetY);
2719
2720 // These represent the visual top and left of drag view if a dragRect was provided.
2721 // If a dragRect was not provided, then they correspond to the actual view left and
2722 // top, as the dragRect is in that case taken to be the entire dragView.
2723 // R.dimen.dragViewOffsetY.
2724 int left = x - xOffset;
2725 int top = y - yOffset;
2726
2727 // In order to find the visual center, we shift by half the dragRect
2728 res[0] = left + dragView.getDragRegion().width() / 2;
2729 res[1] = top + dragView.getDragRegion().height() / 2;
2730
2731 return res;
2732 }
2733
Winson Chungea359c62011-08-03 17:06:35 -07002734 private boolean isDragWidget(DragObject d) {
2735 return (d.dragInfo instanceof LauncherAppWidgetInfo ||
2736 d.dragInfo instanceof PendingAddWidgetInfo);
2737 }
2738 private boolean isExternalDragWidget(DragObject d) {
2739 return d.dragSource != this && isDragWidget(d);
2740 }
2741
Adam Cohencb3382b2011-05-24 14:07:08 -07002742 public void onDragOver(DragObject d) {
Winson Chungc07918d2011-07-01 15:35:26 -07002743 // Skip drag over events while we are dragging over side pages
Adam Cohen82ac8a22012-02-14 16:27:49 -08002744 if (mInScrollArea || mIsSwitchingState || mState == State.SMALL) return;
Winson Chungc07918d2011-07-01 15:35:26 -07002745
Winson Chung4afe9b32011-07-27 17:46:20 -07002746 Rect r = new Rect();
Winson Chung3d503fb2011-07-13 17:25:49 -07002747 CellLayout layout = null;
Winson Chungc07918d2011-07-01 15:35:26 -07002748 ItemInfo item = (ItemInfo) d.dragInfo;
2749
2750 // Ensure that we have proper spans for the item that we are dropping
2751 if (item.spanX < 0 || item.spanY < 0) throw new RuntimeException("Improper spans found");
Adam Cohen00618752011-07-20 12:06:04 -07002752 mDragViewVisualCenter = getDragViewVisualCenter(d.x, d.y, d.xOffset, d.yOffset,
Winson Chung4afe9b32011-07-27 17:46:20 -07002753 d.dragView, mDragViewVisualCenter);
Adam Cohen00618752011-07-20 12:06:04 -07002754
Adam Cohen482ed822012-03-02 14:15:13 -08002755 final View child = (mDragInfo == null) ? null : mDragInfo.cell;
Winson Chungc07918d2011-07-01 15:35:26 -07002756 // Identify whether we have dragged over a side page
Michael Jurkad74c9842011-07-10 12:44:21 -07002757 if (isSmall()) {
Winson Chungea359c62011-08-03 17:06:35 -07002758 if (mLauncher.getHotseat() != null && !isExternalDragWidget(d)) {
Winson Chung4afe9b32011-07-27 17:46:20 -07002759 mLauncher.getHotseat().getHitRect(r);
2760 if (r.contains(d.x, d.y)) {
2761 layout = mLauncher.getHotseat().getLayout();
2762 }
2763 }
2764 if (layout == null) {
Winson Chung96ef4092011-11-22 12:25:14 -08002765 layout = findMatchingPageForDragOver(d.dragView, d.x, d.y, false);
Winson Chung4afe9b32011-07-27 17:46:20 -07002766 }
Winson Chungc07918d2011-07-01 15:35:26 -07002767 if (layout != mDragTargetLayout) {
Winson Chungc07918d2011-07-01 15:35:26 -07002768
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002769 setCurrentDropLayout(layout);
2770 setCurrentDragOverlappingLayout(layout);
Winson Chungc07918d2011-07-01 15:35:26 -07002771
Michael Jurkad74c9842011-07-10 12:44:21 -07002772 boolean isInSpringLoadedMode = (mState == State.SPRING_LOADED);
Winson Chungc07918d2011-07-01 15:35:26 -07002773 if (isInSpringLoadedMode) {
Winson Chung4afe9b32011-07-27 17:46:20 -07002774 if (mLauncher.isHotseatLayout(layout)) {
2775 mSpringLoadedDragController.cancel();
2776 } else {
2777 mSpringLoadedDragController.setAlarm(mDragTargetLayout);
2778 }
Winson Chungc07918d2011-07-01 15:35:26 -07002779 }
2780 }
2781 } else {
Winson Chung3d503fb2011-07-13 17:25:49 -07002782 // Test to see if we are over the hotseat otherwise just use the current page
Winson Chungea359c62011-08-03 17:06:35 -07002783 if (mLauncher.getHotseat() != null && !isDragWidget(d)) {
Winson Chung3d503fb2011-07-13 17:25:49 -07002784 mLauncher.getHotseat().getHitRect(r);
2785 if (r.contains(d.x, d.y)) {
2786 layout = mLauncher.getHotseat().getLayout();
2787 }
2788 }
2789 if (layout == null) {
2790 layout = getCurrentDropLayout();
2791 }
Winson Chungc07918d2011-07-01 15:35:26 -07002792 if (layout != mDragTargetLayout) {
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002793 setCurrentDropLayout(layout);
2794 setCurrentDragOverlappingLayout(layout);
Winson Chungc07918d2011-07-01 15:35:26 -07002795 }
2796 }
2797
2798 // Handle the drag over
2799 if (mDragTargetLayout != null) {
Winson Chungc07918d2011-07-01 15:35:26 -07002800 // We want the point to be mapped to the dragTarget.
Winson Chung3d503fb2011-07-13 17:25:49 -07002801 if (mLauncher.isHotseatLayout(mDragTargetLayout)) {
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002802 mapPointFromSelfToHotseatLayout(mLauncher.getHotseat(), mDragViewVisualCenter);
Winson Chung3d503fb2011-07-13 17:25:49 -07002803 } else {
2804 mapPointFromSelfToChild(mDragTargetLayout, mDragViewVisualCenter, null);
2805 }
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002806
Winson Chungc07918d2011-07-01 15:35:26 -07002807 ItemInfo info = (ItemInfo) d.dragInfo;
Patrick Dubroy1262e362010-10-06 15:49:50 -07002808
Winson Chungc07918d2011-07-01 15:35:26 -07002809 mTargetCell = findNearestArea((int) mDragViewVisualCenter[0],
Adam Cohend024f982012-05-23 18:26:45 -07002810 (int) mDragViewVisualCenter[1], item.spanX, item.spanY,
2811 mDragTargetLayout, mTargetCell);
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002812
2813 setCurrentDropOverCell(mTargetCell[0], mTargetCell[1]);
2814
Adam Cohen482ed822012-03-02 14:15:13 -08002815 float targetCellDistance = mDragTargetLayout.getDistanceFromCell(
2816 mDragViewVisualCenter[0], mDragViewVisualCenter[1], mTargetCell);
2817
Winson Chungc07918d2011-07-01 15:35:26 -07002818 final View dragOverView = mDragTargetLayout.getChildAt(mTargetCell[0],
2819 mTargetCell[1]);
Winson Chung785d2eb2011-04-14 16:08:02 -07002820
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002821 manageFolderFeedback(info, mDragTargetLayout, mTargetCell,
2822 targetCellDistance, dragOverView);
Adam Cohen482ed822012-03-02 14:15:13 -08002823
2824 int minSpanX = item.spanX;
2825 int minSpanY = item.spanY;
2826 if (item.minSpanX > 0 && item.minSpanY > 0) {
2827 minSpanX = item.minSpanX;
2828 minSpanY = item.minSpanY;
2829 }
2830
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002831 boolean nearestDropOccupied = mDragTargetLayout.isNearestDropLocationOccupied((int)
2832 mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1], item.spanX,
2833 item.spanY, child, mTargetCell);
2834
2835 if (!nearestDropOccupied) {
Adam Cohen19f37922012-03-21 11:59:11 -07002836 mDragTargetLayout.visualizeDropLocation(child, mDragOutline,
2837 (int) mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1],
2838 mTargetCell[0], mTargetCell[1], item.spanX, item.spanY, false,
2839 d.dragView.getDragVisualizeOffset(), d.dragView.getDragRegion());
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002840 } else if ((mDragMode == DRAG_MODE_NONE || mDragMode == DRAG_MODE_REORDER)
Adam Cohend024f982012-05-23 18:26:45 -07002841 && !mReorderAlarm.alarmPending() && (mLastReorderX != mTargetCell[0] ||
2842 mLastReorderY != mTargetCell[1])) {
2843
Adam Cohen19f37922012-03-21 11:59:11 -07002844 // Otherwise, if we aren't adding to or creating a folder and there's no pending
2845 // reorder, then we schedule a reorder
Adam Cohen482ed822012-03-02 14:15:13 -08002846 ReorderAlarmListener listener = new ReorderAlarmListener(mDragViewVisualCenter,
2847 minSpanX, minSpanY, item.spanX, item.spanY, d.dragView, child);
2848 mReorderAlarm.setOnAlarmListener(listener);
2849 mReorderAlarm.setAlarm(REORDER_TIMEOUT);
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002850 }
2851
2852 if (mDragMode == DRAG_MODE_CREATE_FOLDER || mDragMode == DRAG_MODE_ADD_TO_FOLDER ||
2853 !nearestDropOccupied) {
2854 if (mDragTargetLayout != null) {
2855 mDragTargetLayout.revertTempState();
Michael Jurkad3ef3062010-11-23 16:23:58 -08002856 }
2857 }
Adam Cohen482ed822012-03-02 14:15:13 -08002858 }
2859 }
2860
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002861 private void manageFolderFeedback(ItemInfo info, CellLayout targetLayout,
2862 int[] targetCell, float distance, View dragOverView) {
Adam Cohen482ed822012-03-02 14:15:13 -08002863 boolean userFolderPending = willCreateUserFolder(info, targetLayout, targetCell, distance,
2864 false);
2865
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002866 if (mDragMode == DRAG_MODE_NONE && userFolderPending &&
2867 !mFolderCreationAlarm.alarmPending()) {
Adam Cohen482ed822012-03-02 14:15:13 -08002868 mFolderCreationAlarm.setOnAlarmListener(new
2869 FolderCreationAlarmListener(targetLayout, targetCell[0], targetCell[1]));
2870 mFolderCreationAlarm.setAlarm(FOLDER_CREATION_TIMEOUT);
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002871 return;
Adam Cohen482ed822012-03-02 14:15:13 -08002872 }
2873
2874 boolean willAddToFolder =
2875 willAddToExistingUserFolder(info, targetLayout, targetCell, distance);
2876
2877 if (willAddToFolder && mDragMode == DRAG_MODE_NONE) {
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002878 mDragOverFolderIcon = ((FolderIcon) dragOverView);
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002879 mDragOverFolderIcon.onDragEnter(info);
Adam Cohen482ed822012-03-02 14:15:13 -08002880 if (targetLayout != null) {
2881 targetLayout.clearDragOutlines();
Winson Chungc07918d2011-07-01 15:35:26 -07002882 }
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002883 setDragMode(DRAG_MODE_ADD_TO_FOLDER);
2884 return;
Patrick Dubroy976ebec2010-08-04 20:03:37 -07002885 }
Adam Cohen482ed822012-03-02 14:15:13 -08002886
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002887 if (mDragMode == DRAG_MODE_ADD_TO_FOLDER && !willAddToFolder) {
2888 setDragMode(DRAG_MODE_NONE);
2889 }
2890 if (mDragMode == DRAG_MODE_CREATE_FOLDER && !userFolderPending) {
2891 setDragMode(DRAG_MODE_NONE);
Adam Cohen482ed822012-03-02 14:15:13 -08002892 }
2893
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002894 return;
Adam Cohenc0dcf592011-06-01 15:30:43 -07002895 }
2896
Adam Cohen19072da2011-05-31 14:30:45 -07002897 class FolderCreationAlarmListener implements OnAlarmListener {
Adam Cohen69ce2e52011-07-03 19:25:21 -07002898 CellLayout layout;
2899 int cellX;
2900 int cellY;
Adam Cohen19072da2011-05-31 14:30:45 -07002901
Adam Cohen69ce2e52011-07-03 19:25:21 -07002902 public FolderCreationAlarmListener(CellLayout layout, int cellX, int cellY) {
2903 this.layout = layout;
2904 this.cellX = cellX;
2905 this.cellY = cellY;
Adam Cohen19072da2011-05-31 14:30:45 -07002906 }
2907
2908 public void onAlarm(Alarm alarm) {
Adam Cohen19072da2011-05-31 14:30:45 -07002909 if (mDragFolderRingAnimator == null) {
2910 mDragFolderRingAnimator = new FolderRingAnimator(mLauncher, null);
2911 }
Adam Cohen69ce2e52011-07-03 19:25:21 -07002912 mDragFolderRingAnimator.setCell(cellX, cellY);
2913 mDragFolderRingAnimator.setCellLayout(layout);
Adam Cohen19072da2011-05-31 14:30:45 -07002914 mDragFolderRingAnimator.animateToAcceptState();
Adam Cohen69ce2e52011-07-03 19:25:21 -07002915 layout.showFolderAccept(mDragFolderRingAnimator);
2916 layout.clearDragOutlines();
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002917 setDragMode(DRAG_MODE_CREATE_FOLDER);
Adam Cohen482ed822012-03-02 14:15:13 -08002918 }
2919 }
2920
2921 class ReorderAlarmListener implements OnAlarmListener {
2922 float[] dragViewCenter;
2923 int minSpanX, minSpanY, spanX, spanY;
2924 DragView dragView;
2925 View child;
2926
2927 public ReorderAlarmListener(float[] dragViewCenter, int minSpanX, int minSpanY, int spanX,
2928 int spanY, DragView dragView, View child) {
2929 this.dragViewCenter = dragViewCenter;
2930 this.minSpanX = minSpanX;
2931 this.minSpanY = minSpanY;
2932 this.spanX = spanX;
2933 this.spanY = spanY;
2934 this.child = child;
2935 this.dragView = dragView;
2936 }
2937
2938 public void onAlarm(Alarm alarm) {
2939 int[] resultSpan = new int[2];
Adam Cohen19f37922012-03-21 11:59:11 -07002940 mTargetCell = findNearestArea((int) mDragViewVisualCenter[0],
2941 (int) mDragViewVisualCenter[1], spanX, spanY, mDragTargetLayout, mTargetCell);
2942 mLastReorderX = mTargetCell[0];
2943 mLastReorderY = mTargetCell[1];
2944
Adam Cohen482ed822012-03-02 14:15:13 -08002945 mTargetCell = mDragTargetLayout.createArea((int) mDragViewVisualCenter[0],
2946 (int) mDragViewVisualCenter[1], minSpanX, minSpanY, spanX, spanY,
2947 child, mTargetCell, resultSpan, CellLayout.MODE_DRAG_OVER);
2948
Adam Cohen19f37922012-03-21 11:59:11 -07002949 if (mTargetCell[0] < 0 || mTargetCell[1] < 0) {
2950 mDragTargetLayout.revertTempState();
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002951 } else {
2952 setDragMode(DRAG_MODE_REORDER);
Adam Cohen19f37922012-03-21 11:59:11 -07002953 }
Adam Cohen482ed822012-03-02 14:15:13 -08002954
Adam Cohen482ed822012-03-02 14:15:13 -08002955 boolean resize = resultSpan[0] != spanX || resultSpan[1] != spanY;
2956 mDragTargetLayout.visualizeDropLocation(child, mDragOutline,
2957 (int) mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1],
2958 mTargetCell[0], mTargetCell[1], resultSpan[0], resultSpan[1], resize,
2959 dragView.getDragVisualizeOffset(), dragView.getDragRegion());
Adam Cohen19072da2011-05-31 14:30:45 -07002960 }
2961 }
2962
Winson Chunga34abf82010-11-12 12:10:35 -08002963 @Override
2964 public void getHitRect(Rect outRect) {
2965 // We want the workspace to have the whole area of the display (it will find the correct
2966 // cell layout to drop to in the existing drag/drop logic.
Michael Jurka84f2ce72012-04-13 15:08:01 -07002967 outRect.set(0, 0, mDisplaySize.x, mDisplaySize.y);
Winson Chunga34abf82010-11-12 12:10:35 -08002968 }
2969
Patrick Dubroy2b9ff372010-09-07 17:49:27 -07002970 /**
2971 * Add the item specified by dragInfo to the given layout.
Patrick Dubroy2b9ff372010-09-07 17:49:27 -07002972 * @return true if successful
2973 */
Adam Cohen120980b2010-12-08 11:05:37 -08002974 public boolean addExternalItemToScreen(ItemInfo dragInfo, CellLayout layout) {
2975 if (layout.findCellForSpan(mTempEstimate, dragInfo.spanX, dragInfo.spanY)) {
Patrick Dubroybbaa75c2011-03-08 18:47:40 -08002976 onDropExternal(dragInfo.dropPos, (ItemInfo) dragInfo, (CellLayout) layout, false);
Patrick Dubroy2b9ff372010-09-07 17:49:27 -07002977 return true;
2978 }
Winson Chung93eef082012-03-23 15:59:27 -07002979 mLauncher.showOutOfSpaceMessage(mLauncher.isHotseatLayout(layout));
Patrick Dubroy2b9ff372010-09-07 17:49:27 -07002980 return false;
2981 }
2982
Adam Cohend5e42732011-03-28 17:33:39 -07002983 private void onDropExternal(int[] touchXY, Object dragInfo,
2984 CellLayout cellLayout, boolean insertAtFirst) {
Adam Cohene3e27a82011-04-15 12:07:39 -07002985 onDropExternal(touchXY, dragInfo, cellLayout, insertAtFirst, null);
Adam Cohend5e42732011-03-28 17:33:39 -07002986 }
2987
Adam Cohen120980b2010-12-08 11:05:37 -08002988 /**
2989 * Drop an item that didn't originate on one of the workspace screens.
2990 * It may have come from Launcher (e.g. from all apps or customize), or it may have
2991 * come from another app altogether.
2992 *
2993 * NOTE: This can also be called when we are outside of a drag event, when we want
2994 * to add an item to one of the workspace screens.
2995 */
Winson Chung557d6ed2011-07-08 15:34:52 -07002996 private void onDropExternal(final int[] touchXY, final Object dragInfo,
2997 final CellLayout cellLayout, boolean insertAtFirst, DragObject d) {
2998 final Runnable exitSpringLoadedRunnable = new Runnable() {
2999 @Override
3000 public void run() {
Adam Cohened66b2b2012-01-23 17:28:51 -08003001 mLauncher.exitSpringLoadedDragModeDelayed(true, false, null);
Winson Chung557d6ed2011-07-08 15:34:52 -07003002 }
3003 };
Adam Cohenb7e16182011-07-15 17:55:02 -07003004
3005 ItemInfo info = (ItemInfo) dragInfo;
3006 int spanX = info.spanX;
3007 int spanY = info.spanY;
3008 if (mDragInfo != null) {
3009 spanX = mDragInfo.spanX;
3010 spanY = mDragInfo.spanY;
3011 }
3012
Winson Chung3d503fb2011-07-13 17:25:49 -07003013 final long container = mLauncher.isHotseatLayout(cellLayout) ?
3014 LauncherSettings.Favorites.CONTAINER_HOTSEAT :
3015 LauncherSettings.Favorites.CONTAINER_DESKTOP;
Winson Chung557d6ed2011-07-08 15:34:52 -07003016 final int screen = indexOfChild(cellLayout);
Winson Chung3d503fb2011-07-13 17:25:49 -07003017 if (!mLauncher.isHotseatLayout(cellLayout) && screen != mCurrentPage
3018 && mState != State.SPRING_LOADED) {
Adam Cohen76078c42011-06-09 15:06:52 -07003019 snapToPage(screen);
3020 }
Adam Cohenb7e16182011-07-15 17:55:02 -07003021
3022 if (info instanceof PendingAddItemInfo) {
3023 final PendingAddItemInfo pendingInfo = (PendingAddItemInfo) dragInfo;
3024
Adam Cohen558baaf2011-08-15 15:22:57 -07003025 boolean findNearestVacantCell = true;
3026 if (pendingInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) {
3027 mTargetCell = findNearestArea((int) touchXY[0], (int) touchXY[1], spanX, spanY,
3028 cellLayout, mTargetCell);
Adam Cohen482ed822012-03-02 14:15:13 -08003029 float distance = cellLayout.getDistanceFromCell(mDragViewVisualCenter[0],
3030 mDragViewVisualCenter[1], mTargetCell);
Adam Cohenc6cc61d2012-04-04 12:47:08 -07003031 if (willCreateUserFolder((ItemInfo) d.dragInfo, cellLayout, mTargetCell,
Adam Cohen482ed822012-03-02 14:15:13 -08003032 distance, true) || willAddToExistingUserFolder((ItemInfo) d.dragInfo,
Adam Cohenc6cc61d2012-04-04 12:47:08 -07003033 cellLayout, mTargetCell, distance)) {
Adam Cohen558baaf2011-08-15 15:22:57 -07003034 findNearestVacantCell = false;
3035 }
3036 }
Adam Cohen482ed822012-03-02 14:15:13 -08003037
Adam Cohend41fbf52012-02-16 23:53:59 -08003038 final ItemInfo item = (ItemInfo) d.dragInfo;
Adam Cohen558baaf2011-08-15 15:22:57 -07003039 if (findNearestVacantCell) {
Adam Cohen482ed822012-03-02 14:15:13 -08003040 int minSpanX = item.spanX;
3041 int minSpanY = item.spanY;
3042 if (item.minSpanX > 0 && item.minSpanY > 0) {
3043 minSpanX = item.minSpanX;
3044 minSpanY = item.minSpanY;
3045 }
Adam Cohend41fbf52012-02-16 23:53:59 -08003046 int[] resultSpan = new int[2];
Adam Cohenc6cc61d2012-04-04 12:47:08 -07003047 mTargetCell = cellLayout.createArea((int) mDragViewVisualCenter[0],
Adam Cohen482ed822012-03-02 14:15:13 -08003048 (int) mDragViewVisualCenter[1], minSpanX, minSpanY, info.spanX, info.spanY,
3049 null, mTargetCell, resultSpan, CellLayout.MODE_ON_DROP_EXTERNAL);
Adam Cohend41fbf52012-02-16 23:53:59 -08003050 item.spanX = resultSpan[0];
3051 item.spanY = resultSpan[1];
Adam Cohen558baaf2011-08-15 15:22:57 -07003052 }
3053
Adam Cohenb7e16182011-07-15 17:55:02 -07003054 Runnable onAnimationCompleteRunnable = new Runnable() {
Winson Chung557d6ed2011-07-08 15:34:52 -07003055 @Override
3056 public void run() {
3057 // When dragging and dropping from customization tray, we deal with creating
3058 // widgets/shortcuts/folders in a slightly different way
Adam Cohenb7e16182011-07-15 17:55:02 -07003059 switch (pendingInfo.itemType) {
Winson Chung557d6ed2011-07-08 15:34:52 -07003060 case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
Adam Cohend41fbf52012-02-16 23:53:59 -08003061 int span[] = new int[2];
3062 span[0] = item.spanX;
3063 span[1] = item.spanY;
Adam Cohenb7e16182011-07-15 17:55:02 -07003064 mLauncher.addAppWidgetFromDrop((PendingAddWidgetInfo) pendingInfo,
Adam Cohend41fbf52012-02-16 23:53:59 -08003065 container, screen, mTargetCell, span, null);
Winson Chung557d6ed2011-07-08 15:34:52 -07003066 break;
3067 case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
Adam Cohenb7e16182011-07-15 17:55:02 -07003068 mLauncher.processShortcutFromDrop(pendingInfo.componentName,
Winson Chung3d503fb2011-07-13 17:25:49 -07003069 container, screen, mTargetCell, null);
Winson Chung557d6ed2011-07-08 15:34:52 -07003070 break;
3071 default:
Adam Cohenb7e16182011-07-15 17:55:02 -07003072 throw new IllegalStateException("Unknown item type: " +
3073 pendingInfo.itemType);
Winson Chung557d6ed2011-07-08 15:34:52 -07003074 }
Winson Chung557d6ed2011-07-08 15:34:52 -07003075 }
Adam Cohenb7e16182011-07-15 17:55:02 -07003076 };
Adam Cohend41fbf52012-02-16 23:53:59 -08003077 View finalView = pendingInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET
3078 ? ((PendingAddWidgetInfo) pendingInfo).boundWidget : null;
3079 int animationStyle = ANIMATE_INTO_POSITION_AND_DISAPPEAR;
3080 if (pendingInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET &&
3081 ((PendingAddWidgetInfo) pendingInfo).info.configure != null) {
3082 animationStyle = ANIMATE_INTO_POSITION_AND_REMAIN;
3083 }
3084 animateWidgetDrop(info, cellLayout, d.dragView, onAnimationCompleteRunnable,
3085 animationStyle, finalView, true);
Patrick Dubroy6569f2c2010-07-12 14:25:18 -07003086 } else {
Michael Jurka9c6de3d2010-11-23 16:23:58 -08003087 // This is for other drag/drop cases, like dragging from All Apps
Michael Jurka9c6de3d2010-11-23 16:23:58 -08003088 View view = null;
3089
3090 switch (info.itemType) {
3091 case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
3092 case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
3093 if (info.container == NO_ID && info instanceof ApplicationInfo) {
3094 // Came from all apps -- make a copy
Michael Jurkac9d95c52011-08-29 14:03:34 -07003095 info = new ShortcutInfo((ApplicationInfo) info);
Michael Jurka9c6de3d2010-11-23 16:23:58 -08003096 }
3097 view = mLauncher.createShortcut(R.layout.application, cellLayout,
3098 (ShortcutInfo) info);
3099 break;
Adam Cohendf2cc412011-04-27 16:56:57 -07003100 case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
Adam Cohenc0dcf592011-06-01 15:30:43 -07003101 view = FolderIcon.fromXml(R.layout.folder_icon, mLauncher, cellLayout,
3102 (FolderInfo) info, mIconCache);
Michael Jurka9c6de3d2010-11-23 16:23:58 -08003103 break;
3104 default:
3105 throw new IllegalStateException("Unknown item type: " + info.itemType);
3106 }
3107
Adam Cohenc0dcf592011-06-01 15:30:43 -07003108 // First we find the cell nearest to point at which the item is
3109 // dropped, without any consideration to whether there is an item there.
3110 if (touchXY != null) {
3111 mTargetCell = findNearestArea((int) touchXY[0], (int) touchXY[1], spanX, spanY,
3112 cellLayout, mTargetCell);
Adam Cohen482ed822012-03-02 14:15:13 -08003113 float distance = cellLayout.getDistanceFromCell(mDragViewVisualCenter[0],
3114 mDragViewVisualCenter[1], mTargetCell);
Winson Chung557d6ed2011-07-08 15:34:52 -07003115 d.postAnimationRunnable = exitSpringLoadedRunnable;
Adam Cohen482ed822012-03-02 14:15:13 -08003116 if (createUserFolderIfNecessary(view, container, cellLayout, mTargetCell, distance,
3117 true, d.dragView, d.postAnimationRunnable)) {
Adam Cohenc0dcf592011-06-01 15:30:43 -07003118 return;
3119 }
Adam Cohen482ed822012-03-02 14:15:13 -08003120 if (addToExistingFolderIfNecessary(view, cellLayout, mTargetCell, distance, d,
3121 true)) {
Adam Cohenc0dcf592011-06-01 15:30:43 -07003122 return;
3123 }
Adam Cohen10b17372011-04-15 14:21:25 -07003124 }
3125
Michael Jurkac4e772e2011-02-10 13:32:01 -08003126 if (touchXY != null) {
Michael Jurka9c6de3d2010-11-23 16:23:58 -08003127 // when dragging and dropping, just find the closest free spot
Adam Cohenc6cc61d2012-04-04 12:47:08 -07003128 mTargetCell = cellLayout.createArea((int) mDragViewVisualCenter[0],
Adam Cohen482ed822012-03-02 14:15:13 -08003129 (int) mDragViewVisualCenter[1], 1, 1, 1, 1,
Adam Cohenea889a22012-03-27 16:45:39 -07003130 null, mTargetCell, null, CellLayout.MODE_ON_DROP_EXTERNAL);
Michael Jurka9c6de3d2010-11-23 16:23:58 -08003131 } else {
3132 cellLayout.findCellForSpan(mTargetCell, 1, 1);
3133 }
Winson Chung3d503fb2011-07-13 17:25:49 -07003134 addInScreen(view, container, screen, mTargetCell[0], mTargetCell[1], info.spanX,
3135 info.spanY, insertAtFirst);
Adam Cohen716b51e2011-06-30 12:09:54 -07003136 cellLayout.onDropChild(view);
Patrick Dubroy6569f2c2010-07-12 14:25:18 -07003137 CellLayout.LayoutParams lp = (CellLayout.LayoutParams) view.getLayoutParams();
Michael Jurkaa52570f2012-03-20 03:18:20 -07003138 cellLayout.getShortcutsAndWidgets().measureChild(view);
Adam Cohend5e42732011-03-28 17:33:39 -07003139
Andrew Flynn0dca1ec2012-02-29 13:33:22 -08003140
Winson Chung3d503fb2011-07-13 17:25:49 -07003141 LauncherModel.addOrMoveItemInDatabase(mLauncher, info, container, screen,
Winson Chungaafa03c2010-06-11 17:34:16 -07003142 lp.cellX, lp.cellY);
Adam Cohen3e8f8112011-07-02 18:03:00 -07003143
3144 if (d.dragView != null) {
Adam Cohen4b285c52011-07-21 14:24:06 -07003145 // We wrap the animation call in the temporary set and reset of the current
3146 // cellLayout to its final transform -- this means we animate the drag view to
3147 // the correct final location.
3148 setFinalTransitionTransform(cellLayout);
Winson Chung557d6ed2011-07-08 15:34:52 -07003149 mLauncher.getDragLayer().animateViewIntoPosition(d.dragView, view,
Adam Cohen4b285c52011-07-21 14:24:06 -07003150 exitSpringLoadedRunnable);
3151 resetTransitionTransform(cellLayout);
Adam Cohen3e8f8112011-07-02 18:03:00 -07003152 }
Joe Onorato00acb122009-08-04 16:04:30 -04003153 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003154 }
Winson Chungaafa03c2010-06-11 17:34:16 -07003155
Adam Cohend41fbf52012-02-16 23:53:59 -08003156 public Bitmap createWidgetBitmap(ItemInfo widgetInfo, View layout) {
Adam Cohened66b2b2012-01-23 17:28:51 -08003157 int[] unScaledSize = mLauncher.getWorkspace().estimateItemSize(widgetInfo.spanX,
3158 widgetInfo.spanY, widgetInfo, false);
Adam Cohend41fbf52012-02-16 23:53:59 -08003159 int visibility = layout.getVisibility();
Adam Cohened66b2b2012-01-23 17:28:51 -08003160 layout.setVisibility(VISIBLE);
3161
3162 int width = MeasureSpec.makeMeasureSpec(unScaledSize[0], MeasureSpec.EXACTLY);
3163 int height = MeasureSpec.makeMeasureSpec(unScaledSize[1], MeasureSpec.EXACTLY);
3164 Bitmap b = Bitmap.createBitmap(unScaledSize[0], unScaledSize[1],
3165 Bitmap.Config.ARGB_8888);
3166 Canvas c = new Canvas(b);
3167
3168 layout.measure(width, height);
3169 layout.layout(0, 0, unScaledSize[0], unScaledSize[1]);
Adam Cohened66b2b2012-01-23 17:28:51 -08003170 layout.draw(c);
3171 c.setBitmap(null);
Adam Cohend41fbf52012-02-16 23:53:59 -08003172 layout.setVisibility(visibility);
Adam Cohened66b2b2012-01-23 17:28:51 -08003173 return b;
3174 }
3175
Adam Cohend41fbf52012-02-16 23:53:59 -08003176 private void getFinalPositionForDropAnimation(int[] loc, float[] scaleXY,
Adam Cohen9d5b7d82012-05-09 18:00:44 -07003177 DragView dragView, CellLayout layout, ItemInfo info, int[] targetCell,
Michael Jurkaa2fe7862012-05-29 05:58:17 -07003178 boolean external, boolean scale) {
Adam Cohened66b2b2012-01-23 17:28:51 -08003179 // Now we animate the dragView, (ie. the widget or shortcut preview) into its final
3180 // location and size on the home screen.
Adam Cohend41fbf52012-02-16 23:53:59 -08003181 int spanX = info.spanX;
3182 int spanY = info.spanY;
Adam Cohened66b2b2012-01-23 17:28:51 -08003183
Adam Cohend41fbf52012-02-16 23:53:59 -08003184 Rect r = estimateItemPosition(layout, info, targetCell[0], targetCell[1], spanX, spanY);
3185 loc[0] = r.left;
3186 loc[1] = r.top;
3187
3188 setFinalTransitionTransform(layout);
3189 float cellLayoutScale =
3190 mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(layout, loc);
3191 resetTransitionTransform(layout);
Michael Jurkaa2fe7862012-05-29 05:58:17 -07003192
3193 float dragViewScaleX;
3194 float dragViewScaleY;
3195 if (scale) {
3196 dragViewScaleX = (1.0f * r.width()) / dragView.getMeasuredWidth();
3197 dragViewScaleY = (1.0f * r.height()) / dragView.getMeasuredHeight();
3198 } else {
3199 dragViewScaleX = 1f;
3200 dragViewScaleY = 1f;
3201 }
Adam Cohend41fbf52012-02-16 23:53:59 -08003202
Adam Cohened66b2b2012-01-23 17:28:51 -08003203 // The animation will scale the dragView about its center, so we need to center about
3204 // the final location.
3205 loc[0] -= (dragView.getMeasuredWidth() - cellLayoutScale * r.width()) / 2;
3206 loc[1] -= (dragView.getMeasuredHeight() - cellLayoutScale * r.height()) / 2;
3207
Adam Cohend41fbf52012-02-16 23:53:59 -08003208 scaleXY[0] = dragViewScaleX * cellLayoutScale;
3209 scaleXY[1] = dragViewScaleY * cellLayoutScale;
3210 }
3211
3212 public void animateWidgetDrop(ItemInfo info, CellLayout cellLayout, DragView dragView,
3213 final Runnable onCompleteRunnable, int animationType, final View finalView,
3214 boolean external) {
3215 Rect from = new Rect();
3216 mLauncher.getDragLayer().getViewRectRelativeToSelf(dragView, from);
3217
3218 int[] finalPos = new int[2];
3219 float scaleXY[] = new float[2];
Michael Jurkaa2fe7862012-05-29 05:58:17 -07003220 boolean scalePreview = !(info instanceof PendingAddShortcutInfo);
Adam Cohend41fbf52012-02-16 23:53:59 -08003221 getFinalPositionForDropAnimation(finalPos, scaleXY, dragView, cellLayout, info, mTargetCell,
Michael Jurkaa2fe7862012-05-29 05:58:17 -07003222 external, scalePreview);
Adam Cohened66b2b2012-01-23 17:28:51 -08003223
3224 Resources res = mLauncher.getResources();
3225 int duration = res.getInteger(R.integer.config_dropAnimMaxDuration) - 200;
3226
Adam Cohend41fbf52012-02-16 23:53:59 -08003227 // In the case where we've prebound the widget, we remove it from the DragLayer
3228 if (finalView instanceof AppWidgetHostView && external) {
Adam Cohen68f681b2012-05-28 15:01:16 -07003229 Log.d(TAG, "6557954 Animate widget drop, final view is appWidgetHostView");
Adam Cohend41fbf52012-02-16 23:53:59 -08003230 mLauncher.getDragLayer().removeView(finalView);
3231 }
3232 if ((animationType == ANIMATE_INTO_POSITION_AND_RESIZE || external) && finalView != null) {
3233 Bitmap crossFadeBitmap = createWidgetBitmap(info, finalView);
Adam Cohened66b2b2012-01-23 17:28:51 -08003234 dragView.setCrossFadeBitmap(crossFadeBitmap);
3235 dragView.crossFade((int) (duration * 0.8f));
Adam Cohend41fbf52012-02-16 23:53:59 -08003236 } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET && external) {
3237 scaleXY[0] = scaleXY[1] = Math.min(scaleXY[0], scaleXY[1]);
Adam Cohened66b2b2012-01-23 17:28:51 -08003238 }
3239
Adam Cohend41fbf52012-02-16 23:53:59 -08003240 DragLayer dragLayer = mLauncher.getDragLayer();
Winson Chung7bd1bbb2012-02-13 18:29:29 -08003241 if (animationType == CANCEL_TWO_STAGE_WIDGET_DROP_ANIMATION) {
Adam Cohend41fbf52012-02-16 23:53:59 -08003242 mLauncher.getDragLayer().animateViewIntoPosition(dragView, finalPos, 0f, 0.1f, 0.1f,
Adam Cohened66b2b2012-01-23 17:28:51 -08003243 DragLayer.ANIMATION_END_DISAPPEAR, onCompleteRunnable, duration);
3244 } else {
Adam Cohend41fbf52012-02-16 23:53:59 -08003245 int endStyle;
3246 if (animationType == ANIMATE_INTO_POSITION_AND_REMAIN) {
3247 endStyle = DragLayer.ANIMATION_END_REMAIN_VISIBLE;
3248 } else {
3249 endStyle = DragLayer.ANIMATION_END_DISAPPEAR;;
3250 }
3251
3252 Runnable onComplete = new Runnable() {
3253 @Override
3254 public void run() {
3255 if (finalView != null) {
3256 finalView.setVisibility(VISIBLE);
3257 }
3258 if (onCompleteRunnable != null) {
3259 onCompleteRunnable.run();
3260 }
3261 }
3262 };
3263 dragLayer.animateViewIntoPosition(dragView, from.left, from.top, finalPos[0],
3264 finalPos[1], 1, 1, 1, scaleXY[0], scaleXY[1], onComplete, endStyle,
3265 duration, this);
Adam Cohened66b2b2012-01-23 17:28:51 -08003266 }
3267 }
3268
Adam Cohen4b285c52011-07-21 14:24:06 -07003269 public void setFinalTransitionTransform(CellLayout layout) {
3270 if (isSwitchingState()) {
3271 int index = indexOfChild(layout);
3272 mCurrentScaleX = layout.getScaleX();
3273 mCurrentScaleY = layout.getScaleY();
3274 mCurrentTranslationX = layout.getTranslationX();
3275 mCurrentTranslationY = layout.getTranslationY();
3276 mCurrentRotationY = layout.getRotationY();
3277 layout.setScaleX(mNewScaleXs[index]);
3278 layout.setScaleY(mNewScaleYs[index]);
3279 layout.setTranslationX(mNewTranslationXs[index]);
3280 layout.setTranslationY(mNewTranslationYs[index]);
3281 layout.setRotationY(mNewRotationYs[index]);
3282 }
3283 }
3284 public void resetTransitionTransform(CellLayout layout) {
3285 if (isSwitchingState()) {
Adam Cohen4b285c52011-07-21 14:24:06 -07003286 mCurrentScaleX = layout.getScaleX();
3287 mCurrentScaleY = layout.getScaleY();
3288 mCurrentTranslationX = layout.getTranslationX();
3289 mCurrentTranslationY = layout.getTranslationY();
3290 mCurrentRotationY = layout.getRotationY();
3291 layout.setScaleX(mCurrentScaleX);
3292 layout.setScaleY(mCurrentScaleY);
3293 layout.setTranslationX(mCurrentTranslationX);
3294 layout.setTranslationY(mCurrentTranslationY);
3295 layout.setRotationY(mCurrentRotationY);
3296 }
3297 }
3298
Jeff Sharkey70864282009-04-07 21:08:40 -07003299 /**
3300 * Return the current {@link CellLayout}, correctly picking the destination
3301 * screen while a scroll is in progress.
3302 */
Patrick Dubroy5f445422011-02-18 14:35:21 -08003303 public CellLayout getCurrentDropLayout() {
Winson Chung360e63f2012-04-27 13:48:05 -07003304 return (CellLayout) getChildAt(getNextPage());
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003305 }
3306
Jeff Sharkey70864282009-04-07 21:08:40 -07003307 /**
Michael Jurka0280c3b2010-09-17 15:00:07 -07003308 * Return the current CellInfo describing our current drag; this method exists
3309 * so that Launcher can sync this object with the correct info when the activity is created/
3310 * destroyed
3311 *
3312 */
3313 public CellLayout.CellInfo getDragInfo() {
3314 return mDragInfo;
3315 }
3316
3317 /**
Jeff Sharkey70864282009-04-07 21:08:40 -07003318 * Calculate the nearest cell where the given object would be dropped.
Adam Cohene3e27a82011-04-15 12:07:39 -07003319 *
3320 * pixelX and pixelY should be in the coordinate system of layout
Jeff Sharkey70864282009-04-07 21:08:40 -07003321 */
Adam Cohendf035382011-04-11 17:22:04 -07003322 private int[] findNearestArea(int pixelX, int pixelY,
Adam Cohene3e27a82011-04-15 12:07:39 -07003323 int spanX, int spanY, CellLayout layout, int[] recycle) {
Adam Cohendf035382011-04-11 17:22:04 -07003324 return layout.findNearestArea(
Adam Cohene3e27a82011-04-15 12:07:39 -07003325 pixelX, pixelY, spanX, spanY, recycle);
Adam Cohendf035382011-04-11 17:22:04 -07003326 }
3327
Adam Cohencff6af82011-09-13 14:51:53 -07003328 void setup(DragController dragController) {
Michael Jurkac2f7f472010-12-14 15:34:42 -08003329 mSpringLoadedDragController = new SpringLoadedDragController(mLauncher);
Joe Onorato00acb122009-08-04 16:04:30 -04003330 mDragController = dragController;
Michael Jurkad74c9842011-07-10 12:44:21 -07003331
Michael Jurkad74c9842011-07-10 12:44:21 -07003332 // hardware layers on children are enabled on startup, but should be disabled until
3333 // needed
Michael Jurka3a0469d2012-06-21 09:38:41 -07003334 updateChildrenLayersEnabled(false);
Michael Jurkad74c9842011-07-10 12:44:21 -07003335 setWallpaperDimension();
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003336 }
3337
Patrick Dubroye3887cc2011-01-20 10:43:40 -08003338 /**
3339 * Called at the end of a drag which originated on the workspace.
3340 */
Winson Chunga48487a2012-03-20 16:19:37 -07003341 public void onDropCompleted(View target, DragObject d, boolean isFlingToDelete,
3342 boolean success) {
Winson Chungaafa03c2010-06-11 17:34:16 -07003343 if (success) {
Michael Jurkad74c9842011-07-10 12:44:21 -07003344 if (target != this) {
3345 if (mDragInfo != null) {
Winson Chung3d503fb2011-07-13 17:25:49 -07003346 getParentCellLayoutForView(mDragInfo.cell).removeView(mDragInfo.cell);
Michael Jurkad74c9842011-07-10 12:44:21 -07003347 if (mDragInfo.cell instanceof DropTarget) {
3348 mDragController.removeDropTarget((DropTarget) mDragInfo.cell);
3349 }
Joe Onorato00acb122009-08-04 16:04:30 -04003350 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003351 }
Patrick Dubroyce34a972010-10-19 10:34:32 -07003352 } else if (mDragInfo != null) {
Winson Chung3d503fb2011-07-13 17:25:49 -07003353 CellLayout cellLayout;
3354 if (mLauncher.isHotseatLayout(target)) {
3355 cellLayout = mLauncher.getHotseat().getLayout();
3356 } else {
3357 cellLayout = (CellLayout) getChildAt(mDragInfo.screen);
3358 }
3359 cellLayout.onDropChild(mDragInfo.cell);
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003360 }
Adam Cohen36cc09b2011-09-29 17:33:15 -07003361 if (d.cancelled && mDragInfo.cell != null) {
3362 mDragInfo.cell.setVisibility(VISIBLE);
3363 }
Joe Onorato4be866d2010-10-10 11:26:02 -07003364 mDragOutline = null;
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003365 mDragInfo = null;
Winson Chung1afedc32012-01-23 16:14:56 -08003366
3367 // Hide the scrolling indicator after you pick up an item
3368 hideScrollingIndicator(false);
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003369 }
3370
Adam Cohenea889a22012-03-27 16:45:39 -07003371 void updateItemLocationsInDatabase(CellLayout cl) {
Michael Jurkaa52570f2012-03-20 03:18:20 -07003372 int count = cl.getShortcutsAndWidgets().getChildCount();
Adam Cohend3461712012-03-29 17:25:17 -07003373
Adam Cohen482ed822012-03-02 14:15:13 -08003374 int screen = indexOfChild(cl);
Adam Cohend3461712012-03-29 17:25:17 -07003375 int container = Favorites.CONTAINER_DESKTOP;
3376
3377 if (mLauncher.isHotseatLayout(cl)) {
3378 screen = -1;
3379 container = Favorites.CONTAINER_HOTSEAT;
3380 }
3381
Adam Cohen482ed822012-03-02 14:15:13 -08003382 for (int i = 0; i < count; i++) {
Michael Jurkaa52570f2012-03-20 03:18:20 -07003383 View v = cl.getShortcutsAndWidgets().getChildAt(i);
Adam Cohen482ed822012-03-02 14:15:13 -08003384 ItemInfo info = (ItemInfo) v.getTag();
Adam Cohen2acce882012-03-28 19:03:19 -07003385 // Null check required as the AllApps button doesn't have an item info
3386 if (info != null) {
Adam Cohenbebf0422012-04-11 18:06:28 -07003387 LauncherModel.modifyItemInDatabase(mLauncher, info, container, screen, info.cellX,
3388 info.cellY, info.spanX, info.spanY);
Adam Cohen2acce882012-03-28 19:03:19 -07003389 }
Adam Cohen482ed822012-03-02 14:15:13 -08003390 }
3391 }
3392
Winson Chunga48487a2012-03-20 16:19:37 -07003393 @Override
Winson Chung043f2af2012-03-01 16:09:54 -08003394 public boolean supportsFlingToDelete() {
3395 return true;
3396 }
3397
Winson Chunga48487a2012-03-20 16:19:37 -07003398 @Override
3399 public void onFlingToDelete(DragObject d, int x, int y, PointF vec) {
3400 // Do nothing
3401 }
3402
3403 @Override
3404 public void onFlingToDeleteCompleted() {
3405 // Do nothing
3406 }
3407
Michael Jurka0280c3b2010-09-17 15:00:07 -07003408 public boolean isDropEnabled() {
3409 return true;
3410 }
3411
Michael Jurka0142d492010-08-25 17:46:15 -07003412 @Override
3413 protected void onRestoreInstanceState(Parcelable state) {
3414 super.onRestoreInstanceState(state);
3415 Launcher.setScreen(mCurrentPage);
3416 }
3417
3418 @Override
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003419 public void scrollLeft() {
Michael Jurkad74c9842011-07-10 12:44:21 -07003420 if (!isSmall() && !mIsSwitchingState) {
Michael Jurka0142d492010-08-25 17:46:15 -07003421 super.scrollLeft();
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003422 }
Adam Cohen95bb8002011-07-03 23:40:28 -07003423 Folder openFolder = getOpenFolder();
3424 if (openFolder != null) {
3425 openFolder.completeDragExit();
3426 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003427 }
3428
Michael Jurka0142d492010-08-25 17:46:15 -07003429 @Override
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003430 public void scrollRight() {
Michael Jurkad74c9842011-07-10 12:44:21 -07003431 if (!isSmall() && !mIsSwitchingState) {
Michael Jurka0142d492010-08-25 17:46:15 -07003432 super.scrollRight();
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003433 }
Adam Cohen95bb8002011-07-03 23:40:28 -07003434 Folder openFolder = getOpenFolder();
3435 if (openFolder != null) {
3436 openFolder.completeDragExit();
3437 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003438 }
3439
Patrick Dubroy1262e362010-10-06 15:49:50 -07003440 @Override
Winson Chung3e0839e2011-10-03 15:15:18 -07003441 public boolean onEnterScrollArea(int x, int y, int direction) {
Winson Chung1c4cf4a2011-07-29 14:49:10 -07003442 // Ignore the scroll area if we are dragging over the hot seat
Winson Chung10bfc6e2012-03-28 15:41:26 -07003443 boolean isPortrait = !LauncherApplication.isScreenLandscape(getContext());
3444 if (mLauncher.getHotseat() != null && isPortrait) {
Winson Chung1c4cf4a2011-07-29 14:49:10 -07003445 Rect r = new Rect();
3446 mLauncher.getHotseat().getHitRect(r);
3447 if (r.contains(x, y)) {
Winson Chung3e0839e2011-10-03 15:15:18 -07003448 return false;
Winson Chung1c4cf4a2011-07-29 14:49:10 -07003449 }
3450 }
3451
Winson Chung3e0839e2011-10-03 15:15:18 -07003452 boolean result = false;
Michael Jurkad74c9842011-07-10 12:44:21 -07003453 if (!isSmall() && !mIsSwitchingState) {
Michael Jurkad718d6a2010-10-14 15:35:17 -07003454 mInScrollArea = true;
Patrick Dubroy54fa3b92010-11-17 12:18:45 -08003455
Winson Chung360e63f2012-04-27 13:48:05 -07003456 final int page = getNextPage() +
Winson Chungaa15ffe2012-01-18 15:45:28 -08003457 (direction == DragController.SCROLL_LEFT ? -1 : 1);
Adam Cohenc6cc61d2012-04-04 12:47:08 -07003458
3459 // We always want to exit the current layout to ensure parity of enter / exit
3460 setCurrentDropLayout(null);
Patrick Dubroy54fa3b92010-11-17 12:18:45 -08003461
Winson Chungaa15ffe2012-01-18 15:45:28 -08003462 if (0 <= page && page < getChildCount()) {
3463 CellLayout layout = (CellLayout) getChildAt(page);
Adam Cohenc6cc61d2012-04-04 12:47:08 -07003464 setCurrentDragOverlappingLayout(layout);
Winson Chungc07918d2011-07-01 15:35:26 -07003465
3466 // Workspace is responsible for drawing the edge glow on adjacent pages,
3467 // so we need to redraw the workspace when this may have changed.
3468 invalidate();
Winson Chung3e0839e2011-10-03 15:15:18 -07003469 result = true;
Michael Jurkad718d6a2010-10-14 15:35:17 -07003470 }
Patrick Dubroy1262e362010-10-06 15:49:50 -07003471 }
Winson Chung3e0839e2011-10-03 15:15:18 -07003472 return result;
Patrick Dubroy1262e362010-10-06 15:49:50 -07003473 }
3474
3475 @Override
Winson Chung3e0839e2011-10-03 15:15:18 -07003476 public boolean onExitScrollArea() {
3477 boolean result = false;
Michael Jurkad718d6a2010-10-14 15:35:17 -07003478 if (mInScrollArea) {
Adam Cohenc6cc61d2012-04-04 12:47:08 -07003479 invalidate();
3480 CellLayout layout = getCurrentDropLayout();
3481 setCurrentDropLayout(layout);
3482 setCurrentDragOverlappingLayout(layout);
3483
Adam Cohen8a18afc2011-12-13 15:57:01 -08003484 result = true;
Winson Chungc07918d2011-07-01 15:35:26 -07003485 mInScrollArea = false;
Patrick Dubroy1262e362010-10-06 15:49:50 -07003486 }
Winson Chung3e0839e2011-10-03 15:15:18 -07003487 return result;
Patrick Dubroy1262e362010-10-06 15:49:50 -07003488 }
3489
Winson Chungc07918d2011-07-01 15:35:26 -07003490 private void onResetScrollArea() {
Adam Cohenc6cc61d2012-04-04 12:47:08 -07003491 setCurrentDragOverlappingLayout(null);
Winson Chungc07918d2011-07-01 15:35:26 -07003492 mInScrollArea = false;
3493 }
3494
Winson Chung3d503fb2011-07-13 17:25:49 -07003495 /**
3496 * Returns a specific CellLayout
3497 */
3498 CellLayout getParentCellLayoutForView(View v) {
3499 ArrayList<CellLayout> layouts = getWorkspaceAndHotseatCellLayouts();
3500 for (CellLayout layout : layouts) {
Michael Jurkaa52570f2012-03-20 03:18:20 -07003501 if (layout.getShortcutsAndWidgets().indexOfChild(v) > -1) {
Winson Chung3d503fb2011-07-13 17:25:49 -07003502 return layout;
3503 }
3504 }
3505 return null;
3506 }
3507
3508 /**
3509 * Returns a list of all the CellLayouts in the workspace.
3510 */
3511 ArrayList<CellLayout> getWorkspaceAndHotseatCellLayouts() {
3512 ArrayList<CellLayout> layouts = new ArrayList<CellLayout>();
3513 int screenCount = getChildCount();
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003514 for (int screen = 0; screen < screenCount; screen++) {
Winson Chung3d503fb2011-07-13 17:25:49 -07003515 layouts.add(((CellLayout) getChildAt(screen)));
3516 }
3517 if (mLauncher.getHotseat() != null) {
3518 layouts.add(mLauncher.getHotseat().getLayout());
3519 }
3520 return layouts;
3521 }
3522
3523 /**
3524 * We should only use this to search for specific children. Do not use this method to modify
Michael Jurkaa52570f2012-03-20 03:18:20 -07003525 * ShortcutsAndWidgetsContainer directly. Includes ShortcutAndWidgetContainers from
3526 * the hotseat and workspace pages
Winson Chung3d503fb2011-07-13 17:25:49 -07003527 */
Michael Jurkaa52570f2012-03-20 03:18:20 -07003528 ArrayList<ShortcutAndWidgetContainer> getAllShortcutAndWidgetContainers() {
3529 ArrayList<ShortcutAndWidgetContainer> childrenLayouts =
3530 new ArrayList<ShortcutAndWidgetContainer>();
Winson Chung3d503fb2011-07-13 17:25:49 -07003531 int screenCount = getChildCount();
3532 for (int screen = 0; screen < screenCount; screen++) {
Michael Jurkaa52570f2012-03-20 03:18:20 -07003533 childrenLayouts.add(((CellLayout) getChildAt(screen)).getShortcutsAndWidgets());
Winson Chung3d503fb2011-07-13 17:25:49 -07003534 }
3535 if (mLauncher.getHotseat() != null) {
Michael Jurkaa52570f2012-03-20 03:18:20 -07003536 childrenLayouts.add(mLauncher.getHotseat().getLayout().getShortcutsAndWidgets());
Winson Chung3d503fb2011-07-13 17:25:49 -07003537 }
3538 return childrenLayouts;
3539 }
3540
3541 public Folder getFolderForTag(Object tag) {
Michael Jurkaa52570f2012-03-20 03:18:20 -07003542 ArrayList<ShortcutAndWidgetContainer> childrenLayouts =
3543 getAllShortcutAndWidgetContainers();
3544 for (ShortcutAndWidgetContainer layout: childrenLayouts) {
Winson Chung3d503fb2011-07-13 17:25:49 -07003545 int count = layout.getChildCount();
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003546 for (int i = 0; i < count; i++) {
Winson Chung3d503fb2011-07-13 17:25:49 -07003547 View child = layout.getChildAt(i);
Winson Chung3d503fb2011-07-13 17:25:49 -07003548 if (child instanceof Folder) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003549 Folder f = (Folder) child;
Winson Chungaafa03c2010-06-11 17:34:16 -07003550 if (f.getInfo() == tag && f.getInfo().opened) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003551 return f;
3552 }
3553 }
3554 }
3555 }
3556 return null;
3557 }
3558
3559 public View getViewForTag(Object tag) {
Michael Jurkaa52570f2012-03-20 03:18:20 -07003560 ArrayList<ShortcutAndWidgetContainer> childrenLayouts =
3561 getAllShortcutAndWidgetContainers();
3562 for (ShortcutAndWidgetContainer layout: childrenLayouts) {
Winson Chung3d503fb2011-07-13 17:25:49 -07003563 int count = layout.getChildCount();
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003564 for (int i = 0; i < count; i++) {
Winson Chung3d503fb2011-07-13 17:25:49 -07003565 View child = layout.getChildAt(i);
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003566 if (child.getTag() == tag) {
3567 return child;
3568 }
3569 }
3570 }
3571 return null;
3572 }
3573
Adam Cohendf035382011-04-11 17:22:04 -07003574 void clearDropTargets() {
Michael Jurkaa52570f2012-03-20 03:18:20 -07003575 ArrayList<ShortcutAndWidgetContainer> childrenLayouts =
3576 getAllShortcutAndWidgetContainers();
3577 for (ShortcutAndWidgetContainer layout: childrenLayouts) {
Adam Cohendf035382011-04-11 17:22:04 -07003578 int childCount = layout.getChildCount();
3579 for (int j = 0; j < childCount; j++) {
3580 View v = layout.getChildAt(j);
3581 if (v instanceof DropTarget) {
3582 mDragController.removeDropTarget((DropTarget) v);
3583 }
3584 }
3585 }
3586 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003587
Winson Chungcd810732012-06-18 16:45:43 -07003588 void removeItems(final ArrayList<String> packages) {
Joe Onorato64e6be72010-03-05 15:05:52 -05003589 final HashSet<String> packageNames = new HashSet<String>();
Winson Chungcd810732012-06-18 16:45:43 -07003590 packageNames.addAll(packages);
Joe Onorato64e6be72010-03-05 15:05:52 -05003591
Winson Chung3d503fb2011-07-13 17:25:49 -07003592 ArrayList<CellLayout> cellLayouts = getWorkspaceAndHotseatCellLayouts();
3593 for (final CellLayout layoutParent: cellLayouts) {
Michael Jurkaa52570f2012-03-20 03:18:20 -07003594 final ViewGroup layout = layoutParent.getShortcutsAndWidgets();
Romain Guy574d20e2009-06-01 15:34:04 -07003595
Romain Guy629de3e2010-01-13 12:20:59 -08003596 // Avoid ANRs by treating each screen separately
3597 post(new Runnable() {
3598 public void run() {
3599 final ArrayList<View> childrenToRemove = new ArrayList<View>();
3600 childrenToRemove.clear();
Winson Chungaafa03c2010-06-11 17:34:16 -07003601
Romain Guy629de3e2010-01-13 12:20:59 -08003602 int childCount = layout.getChildCount();
3603 for (int j = 0; j < childCount; j++) {
3604 final View view = layout.getChildAt(j);
3605 Object tag = view.getTag();
Winson Chungaafa03c2010-06-11 17:34:16 -07003606
Joe Onorato0589f0f2010-02-08 13:44:00 -08003607 if (tag instanceof ShortcutInfo) {
3608 final ShortcutInfo info = (ShortcutInfo) tag;
Romain Guy629de3e2010-01-13 12:20:59 -08003609 final Intent intent = info.intent;
3610 final ComponentName name = intent.getComponent();
Winson Chungaafa03c2010-06-11 17:34:16 -07003611
Winson Chung11a49372012-04-27 15:12:38 -07003612 if (name != null) {
Winson Chung2efec4e2012-05-03 12:31:48 -07003613 if (packageNames.contains(name.getPackageName())) {
3614 LauncherModel.deleteItemFromDatabase(mLauncher, info);
3615 childrenToRemove.add(view);
Joe Onorato64e6be72010-03-05 15:05:52 -05003616 }
Romain Guy629de3e2010-01-13 12:20:59 -08003617 }
Adam Cohendf2cc412011-04-27 16:56:57 -07003618 } else if (tag instanceof FolderInfo) {
3619 final FolderInfo info = (FolderInfo) tag;
Joe Onorato0589f0f2010-02-08 13:44:00 -08003620 final ArrayList<ShortcutInfo> contents = info.contents;
Romain Guy629de3e2010-01-13 12:20:59 -08003621 final int contentsCount = contents.size();
Adam Cohendf1e4e82011-06-24 15:57:39 -07003622 final ArrayList<ShortcutInfo> appsToRemoveFromFolder =
3623 new ArrayList<ShortcutInfo>();
Winson Chungaafa03c2010-06-11 17:34:16 -07003624
Romain Guy629de3e2010-01-13 12:20:59 -08003625 for (int k = 0; k < contentsCount; k++) {
Joe Onorato0589f0f2010-02-08 13:44:00 -08003626 final ShortcutInfo appInfo = contents.get(k);
Romain Guy629de3e2010-01-13 12:20:59 -08003627 final Intent intent = appInfo.intent;
3628 final ComponentName name = intent.getComponent();
Winson Chungaafa03c2010-06-11 17:34:16 -07003629
Winson Chung11a49372012-04-27 15:12:38 -07003630 if (name != null) {
Winson Chung2efec4e2012-05-03 12:31:48 -07003631 if (packageNames.contains(name.getPackageName())) {
3632 appsToRemoveFromFolder.add(appInfo);
Joe Onorato64e6be72010-03-05 15:05:52 -05003633 }
Romain Guy629de3e2010-01-13 12:20:59 -08003634 }
3635 }
Adam Cohendf1e4e82011-06-24 15:57:39 -07003636 for (ShortcutInfo item: appsToRemoveFromFolder) {
3637 info.remove(item);
3638 LauncherModel.deleteItemFromDatabase(mLauncher, item);
Romain Guy629de3e2010-01-13 12:20:59 -08003639 }
Romain Guy629de3e2010-01-13 12:20:59 -08003640 } else if (tag instanceof LauncherAppWidgetInfo) {
3641 final LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) tag;
Winson Chung11a49372012-04-27 15:12:38 -07003642 final ComponentName provider = info.providerName;
Daniel Sandlere1cc6c32010-05-07 11:49:29 -04003643 if (provider != null) {
Winson Chung2efec4e2012-05-03 12:31:48 -07003644 if (packageNames.contains(provider.getPackageName())) {
3645 LauncherModel.deleteItemFromDatabase(mLauncher, info);
3646 childrenToRemove.add(view);
Joe Onorato64e6be72010-03-05 15:05:52 -05003647 }
Romain Guy629de3e2010-01-13 12:20:59 -08003648 }
Romain Guy574d20e2009-06-01 15:34:04 -07003649 }
3650 }
Winson Chungaafa03c2010-06-11 17:34:16 -07003651
Romain Guy629de3e2010-01-13 12:20:59 -08003652 childCount = childrenToRemove.size();
3653 for (int j = 0; j < childCount; j++) {
3654 View child = childrenToRemove.get(j);
Winson Chung7a25a9e2011-01-30 13:33:56 -08003655 // Note: We can not remove the view directly from CellLayoutChildren as this
3656 // does not re-mark the spaces as unoccupied.
3657 layoutParent.removeViewInLayout(child);
Romain Guy629de3e2010-01-13 12:20:59 -08003658 if (child instanceof DropTarget) {
3659 mDragController.removeDropTarget((DropTarget)child);
3660 }
Romain Guy574d20e2009-06-01 15:34:04 -07003661 }
Winson Chungaafa03c2010-06-11 17:34:16 -07003662
Romain Guy629de3e2010-01-13 12:20:59 -08003663 if (childCount > 0) {
3664 layout.requestLayout();
3665 layout.invalidate();
Romain Guy5c16f3e2010-01-12 17:24:58 -08003666 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003667 }
Romain Guy629de3e2010-01-13 12:20:59 -08003668 });
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003669 }
Winson Chung2efec4e2012-05-03 12:31:48 -07003670
Winson Chung42490a52012-06-28 12:13:51 -07003671 // Clean up new-apps animation list
Winson Chung2efec4e2012-05-03 12:31:48 -07003672 post(new Runnable() {
3673 @Override
3674 public void run() {
3675 String spKey = LauncherApplication.getSharedPreferencesKey();
3676 SharedPreferences sp = getContext().getSharedPreferences(spKey,
3677 Context.MODE_PRIVATE);
3678 Set<String> newApps = sp.getStringSet(InstallShortcutReceiver.NEW_APPS_LIST_KEY,
3679 null);
3680
Winson Chung42490a52012-06-28 12:13:51 -07003681 // Remove all queued items that match the same package
3682 if (newApps != null) {
3683 synchronized (newApps) {
3684 Iterator<String> iter = newApps.iterator();
3685 while (iter.hasNext()) {
3686 try {
3687 Intent intent = Intent.parseUri(iter.next(), 0);
3688 String pn = ItemInfo.getPackageName(intent);
3689 if (packageNames.contains(pn)) {
3690 iter.remove();
3691 }
3692 } catch (URISyntaxException e) {}
Winson Chung2efec4e2012-05-03 12:31:48 -07003693 }
3694 }
3695 }
3696 }
3697 });
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003698 }
The Android Open Source Projectf96811c2009-03-18 17:39:48 -07003699
Joe Onorato64e6be72010-03-05 15:05:52 -05003700 void updateShortcuts(ArrayList<ApplicationInfo> apps) {
Michael Jurkaa52570f2012-03-20 03:18:20 -07003701 ArrayList<ShortcutAndWidgetContainer> childrenLayouts = getAllShortcutAndWidgetContainers();
3702 for (ShortcutAndWidgetContainer layout: childrenLayouts) {
The Android Open Source Projectf96811c2009-03-18 17:39:48 -07003703 int childCount = layout.getChildCount();
3704 for (int j = 0; j < childCount; j++) {
3705 final View view = layout.getChildAt(j);
3706 Object tag = view.getTag();
Joe Onorato0589f0f2010-02-08 13:44:00 -08003707 if (tag instanceof ShortcutInfo) {
Michael Jurkae384aff2012-03-09 15:59:25 -08003708 ShortcutInfo info = (ShortcutInfo) tag;
The Android Open Source Projectf96811c2009-03-18 17:39:48 -07003709 // We need to check for ACTION_MAIN otherwise getComponent() might
3710 // return null for some shortcuts (for instance, for shortcuts to
3711 // web pages.)
3712 final Intent intent = info.intent;
3713 final ComponentName name = intent.getComponent();
3714 if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION &&
Joe Onorato64e6be72010-03-05 15:05:52 -05003715 Intent.ACTION_MAIN.equals(intent.getAction()) && name != null) {
3716 final int appCount = apps.size();
Winson Chungaafa03c2010-06-11 17:34:16 -07003717 for (int k = 0; k < appCount; k++) {
Joe Onorato64e6be72010-03-05 15:05:52 -05003718 ApplicationInfo app = apps.get(k);
3719 if (app.componentName.equals(name)) {
Michael Jurkae384aff2012-03-09 15:59:25 -08003720 BubbleTextView shortcut = (BubbleTextView) view;
3721 info.updateIcon(mIconCache);
3722 info.title = app.title.toString();
3723 shortcut.applyFromShortcutInfo(info, mIconCache);
3724 }
Joe Onorato64e6be72010-03-05 15:05:52 -05003725 }
The Android Open Source Projectf96811c2009-03-18 17:39:48 -07003726 }
3727 }
3728 }
3729 }
3730 }
3731
Joe Onorato14f122b2009-11-19 14:06:36 -08003732 void moveToDefaultScreen(boolean animate) {
Winson Chungde1af762011-07-21 16:44:07 -07003733 if (!isSmall()) {
3734 if (animate) {
3735 snapToPage(mDefaultPage);
3736 } else {
3737 setCurrentPage(mDefaultPage);
3738 }
Joe Onoratoc45b1682010-01-11 18:48:40 -05003739 }
Michael Jurka0142d492010-08-25 17:46:15 -07003740 getChildAt(mDefaultPage).requestFocus();
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003741 }
3742
Michael Jurka0142d492010-08-25 17:46:15 -07003743 @Override
3744 public void syncPages() {
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003745 }
Michael Jurka0142d492010-08-25 17:46:15 -07003746
3747 @Override
Winson Chungf314b0e2011-08-16 11:54:27 -07003748 public void syncPageItems(int page, boolean immediate) {
Michael Jurka0142d492010-08-25 17:46:15 -07003749 }
Winson Chung6a0f57d2011-06-29 20:10:49 -07003750
3751 @Override
3752 protected String getCurrentPageDescription() {
3753 int page = (mNextPage != INVALID_PAGE) ? mNextPage : mCurrentPage;
Michael Jurka8b805b12012-04-18 14:23:14 -07003754 return String.format(getContext().getString(R.string.workspace_scroll_format),
Winson Chung6a0f57d2011-06-29 20:10:49 -07003755 page + 1, getChildCount());
3756 }
Adam Cohen8dfcba42011-07-07 16:38:18 -07003757
3758 public void getLocationInDragLayer(int[] loc) {
3759 mLauncher.getDragLayer().getLocationInDragLayer(this, loc);
3760 }
Winson Chung32174c82011-07-19 15:47:55 -07003761
Adam Cohen21b41102011-11-01 17:29:52 -07003762 void setFadeForOverScroll(float fade) {
3763 if (!isScrollingIndicatorEnabled()) return;
3764
3765 mOverscrollFade = fade;
3766 float reducedFade = 0.5f + 0.5f * (1 - fade);
3767 final ViewGroup parent = (ViewGroup) getParent();
Winson Chunge96e5cb2011-11-28 13:02:56 -08003768 final ImageView qsbDivider = (ImageView) (parent.findViewById(R.id.qsb_divider));
Adam Cohen21b41102011-11-01 17:29:52 -07003769 final ImageView dockDivider = (ImageView) (parent.findViewById(R.id.dock_divider));
Michael Jurkaafaa0502011-12-13 18:22:50 -08003770 final View scrollIndicator = getScrollingIndicator();
Adam Cohen21b41102011-11-01 17:29:52 -07003771
3772 cancelScrollingIndicatorAnimations();
Winson Chunge96e5cb2011-11-28 13:02:56 -08003773 if (qsbDivider != null) qsbDivider.setAlpha(reducedFade);
3774 if (dockDivider != null) dockDivider.setAlpha(reducedFade);
Adam Cohen21b41102011-11-01 17:29:52 -07003775 scrollIndicator.setAlpha(1 - fade);
3776 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003777}