blob: 41f0242c2cbdad082f3d66b1abc3a5462697af13 [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
Daniel Sandler325dc232013-06-05 22:57:57 -040017package com.android.launcher3;
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;
Adam Cohen99894d92013-06-14 11:22:59 -070032import android.content.pm.ResolveInfo;
Patrick Dubroy7247f632010-08-04 16:02:59 -070033import android.content.res.Resources;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080034import android.content.res.TypedArray;
Joe Onorato4be866d2010-10-10 11:26:02 -070035import android.graphics.Bitmap;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080036import android.graphics.Canvas;
Michael Jurkaa63c4522010-08-19 13:52:27 -070037import android.graphics.Matrix;
Winson Chungb8c69f32011-10-19 21:36:08 -070038import android.graphics.Point;
Winson Chung043f2af2012-03-01 16:09:54 -080039import android.graphics.PointF;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080040import android.graphics.Rect;
Joe Onorato4be866d2010-10-10 11:26:02 -070041import android.graphics.Region.Op;
The Android Open Source Projectf96811c2009-03-18 17:39:48 -070042import android.graphics.drawable.Drawable;
Adam Cohen99894d92013-06-14 11:22:59 -070043import android.net.Uri;
Joe Onorato956091b2010-02-19 12:47:40 -080044import android.os.IBinder;
Adam Powell495f2892010-04-16 16:40:55 -070045import android.os.Parcelable;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080046import android.util.AttributeSet;
Daniel Sandler291ad122010-05-24 16:03:53 -040047import android.util.Log;
Adam Cohen1462de32012-07-24 22:34:36 -070048import android.util.SparseArray;
Winson Chunga34abf82010-11-12 12:10:35 -080049import android.view.Display;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080050import android.view.MotionEvent;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080051import android.view.View;
Winson Chung6e314082011-01-27 16:46:51 -080052import android.view.ViewGroup;
Patrick Dubroycd68ff52010-10-28 17:57:05 -070053import android.view.animation.DecelerateInterpolator;
Winson Chunga6427b12011-07-27 10:53:39 -070054import android.widget.ImageView;
The Android Open Source Projectf96811c2009-03-18 17:39:48 -070055import android.widget.TextView;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080056
Daniel Sandler325dc232013-06-05 22:57:57 -040057import com.android.launcher3.R;
58import com.android.launcher3.FolderIcon.FolderRingAnimator;
59import com.android.launcher3.LauncherSettings.Favorites;
Romain Guyedcce092010-03-04 13:03:17 -080060
Winson Chung2efec4e2012-05-03 12:31:48 -070061import java.net.URISyntaxException;
Adam Cohen716b51e2011-06-30 12:09:54 -070062import java.util.ArrayList;
63import java.util.HashSet;
Michael Jurka8bd65f52012-06-25 14:56:22 -070064import java.util.Iterator;
Adam Cohen99894d92013-06-14 11:22:59 -070065import java.util.List;
Winson Chung2efec4e2012-05-03 12:31:48 -070066import java.util.Set;
Adam Cohen716b51e2011-06-30 12:09:54 -070067
The Android Open Source Project31dd5032009-03-03 19:32:27 -080068/**
Michael Jurka0142d492010-08-25 17:46:15 -070069 * The workspace is a wide area with a wallpaper and a finite number of pages.
70 * Each page contains a number of icons, folders or widgets the user can
Winson Chungaafa03c2010-06-11 17:34:16 -070071 * interact with. A workspace is meant to be used with a fixed width only.
The Android Open Source Project31dd5032009-03-03 19:32:27 -080072 */
Michael Jurka0142d492010-08-25 17:46:15 -070073public class Workspace extends SmoothPagedView
Michael Jurkad74c9842011-07-10 12:44:21 -070074 implements DropTarget, DragSource, DragScroller, View.OnTouchListener,
Michael Jurka8b805b12012-04-18 14:23:14 -070075 DragController.DragListener, LauncherTransitionable, ViewGroup.OnHierarchyChangeListener {
Joe Onorato3a8820b2009-11-10 15:06:42 -080076 private static final String TAG = "Launcher.Workspace";
Michael Jurka0142d492010-08-25 17:46:15 -070077
Adam Cohenf34bab52010-09-30 14:11:56 -070078 // Y rotation to apply to the workspace screens
Adam Cohenb5ba0972011-09-07 18:02:31 -070079 private static final float WORKSPACE_OVERSCROLL_ROTATION = 24f;
Adam Cohena985e592010-09-09 11:23:48 -070080
Adam Cohen68d73932010-11-15 10:50:58 -080081 private static final int CHILDREN_OUTLINE_FADE_OUT_DELAY = 0;
82 private static final int CHILDREN_OUTLINE_FADE_OUT_DURATION = 375;
Winson Chung9171e6d2010-11-17 17:39:27 -080083 private static final int CHILDREN_OUTLINE_FADE_IN_DURATION = 100;
Adam Cohenf34bab52010-09-30 14:11:56 -070084
Winson Chungf135c6c2010-11-18 16:32:08 -080085 private static final int BACKGROUND_FADE_OUT_DURATION = 350;
Adam Cohened51cc92011-08-01 20:28:08 -070086 private static final int ADJACENT_SCREEN_DROP_DURATION = 300;
Adam Cohen265b9a62011-12-07 14:37:18 -080087 private static final int FLING_THRESHOLD_VELOCITY = 500;
Adam Cohened51cc92011-08-01 20:28:08 -070088
Winson Chung9171e6d2010-11-17 17:39:27 -080089 // These animators are used to fade the children's outlines
90 private ObjectAnimator mChildrenOutlineFadeInAnimation;
91 private ObjectAnimator mChildrenOutlineFadeOutAnimation;
92 private float mChildrenOutlineAlpha = 0;
93
94 // These properties refer to the background protection gradient used for AllApps and Customize
Michael Jurkae0f5a612011-02-07 16:45:41 -080095 private ValueAnimator mBackgroundFadeInAnimation;
96 private ValueAnimator mBackgroundFadeOutAnimation;
Winson Chung9171e6d2010-11-17 17:39:27 -080097 private Drawable mBackground;
Michael Jurka25356e72011-03-03 14:53:11 -080098 boolean mDrawBackground = true;
Adam Cohenf34bab52010-09-30 14:11:56 -070099 private float mBackgroundAlpha = 0;
100
Adam Cohenbeff8c62011-08-31 17:46:01 -0700101 private float mWallpaperScrollRatio = 1.0f;
Michael Jurka37990b42012-09-25 15:14:30 -0700102 private int mOriginalPageSpacing;
Adam Cohenbeff8c62011-08-31 17:46:01 -0700103
Dianne Hackborn8f573952009-08-10 23:21:09 -0700104 private final WallpaperManager mWallpaperManager;
Michael Jurka9c6fbed2011-03-02 17:41:34 -0800105 private IBinder mWindowToken;
Michael Jurka16706982011-09-26 16:39:22 -0700106 private static final float WALLPAPER_SCREENS_SPAN = 2f;
Winson Chungaafa03c2010-06-11 17:34:16 -0700107
Michael Jurka0142d492010-08-25 17:46:15 -0700108 private int mDefaultPage;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800109
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800110 /**
111 * CellInfo for the cell that is currently being dragged
112 */
113 private CellLayout.CellInfo mDragInfo;
Winson Chungaafa03c2010-06-11 17:34:16 -0700114
Jeff Sharkey70864282009-04-07 21:08:40 -0700115 /**
116 * Target drop area calculated during last acceptDrop call.
117 */
Adam Cohenc0dcf592011-06-01 15:30:43 -0700118 private int[] mTargetCell = new int[2];
Adam Cohenc6cc61d2012-04-04 12:47:08 -0700119 private int mDragOverX = -1;
120 private int mDragOverY = -1;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800121
Adam Cohena897f392012-04-27 18:12:05 -0700122 static Rect mLandscapeCellLayoutMetrics = null;
123 static Rect mPortraitCellLayoutMetrics = null;
124
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700125 /**
126 * The CellLayout that is currently being dragged over
127 */
128 private CellLayout mDragTargetLayout = null;
Adam Cohenc6cc61d2012-04-04 12:47:08 -0700129 /**
130 * The CellLayout that we will show as glowing
131 */
132 private CellLayout mDragOverlappingLayout = null;
133
134 /**
135 * The CellLayout which will be dropped to
136 */
137 private CellLayout mDropToLayout = null;
138
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800139 private Launcher mLauncher;
Joe Onorato0589f0f2010-02-08 13:44:00 -0800140 private IconCache mIconCache;
Joe Onorato00acb122009-08-04 16:04:30 -0400141 private DragController mDragController;
Winson Chungaafa03c2010-06-11 17:34:16 -0700142
Michael Jurka4516c112010-10-07 15:13:47 -0700143 // These are temporary variables to prevent having to allocate a new object just to
144 // 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 -0800145 private int[] mTempCell = new int[2];
Jeff Sharkey70864282009-04-07 21:08:40 -0700146 private int[] mTempEstimate = new int[2];
Adam Cohene3e27a82011-04-15 12:07:39 -0700147 private float[] mDragViewVisualCenter = new float[2];
Michael Jurkaa63c4522010-08-19 13:52:27 -0700148 private float[] mTempDragCoordinates = new float[2];
Michael Jurka4516c112010-10-07 15:13:47 -0700149 private float[] mTempCellLayoutCenterCoordinates = new float[2];
Michael Jurkaa63c4522010-08-19 13:52:27 -0700150 private float[] mTempDragBottomRightCoordinates = new float[2];
Michael Jurka0280c3b2010-09-17 15:00:07 -0700151 private Matrix mTempInverseMatrix = new Matrix();
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800152
Michael Jurkac2f7f472010-12-14 15:34:42 -0800153 private SpringLoadedDragController mSpringLoadedDragController;
Winson Chungb26f3d62011-06-02 10:49:29 -0700154 private float mSpringLoadedShrinkFactor;
Michael Jurkad3ef3062010-11-23 16:23:58 -0800155
Adam Cohend22015c2010-07-26 22:02:18 -0700156 private static final int DEFAULT_CELL_COUNT_X = 4;
157 private static final int DEFAULT_CELL_COUNT_Y = 4;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800158
Patrick Dubroy1262e362010-10-06 15:49:50 -0700159 // State variable that indicates whether the pages are small (ie when you're
Michael Jurkadee05892010-07-27 10:01:56 -0700160 // in all apps or customize mode)
Michael Jurkad74c9842011-07-10 12:44:21 -0700161
162 enum State { NORMAL, SPRING_LOADED, SMALL };
Adam Cohen7777d962011-08-18 18:58:38 -0700163 private State mState = State.NORMAL;
Michael Jurkad74c9842011-07-10 12:44:21 -0700164 private boolean mIsSwitchingState = false;
Michael Jurkad74c9842011-07-10 12:44:21 -0700165
Michael Jurkad74c9842011-07-10 12:44:21 -0700166 boolean mAnimatingViewIntoPlace = false;
167 boolean mIsDragOccuring = false;
168 boolean mChildrenLayersEnabled = true;
Michael Jurkadee05892010-07-27 10:01:56 -0700169
Patrick Dubroy54fa3b92010-11-17 12:18:45 -0800170 /** Is the user is dragging an item near the edge of a page? */
Patrick Dubroy1262e362010-10-06 15:49:50 -0700171 private boolean mInScrollArea = false;
172
Daniel Sandlere572fe42013-06-12 22:46:02 -0400173 private final HolographicOutlineHelper mOutlineHelper = HolographicOutlineHelper.obtain();
Joe Onorato4be866d2010-10-10 11:26:02 -0700174 private Bitmap mDragOutline = null;
Patrick Dubroy8e58e912010-10-14 13:21:48 -0700175 private final Rect mTempRect = new Rect();
176 private final int[] mTempXY = new int[2];
Michael Jurkad51f33a2012-06-28 15:35:26 -0700177 private int[] mTempVisiblePagesRange = new int[2];
Adam Cohen21b41102011-11-01 17:29:52 -0700178 private float mOverscrollFade = 0;
Michael Jurkab06d95f2012-04-02 06:26:53 -0700179 private boolean mOverscrollTransformsSet;
Michael Jurkaf8304f02012-04-26 13:33:26 -0700180 public static final int DRAG_BITMAP_PADDING = 2;
Michael Jurka869390b2012-05-06 15:55:19 -0700181 private boolean mWorkspaceFadeInAdjacentScreens;
Joe Onorato4be866d2010-10-10 11:26:02 -0700182
Michael Jurkac5b262c2011-01-12 20:24:50 -0800183 enum WallpaperVerticalOffset { TOP, MIDDLE, BOTTOM };
184 int mWallpaperWidth;
185 int mWallpaperHeight;
Michael Jurkaab1983f2011-01-18 15:50:17 -0800186 WallpaperOffsetInterpolator mWallpaperOffset;
Michael Jurkac5b262c2011-01-12 20:24:50 -0800187 boolean mUpdateWallpaperOffsetImmediately = false;
Adam Cohen26976d92011-03-22 15:33:33 -0700188 private Runnable mDelayedResizeRunnable;
Winson Chungf0c6ae02012-03-21 16:10:31 -0700189 private Runnable mDelayedSnapToPageRunnable;
Michael Jurka84f2ce72012-04-13 15:08:01 -0700190 private Point mDisplaySize = new Point();
Michael Jurka95515372012-02-29 14:13:01 -0800191 private boolean mIsStaticWallpaper;
Adam Cohencff6af82011-09-13 14:51:53 -0700192 private int mWallpaperTravelWidth;
Winson Chung8aad6102012-05-11 16:27:49 -0700193 private int mSpringLoadedPageSpacing;
Adam Cohen94309882012-06-08 16:24:56 -0700194 private int mCameraDistance;
Michael Jurkac5b262c2011-01-12 20:24:50 -0800195
Adam Cohen19072da2011-05-31 14:30:45 -0700196 // Variables relating to the creation of user folders by hovering shortcuts over shortcuts
Adam Cohen482ed822012-03-02 14:15:13 -0800197 private static final int FOLDER_CREATION_TIMEOUT = 0;
198 private static final int REORDER_TIMEOUT = 250;
Adam Cohen19072da2011-05-31 14:30:45 -0700199 private final Alarm mFolderCreationAlarm = new Alarm();
Adam Cohen482ed822012-03-02 14:15:13 -0800200 private final Alarm mReorderAlarm = new Alarm();
Adam Cohen19072da2011-05-31 14:30:45 -0700201 private FolderRingAnimator mDragFolderRingAnimator = null;
Adam Cohenc6cc61d2012-04-04 12:47:08 -0700202 private FolderIcon mDragOverFolderIcon = null;
Adam Cohen19072da2011-05-31 14:30:45 -0700203 private boolean mCreateUserFolderOnDrop = false;
Adam Cohenc6cc61d2012-04-04 12:47:08 -0700204 private boolean mAddToExistingFolderOnDrop = false;
205 private DropTarget.DragEnforcer mDragEnforcer;
Adam Cohen3aff81c2012-05-16 21:01:01 -0700206 private float mMaxDistanceForFolderCreation;
Adam Cohen073a46f2011-05-17 16:28:09 -0700207
Adam Cohenf8d28232011-02-01 21:47:00 -0800208 // Variables relating to touch disambiguation (scrolling workspace vs. scrolling a widget)
209 private float mXDown;
210 private float mYDown;
211 final static float START_DAMPING_TOUCH_SLOP_ANGLE = (float) Math.PI / 6;
212 final static float MAX_SWIPE_ANGLE = (float) Math.PI / 3;
213 final static float TOUCH_SLOP_DAMPING_FACTOR = 4;
214
Adam Cohened66b2b2012-01-23 17:28:51 -0800215 // Relating to the animation of items being dropped externally
Adam Cohend41fbf52012-02-16 23:53:59 -0800216 public static final int ANIMATE_INTO_POSITION_AND_DISAPPEAR = 0;
217 public static final int ANIMATE_INTO_POSITION_AND_REMAIN = 1;
218 public static final int ANIMATE_INTO_POSITION_AND_RESIZE = 2;
219 public static final int COMPLETE_TWO_STAGE_WIDGET_DROP_ANIMATION = 3;
220 public static final int CANCEL_TWO_STAGE_WIDGET_DROP_ANIMATION = 4;
Adam Cohened66b2b2012-01-23 17:28:51 -0800221
Adam Cohen482ed822012-03-02 14:15:13 -0800222 // Related to dragging, folder creation and reordering
223 private static final int DRAG_MODE_NONE = 0;
224 private static final int DRAG_MODE_CREATE_FOLDER = 1;
225 private static final int DRAG_MODE_ADD_TO_FOLDER = 2;
226 private static final int DRAG_MODE_REORDER = 3;
227 private int mDragMode = DRAG_MODE_NONE;
228 private int mLastReorderX = -1;
229 private int mLastReorderY = -1;
230
Adam Cohen1462de32012-07-24 22:34:36 -0700231 private SparseArray<Parcelable> mSavedStates;
232 private final ArrayList<Integer> mRestoredPages = new ArrayList<Integer>();
233
Adam Cohen4b285c52011-07-21 14:24:06 -0700234 // These variables are used for storing the initial and final values during workspace animations
Adam Cohened51cc92011-08-01 20:28:08 -0700235 private int mSavedScrollX;
236 private float mSavedRotationY;
237 private float mSavedTranslationX;
Adam Cohen4b285c52011-07-21 14:24:06 -0700238 private float mCurrentScaleX;
239 private float mCurrentScaleY;
240 private float mCurrentRotationY;
241 private float mCurrentTranslationX;
242 private float mCurrentTranslationY;
243 private float[] mOldTranslationXs;
244 private float[] mOldTranslationYs;
245 private float[] mOldScaleXs;
246 private float[] mOldScaleYs;
247 private float[] mOldBackgroundAlphas;
Adam Cohen4b285c52011-07-21 14:24:06 -0700248 private float[] mOldAlphas;
Adam Cohen4b285c52011-07-21 14:24:06 -0700249 private float[] mNewTranslationXs;
250 private float[] mNewTranslationYs;
251 private float[] mNewScaleXs;
252 private float[] mNewScaleYs;
253 private float[] mNewBackgroundAlphas;
Adam Cohen4b285c52011-07-21 14:24:06 -0700254 private float[] mNewAlphas;
255 private float[] mNewRotationYs;
Winson Chung70442722012-02-10 15:43:22 -0800256 private float mTransitionProgress;
Adam Cohen4b285c52011-07-21 14:24:06 -0700257
Romain Guyeeacd562012-10-10 18:47:33 -0700258 private final Runnable mBindPages = new Runnable() {
259 @Override
260 public void run() {
261 mLauncher.getModel().bindRemainingSynchronousPages();
262 }
263 };
264
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800265 /**
266 * Used to inflate the Workspace from XML.
267 *
268 * @param context The application's context.
Michael Jurka0142d492010-08-25 17:46:15 -0700269 * @param attrs The attributes set containing the Workspace's customization values.
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800270 */
271 public Workspace(Context context, AttributeSet attrs) {
272 this(context, attrs, 0);
273 }
274
275 /**
276 * Used to inflate the Workspace from XML.
277 *
278 * @param context The application's context.
Michael Jurka0142d492010-08-25 17:46:15 -0700279 * @param attrs The attributes set containing the Workspace's customization values.
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800280 * @param defStyle Unused.
281 */
282 public Workspace(Context context, AttributeSet attrs, int defStyle) {
283 super(context, attrs, defStyle);
Michael Jurka0142d492010-08-25 17:46:15 -0700284 mContentIsRefreshable = false;
Michael Jurka37990b42012-09-25 15:14:30 -0700285 mOriginalPageSpacing = mPageSpacing;
Michael Jurka5f1c5092010-09-03 14:15:02 -0700286
Adam Cohenc6cc61d2012-04-04 12:47:08 -0700287 mDragEnforcer = new DropTarget.DragEnforcer(context);
Winson Chungf0ea4d32011-06-06 14:27:16 -0700288 // With workspace, data is available straight from the get-go
289 setDataIsReady();
290
Michael Jurka8bc66c72012-06-21 08:36:45 -0700291 mLauncher = (Launcher) context;
Winson Chung867ca622012-02-21 15:48:35 -0800292 final Resources res = getResources();
Michael Jurka869390b2012-05-06 15:55:19 -0700293 mWorkspaceFadeInAdjacentScreens = res.getBoolean(R.bool.config_workspaceFadeAdjacentScreens);
294 mFadeInAdjacentScreens = false;
Dianne Hackborn8f573952009-08-10 23:21:09 -0700295 mWallpaperManager = WallpaperManager.getInstance(context);
Winson Chungaafa03c2010-06-11 17:34:16 -0700296
Michael Jurkaf6440da2011-04-05 14:50:34 -0700297 int cellCountX = DEFAULT_CELL_COUNT_X;
298 int cellCountY = DEFAULT_CELL_COUNT_Y;
299
Winson Chungaafa03c2010-06-11 17:34:16 -0700300 TypedArray a = context.obtainStyledAttributes(attrs,
301 R.styleable.Workspace, defStyle, 0);
Michael Jurkaf6440da2011-04-05 14:50:34 -0700302
Daniel Sandlercc8befa2013-06-11 14:45:48 -0400303 if (LauncherAppState.isScreenLarge()) {
Michael Jurkaf61249b2011-05-27 16:27:15 -0700304 // Determine number of rows/columns dynamically
305 // TODO: This code currently fails on tablets with an aspect ratio < 1.3.
306 // Around that ratio we should make cells the same size in portrait and
307 // landscape
Michael Jurkaf6440da2011-04-05 14:50:34 -0700308 TypedArray actionBarSizeTypedArray =
309 context.obtainStyledAttributes(new int[] { android.R.attr.actionBarSize });
Michael Jurkaf61249b2011-05-27 16:27:15 -0700310 final float actionBarHeight = actionBarSizeTypedArray.getDimension(0, 0f);
Michael Jurka8bc66c72012-06-21 08:36:45 -0700311
312 Point minDims = new Point();
313 Point maxDims = new Point();
314 mLauncher.getWindowManager().getDefaultDisplay().getCurrentSizeRange(minDims, maxDims);
Michael Jurkaf6440da2011-04-05 14:50:34 -0700315
Michael Jurkaf61249b2011-05-27 16:27:15 -0700316 cellCountX = 1;
Michael Jurka8bc66c72012-06-21 08:36:45 -0700317 while (CellLayout.widthInPortrait(res, cellCountX + 1) <= minDims.x) {
Michael Jurkaf61249b2011-05-27 16:27:15 -0700318 cellCountX++;
Michael Jurkaf6440da2011-04-05 14:50:34 -0700319 }
Michael Jurkaf6440da2011-04-05 14:50:34 -0700320
Michael Jurkaf61249b2011-05-27 16:27:15 -0700321 cellCountY = 1;
322 while (actionBarHeight + CellLayout.heightInLandscape(res, cellCountY + 1)
Michael Jurka8bc66c72012-06-21 08:36:45 -0700323 <= minDims.y) {
Michael Jurkaf61249b2011-05-27 16:27:15 -0700324 cellCountY++;
Michael Jurkaf6440da2011-04-05 14:50:34 -0700325 }
Michael Jurkaf6440da2011-04-05 14:50:34 -0700326 }
327
Winson Chungb26f3d62011-06-02 10:49:29 -0700328 mSpringLoadedShrinkFactor =
329 res.getInteger(R.integer.config_workspaceSpringLoadShrinkPercentage) / 100.0f;
Winson Chung8aad6102012-05-11 16:27:49 -0700330 mSpringLoadedPageSpacing =
331 res.getDimensionPixelSize(R.dimen.workspace_spring_loaded_page_spacing);
Adam Cohen94309882012-06-08 16:24:56 -0700332 mCameraDistance = res.getInteger(R.integer.config_cameraDistance);
Winson Chungb26f3d62011-06-02 10:49:29 -0700333
Michael Jurkaf6440da2011-04-05 14:50:34 -0700334 // if the value is manually specified, use that instead
335 cellCountX = a.getInt(R.styleable.Workspace_cellCountX, cellCountX);
336 cellCountY = a.getInt(R.styleable.Workspace_cellCountY, cellCountY);
Michael Jurka0142d492010-08-25 17:46:15 -0700337 mDefaultPage = a.getInt(R.styleable.Workspace_defaultScreen, 1);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800338 a.recycle();
339
Michael Jurka8b805b12012-04-18 14:23:14 -0700340 setOnHierarchyChangeListener(this);
341
Adam Cohend22015c2010-07-26 22:02:18 -0700342 LauncherModel.updateWorkspaceLayoutCells(cellCountX, cellCountY);
Joe Onorato0d44e942009-11-16 18:20:51 -0800343 setHapticFeedbackEnabled(false);
Michael Jurka0142d492010-08-25 17:46:15 -0700344
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800345 initWorkspace();
Winson Chungc35afb22011-02-23 13:01:49 -0800346
347 // Disable multitouch across the workspace/all apps/customize tray
348 setMotionEventSplittingEnabled(true);
Svetoslav Ganov08055f62012-05-15 11:06:36 -0700349
350 // Unless otherwise specified this view is important for accessibility.
351 if (getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
352 setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
353 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800354 }
355
Michael Jurka038f9d82011-11-03 13:50:45 -0700356 // estimate the size of a widget with spans hSpan, vSpan. return MAX_VALUE for each
357 // dimension if unsuccessful
358 public int[] estimateItemSize(int hSpan, int vSpan,
Adam Cohend41fbf52012-02-16 23:53:59 -0800359 ItemInfo itemInfo, boolean springLoaded) {
Michael Jurka038f9d82011-11-03 13:50:45 -0700360 int[] size = new int[2];
361 if (getChildCount() > 0) {
362 CellLayout cl = (CellLayout) mLauncher.getWorkspace().getChildAt(0);
Adam Cohend41fbf52012-02-16 23:53:59 -0800363 Rect r = estimateItemPosition(cl, itemInfo, 0, 0, hSpan, vSpan);
364 size[0] = r.width();
365 size[1] = r.height();
Michael Jurka038f9d82011-11-03 13:50:45 -0700366 if (springLoaded) {
367 size[0] *= mSpringLoadedShrinkFactor;
368 size[1] *= mSpringLoadedShrinkFactor;
369 }
370 return size;
371 } else {
372 size[0] = Integer.MAX_VALUE;
373 size[1] = Integer.MAX_VALUE;
374 return size;
375 }
376 }
Adam Cohend41fbf52012-02-16 23:53:59 -0800377 public Rect estimateItemPosition(CellLayout cl, ItemInfo pendingInfo,
Michael Jurka038f9d82011-11-03 13:50:45 -0700378 int hCell, int vCell, int hSpan, int vSpan) {
Adam Cohend41fbf52012-02-16 23:53:59 -0800379 Rect r = new Rect();
Michael Jurka038f9d82011-11-03 13:50:45 -0700380 cl.cellToRect(hCell, vCell, hSpan, vSpan, r);
Michael Jurka038f9d82011-11-03 13:50:45 -0700381 return r;
382 }
383
Michael Jurkad74c9842011-07-10 12:44:21 -0700384 public void onDragStart(DragSource source, Object info, int dragAction) {
385 mIsDragOccuring = true;
Michael Jurka3a0469d2012-06-21 09:38:41 -0700386 updateChildrenLayersEnabled(false);
Winson Chung641d71d2012-04-26 15:58:01 -0700387 mLauncher.lockScreenOrientation();
Michael Jurkaa3d30ad2012-05-08 13:43:43 -0700388 setChildrenBackgroundAlphaMultipliers(1f);
Winson Chungf561bdf2012-05-03 11:20:19 -0700389 // Prevent any Un/InstallShortcutReceivers from updating the db while we are dragging
390 InstallShortcutReceiver.enableInstallQueue();
391 UninstallShortcutReceiver.enableUninstallQueue();
Michael Jurkad74c9842011-07-10 12:44:21 -0700392 }
393
394 public void onDragEnd() {
395 mIsDragOccuring = false;
Michael Jurka3a0469d2012-06-21 09:38:41 -0700396 updateChildrenLayersEnabled(false);
Winson Chung4b919f82012-05-01 10:44:08 -0700397 mLauncher.unlockScreenOrientation(false);
Winson Chungf561bdf2012-05-03 11:20:19 -0700398
399 // Re-enable any Un/InstallShortcutReceiver and now process any queued items
400 InstallShortcutReceiver.disableAndFlushInstallQueue(getContext());
401 UninstallShortcutReceiver.disableAndFlushUninstallQueue(getContext());
Michael Jurkad74c9842011-07-10 12:44:21 -0700402 }
403
Adam Cohen66a01fd2013-06-11 12:48:00 -0700404 // Just a hack so that if a custom content screen is added to the left, we adjust the
405 // default screen accordingly so that it stays the same.
406 void incrementDefaultScreen() {
407 mDefaultPage++;
408 }
409
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800410 /**
411 * Initializes various states for this workspace.
412 */
Michael Jurka0142d492010-08-25 17:46:15 -0700413 protected void initWorkspace() {
Joe Onorato0589f0f2010-02-08 13:44:00 -0800414 Context context = getContext();
Michael Jurka0142d492010-08-25 17:46:15 -0700415 mCurrentPage = mDefaultPage;
416 Launcher.setScreen(mCurrentPage);
Daniel Sandlercc8befa2013-06-11 14:45:48 -0400417 LauncherAppState app = LauncherAppState.getInstance();
Joe Onorato0589f0f2010-02-08 13:44:00 -0800418 mIconCache = app.getIconCache();
Patrick Dubroycd68ff52010-10-28 17:57:05 -0700419 setWillNotDraw(false);
Romain Guyce3cbd12013-02-25 15:00:36 -0800420 setClipChildren(false);
421 setClipToPadding(false);
Adam Cohen7777d962011-08-18 18:58:38 -0700422 setChildrenDrawnWithCacheEnabled(true);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800423
Adam Cohen482ed822012-03-02 14:15:13 -0800424 final Resources res = getResources();
Winson Chungb4b7fa72010-11-18 14:38:53 -0800425 try {
Winson Chungfd3385f2011-06-15 19:51:24 -0700426 mBackground = res.getDrawable(R.drawable.apps_customize_bg);
Winson Chungb4b7fa72010-11-18 14:38:53 -0800427 } catch (Resources.NotFoundException e) {
428 // In this case, we will skip drawing background protection
429 }
Winson Chung9171e6d2010-11-17 17:39:27 -0800430
Michael Jurkaab1983f2011-01-18 15:50:17 -0800431 mWallpaperOffset = new WallpaperOffsetInterpolator();
Adam Cohencff6af82011-09-13 14:51:53 -0700432 Display display = mLauncher.getWindowManager().getDefaultDisplay();
Michael Jurka84f2ce72012-04-13 15:08:01 -0700433 display.getSize(mDisplaySize);
434 mWallpaperTravelWidth = (int) (mDisplaySize.x *
435 wallpaperTravelToScreenWidthRatio(mDisplaySize.x, mDisplaySize.y));
Adam Cohen265b9a62011-12-07 14:37:18 -0800436
Adam Cohen3aff81c2012-05-16 21:01:01 -0700437 mMaxDistanceForFolderCreation = (0.55f * res.getDimensionPixelSize(R.dimen.app_icon_size));
Adam Cohen265b9a62011-12-07 14:37:18 -0800438 mFlingThresholdVelocity = (int) (FLING_THRESHOLD_VELOCITY * mDensity);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800439 }
440
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800441 @Override
Adam Cohenf34bab52010-09-30 14:11:56 -0700442 protected int getScrollMode() {
Winson Chungb26f3d62011-06-02 10:49:29 -0700443 return SmoothPagedView.X_LARGE_MODE;
Adam Cohenf34bab52010-09-30 14:11:56 -0700444 }
445
Michael Jurka08ee7702011-08-11 16:53:35 -0700446 @Override
Michael Jurka8b805b12012-04-18 14:23:14 -0700447 public void onChildViewAdded(View parent, View child) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800448 if (!(child instanceof CellLayout)) {
449 throw new IllegalArgumentException("A Workspace can only have CellLayout children.");
450 }
Adam Cohen2801caf2011-05-13 20:57:39 -0700451 CellLayout cl = ((CellLayout) child);
452 cl.setOnInterceptTouchListener(this);
Adam Cohen2801caf2011-05-13 20:57:39 -0700453 cl.setClickable(true);
alanv51944f12012-05-07 17:31:32 -0700454 cl.setContentDescription(getContext().getString(
455 R.string.workspace_description_format, getChildCount()));
Michael Jurkae5fb0f22011-04-11 13:27:46 -0700456 }
Adam Cohen2801caf2011-05-13 20:57:39 -0700457
Michael Jurka8b805b12012-04-18 14:23:14 -0700458 @Override
459 public void onChildViewRemoved(View parent, View child) {
460 }
461
Michael Jurka920d7f42012-05-14 16:29:55 -0700462 protected boolean shouldDrawChild(View child) {
463 final CellLayout cl = (CellLayout) child;
464 return super.shouldDrawChild(child) &&
465 (cl.getShortcutsAndWidgets().getAlpha() > 0 ||
466 cl.getBackgroundAlpha() > 0);
467 }
468
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800469 /**
470 * @return The open folder on the current screen, or null if there is none
471 */
472 Folder getOpenFolder() {
Adam Cohen716b51e2011-06-30 12:09:54 -0700473 DragLayer dragLayer = mLauncher.getDragLayer();
Adam Cohen8e776a62011-06-28 18:10:06 -0700474 int count = dragLayer.getChildCount();
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800475 for (int i = 0; i < count; i++) {
Adam Cohen8e776a62011-06-28 18:10:06 -0700476 View child = dragLayer.getChildAt(i);
Winson Chungaafa03c2010-06-11 17:34:16 -0700477 if (child instanceof Folder) {
478 Folder folder = (Folder) child;
479 if (folder.getInfo().opened)
480 return folder;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800481 }
482 }
483 return null;
484 }
485
Patrick Dubroya0aa0122011-02-24 11:42:23 -0800486 boolean isTouchActive() {
487 return mTouchState != TOUCH_STATE_REST;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800488 }
489
490 /**
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800491 * Adds the specified child in the specified screen. The position and dimension of
492 * the child are defined by x, y, spanX and spanY.
493 *
494 * @param child The child to add in one of the workspace's screens.
495 * @param screen The screen in which to add the child.
496 * @param x The X position of the child in the screen's grid.
497 * @param y The Y position of the child in the screen's grid.
498 * @param spanX The number of cells spanned horizontally by the child.
499 * @param spanY The number of cells spanned vertically by the child.
500 */
Winson Chung3d503fb2011-07-13 17:25:49 -0700501 void addInScreen(View child, long container, int screen, int x, int y, int spanX, int spanY) {
502 addInScreen(child, container, screen, x, y, spanX, spanY, false);
Winson Chungaafa03c2010-06-11 17:34:16 -0700503 }
504
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800505 /**
506 * Adds the specified child in the specified screen. The position and dimension of
507 * the child are defined by x, y, spanX and spanY.
508 *
509 * @param child The child to add in one of the workspace's screens.
510 * @param screen The screen in which to add the child.
511 * @param x The X position of the child in the screen's grid.
512 * @param y The Y position of the child in the screen's grid.
513 * @param spanX The number of cells spanned horizontally by the child.
514 * @param spanY The number of cells spanned vertically by the child.
515 * @param insert When true, the child is inserted at the beginning of the children list.
516 */
Winson Chung3d503fb2011-07-13 17:25:49 -0700517 void addInScreen(View child, long container, int screen, int x, int y, int spanX, int spanY,
518 boolean insert) {
519 if (container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
520 if (screen < 0 || screen >= getChildCount()) {
521 Log.e(TAG, "The screen must be >= 0 and < " + getChildCount()
522 + " (was " + screen + "); skipping child");
523 return;
524 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800525 }
526
Winson Chung3d503fb2011-07-13 17:25:49 -0700527 final CellLayout layout;
528 if (container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
529 layout = mLauncher.getHotseat().getLayout();
Winson Chung4d279d92011-07-21 11:46:32 -0700530 child.setOnKeyListener(null);
Winson Chung3d503fb2011-07-13 17:25:49 -0700531
Adam Cohen099f60d2011-08-23 21:07:26 -0700532 // Hide folder title in the hotseat
533 if (child instanceof FolderIcon) {
534 ((FolderIcon) child).setTextVisible(false);
535 }
536
Winson Chung3d503fb2011-07-13 17:25:49 -0700537 if (screen < 0) {
538 screen = mLauncher.getHotseat().getOrderInHotseat(x, y);
539 } else {
540 // Note: We do this to ensure that the hotseat is always laid out in the orientation
541 // of the hotseat in order regardless of which orientation they were added
542 x = mLauncher.getHotseat().getCellXFromOrder(screen);
543 y = mLauncher.getHotseat().getCellYFromOrder(screen);
544 }
545 } else {
Adam Cohen099f60d2011-08-23 21:07:26 -0700546 // Show folder title if not in the hotseat
547 if (child instanceof FolderIcon) {
548 ((FolderIcon) child).setTextVisible(true);
549 }
550
Winson Chung3d503fb2011-07-13 17:25:49 -0700551 layout = (CellLayout) getChildAt(screen);
Adam Cohenac56cff2011-09-28 20:45:37 -0700552 child.setOnKeyListener(new IconKeyEventListener());
Winson Chung3d503fb2011-07-13 17:25:49 -0700553 }
554
Adam Cohened66b2b2012-01-23 17:28:51 -0800555 LayoutParams genericLp = child.getLayoutParams();
556 CellLayout.LayoutParams lp;
557 if (genericLp == null || !(genericLp instanceof CellLayout.LayoutParams)) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800558 lp = new CellLayout.LayoutParams(x, y, spanX, spanY);
559 } else {
Adam Cohened66b2b2012-01-23 17:28:51 -0800560 lp = (CellLayout.LayoutParams) genericLp;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800561 lp.cellX = x;
562 lp.cellY = y;
563 lp.cellHSpan = spanX;
564 lp.cellVSpan = spanY;
565 }
Winson Chungaafa03c2010-06-11 17:34:16 -0700566
Adam Cohen7f4eabe2011-04-21 16:19:16 -0700567 if (spanX < 0 && spanY < 0) {
568 lp.isLockedToGrid = false;
569 }
570
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700571 // Get the canonical child id to uniquely represent this view in this screen
Winson Chung3d503fb2011-07-13 17:25:49 -0700572 int childId = LauncherModel.getCellLayoutChildId(container, screen, x, y, spanX, spanY);
Michael Jurkaf3ca3ab2010-10-20 17:08:24 -0700573 boolean markCellsAsOccupied = !(child instanceof Folder);
Winson Chung3d503fb2011-07-13 17:25:49 -0700574 if (!layout.addViewToCellLayout(child, insert ? 0 : -1, childId, lp, markCellsAsOccupied)) {
Winson Chungaafa03c2010-06-11 17:34:16 -0700575 // TODO: This branch occurs when the workspace is adding views
576 // outside of the defined grid
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700577 // maybe we should be deleting these items from the LauncherModel?
Winson Chungaafa03c2010-06-11 17:34:16 -0700578 Log.w(TAG, "Failed to add to item at (" + lp.cellX + "," + lp.cellY + ") to CellLayout");
579 }
580
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800581 if (!(child instanceof Folder)) {
Joe Onorato0d44e942009-11-16 18:20:51 -0800582 child.setHapticFeedbackEnabled(false);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800583 child.setOnLongClickListener(mLongClickListener);
584 }
Joe Onorato00acb122009-08-04 16:04:30 -0400585 if (child instanceof DropTarget) {
Winson Chungaafa03c2010-06-11 17:34:16 -0700586 mDragController.addDropTarget((DropTarget) child);
Joe Onorato00acb122009-08-04 16:04:30 -0400587 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800588 }
589
Patrick Dubroyd0ce1ec2011-01-19 18:47:27 -0800590 /**
591 * Check if the point (x, y) hits a given page.
592 */
593 private boolean hitsPage(int index, float x, float y) {
594 final View page = getChildAt(index);
595 if (page != null) {
596 float[] localXY = { x, y };
597 mapPointFromSelfToChild(page, localXY);
598 return (localXY[0] >= 0 && localXY[0] < page.getWidth()
599 && localXY[1] >= 0 && localXY[1] < page.getHeight());
600 }
601 return false;
602 }
603
604 @Override
605 protected boolean hitsPreviousPage(float x, float y) {
606 // mNextPage is set to INVALID_PAGE whenever we are stationary.
607 // Calculating "next page" this way ensures that you scroll to whatever page you tap on
608 final int current = (mNextPage == INVALID_PAGE) ? mCurrentPage : mNextPage;
Michael Jurkab72094f2011-09-14 14:53:19 -0700609
610 // Only allow tap to next page on large devices, where there's significant margin outside
611 // the active workspace
Daniel Sandlercc8befa2013-06-11 14:45:48 -0400612 return LauncherAppState.isScreenLarge() && hitsPage(current - 1, x, y);
Patrick Dubroyd0ce1ec2011-01-19 18:47:27 -0800613 }
614
615 @Override
616 protected boolean hitsNextPage(float x, float y) {
617 // mNextPage is set to INVALID_PAGE whenever we are stationary.
618 // Calculating "next page" this way ensures that you scroll to whatever page you tap on
619 final int current = (mNextPage == INVALID_PAGE) ? mCurrentPage : mNextPage;
Michael Jurkab72094f2011-09-14 14:53:19 -0700620
621 // Only allow tap to next page on large devices, where there's significant margin outside
622 // the active workspace
Daniel Sandlercc8befa2013-06-11 14:45:48 -0400623 return LauncherAppState.isScreenLarge() && hitsPage(current + 1, x, y);
Patrick Dubroyd0ce1ec2011-01-19 18:47:27 -0800624 }
625
Patrick Dubroye708c522011-03-01 16:03:43 -0800626 /**
627 * Called directly from a CellLayout (not by the framework), after we've been added as a
628 * listener via setOnInterceptTouchEventListener(). This allows us to tell the CellLayout
629 * that it should intercept touch events, which is not something that is normally supported.
630 */
631 @Override
Michael Jurkadee05892010-07-27 10:01:56 -0700632 public boolean onTouch(View v, MotionEvent event) {
Winson Chung70442722012-02-10 15:43:22 -0800633 return (isSmall() || !isFinishedSwitchingState());
Patrick Dubroye708c522011-03-01 16:03:43 -0800634 }
635
Adam Cohenfc53cd22011-07-20 15:45:11 -0700636 public boolean isSwitchingState() {
637 return mIsSwitchingState;
638 }
639
Winson Chung70442722012-02-10 15:43:22 -0800640 /** This differs from isSwitchingState in that we take into account how far the transition
641 * has completed. */
Winson Chung9b0b2fe2012-02-24 13:03:34 -0800642 public boolean isFinishedSwitchingState() {
Winson Chung70442722012-02-10 15:43:22 -0800643 return !mIsSwitchingState || (mTransitionProgress > 0.5f);
644 }
645
Adam Cohended9f8d2010-11-03 13:25:16 -0700646 protected void onWindowVisibilityChanged (int visibility) {
647 mLauncher.onWindowVisibilityChanged(visibility);
648 }
649
Michael Jurka5f1c5092010-09-03 14:15:02 -0700650 @Override
651 public boolean dispatchUnhandledMove(View focused, int direction) {
Winson Chung70442722012-02-10 15:43:22 -0800652 if (isSmall() || !isFinishedSwitchingState()) {
Michael Jurka5f1c5092010-09-03 14:15:02 -0700653 // when the home screens are shrunken, shouldn't allow side-scrolling
654 return false;
655 }
656 return super.dispatchUnhandledMove(focused, direction);
657 }
658
659 @Override
660 public boolean onInterceptTouchEvent(MotionEvent ev) {
Michael Jurkad771c962011-08-09 15:00:48 -0700661 switch (ev.getAction() & MotionEvent.ACTION_MASK) {
662 case MotionEvent.ACTION_DOWN:
Adam Cohenf8d28232011-02-01 21:47:00 -0800663 mXDown = ev.getX();
664 mYDown = ev.getY();
Michael Jurkad771c962011-08-09 15:00:48 -0700665 break;
666 case MotionEvent.ACTION_POINTER_UP:
667 case MotionEvent.ACTION_UP:
668 if (mTouchState == TOUCH_STATE_REST) {
669 final CellLayout currentPage = (CellLayout) getChildAt(mCurrentPage);
670 if (!currentPage.lastDownOnOccupiedCell()) {
671 onWallpaperTap(ev);
672 }
673 }
Adam Cohenf8d28232011-02-01 21:47:00 -0800674 }
Bjorn Bringertc459e522013-06-07 19:36:01 +0100675
676 if (mLauncher != null && mLauncher.onTouch(this, ev)) {
677 return true;
678 }
679
Michael Jurka5f1c5092010-09-03 14:15:02 -0700680 return super.onInterceptTouchEvent(ev);
681 }
682
Adam Cohen3d509322012-06-06 14:10:04 -0700683 protected void reinflateWidgetsIfNecessary() {
684 final int clCount = getChildCount();
685 for (int i = 0; i < clCount; i++) {
686 CellLayout cl = (CellLayout) getChildAt(i);
687 ShortcutAndWidgetContainer swc = cl.getShortcutsAndWidgets();
688 final int itemCount = swc.getChildCount();
689 for (int j = 0; j < itemCount; j++) {
690 View v = swc.getChildAt(j);
691
692 if (v.getTag() instanceof LauncherAppWidgetInfo) {
693 LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) v.getTag();
694 LauncherAppWidgetHostView lahv = (LauncherAppWidgetHostView) info.hostView;
695 if (lahv != null && lahv.orientationChangedSincedInflation()) {
696 mLauncher.removeAppWidget(info);
697 // Remove the current widget which is inflated with the wrong orientation
698 cl.removeView(lahv);
699 mLauncher.bindAppWidget(info);
700 }
701 }
702 }
703 }
704 }
705
Michael Jurka1adf5392010-10-18 18:10:22 -0700706 @Override
707 protected void determineScrollingStart(MotionEvent ev) {
Winson Chung70442722012-02-10 15:43:22 -0800708 if (isSmall()) return;
709 if (!isFinishedSwitchingState()) return;
Adam Cohenf8d28232011-02-01 21:47:00 -0800710
Winson Chung70442722012-02-10 15:43:22 -0800711 float deltaX = Math.abs(ev.getX() - mXDown);
712 float deltaY = Math.abs(ev.getY() - mYDown);
Adam Cohenf8d28232011-02-01 21:47:00 -0800713
Winson Chung70442722012-02-10 15:43:22 -0800714 if (Float.compare(deltaX, 0f) == 0) return;
Adam Cohenf8d28232011-02-01 21:47:00 -0800715
Winson Chung70442722012-02-10 15:43:22 -0800716 float slope = deltaY / deltaX;
717 float theta = (float) Math.atan(slope);
Adam Cohenf8d28232011-02-01 21:47:00 -0800718
Winson Chung70442722012-02-10 15:43:22 -0800719 if (deltaX > mTouchSlop || deltaY > mTouchSlop) {
720 cancelCurrentPageLongPress();
721 }
722
723 if (theta > MAX_SWIPE_ANGLE) {
724 // Above MAX_SWIPE_ANGLE, we don't want to ever start scrolling the workspace
725 return;
726 } else if (theta > START_DAMPING_TOUCH_SLOP_ANGLE) {
727 // Above START_DAMPING_TOUCH_SLOP_ANGLE and below MAX_SWIPE_ANGLE, we want to
728 // increase the touch slop to make it harder to begin scrolling the workspace. This
729 // results in vertically scrolling widgets to more easily. The higher the angle, the
730 // more we increase touch slop.
731 theta -= START_DAMPING_TOUCH_SLOP_ANGLE;
732 float extraRatio = (float)
733 Math.sqrt((theta / (MAX_SWIPE_ANGLE - START_DAMPING_TOUCH_SLOP_ANGLE)));
734 super.determineScrollingStart(ev, 1 + TOUCH_SLOP_DAMPING_FACTOR * extraRatio);
735 } else {
736 // Below START_DAMPING_TOUCH_SLOP_ANGLE, we don't do anything special
737 super.determineScrollingStart(ev);
Adam Cohenf8d28232011-02-01 21:47:00 -0800738 }
Michael Jurka1adf5392010-10-18 18:10:22 -0700739 }
740
Patrick Dubroy1262e362010-10-06 15:49:50 -0700741 protected void onPageBeginMoving() {
Winson Chung007c6982011-06-14 13:27:53 -0700742 super.onPageBeginMoving();
743
Michael Jurkad74c9842011-07-10 12:44:21 -0700744 if (isHardwareAccelerated()) {
Michael Jurka3a0469d2012-06-21 09:38:41 -0700745 updateChildrenLayersEnabled(false);
Michael Jurka0142d492010-08-25 17:46:15 -0700746 } else {
Michael Jurkad74c9842011-07-10 12:44:21 -0700747 if (mNextPage != INVALID_PAGE) {
748 // we're snapping to a particular screen
749 enableChildrenCache(mCurrentPage, mNextPage);
750 } else {
751 // this is when user is actively dragging a particular screen, they might
752 // swipe it either left or right (but we won't advance by more than one screen)
753 enableChildrenCache(mCurrentPage - 1, mCurrentPage + 1);
754 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800755 }
Winson Chung007c6982011-06-14 13:27:53 -0700756
757 // Only show page outlines as we pan if we are on large screen
Daniel Sandlercc8befa2013-06-11 14:45:48 -0400758 if (LauncherAppState.isScreenLarge()) {
Winson Chung007c6982011-06-14 13:27:53 -0700759 showOutlines();
Michael Jurka95515372012-02-29 14:13:01 -0800760 mIsStaticWallpaper = mWallpaperManager.getWallpaperInfo() == null;
Winson Chung007c6982011-06-14 13:27:53 -0700761 }
Winson Chung1afedc32012-01-23 16:14:56 -0800762
Winson Chung70442722012-02-10 15:43:22 -0800763 // If we are not fading in adjacent screens, we still need to restore the alpha in case the
764 // user scrolls while we are transitioning (should not affect dispatchDraw optimizations)
Michael Jurka869390b2012-05-06 15:55:19 -0700765 if (!mWorkspaceFadeInAdjacentScreens) {
Winson Chung70442722012-02-10 15:43:22 -0800766 for (int i = 0; i < getChildCount(); ++i) {
Michael Jurkaa52570f2012-03-20 03:18:20 -0700767 ((CellLayout) getPageAt(i)).setShortcutAndWidgetAlpha(1f);
Winson Chung70442722012-02-10 15:43:22 -0800768 }
769 }
770
Winson Chung1afedc32012-01-23 16:14:56 -0800771 // Show the scroll indicator as you pan the page
772 showScrollingIndicator(false);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800773 }
774
Patrick Dubroy1262e362010-10-06 15:49:50 -0700775 protected void onPageEndMoving() {
Winson Chung007c6982011-06-14 13:27:53 -0700776 super.onPageEndMoving();
777
Michael Jurkad74c9842011-07-10 12:44:21 -0700778 if (isHardwareAccelerated()) {
Michael Jurka3a0469d2012-06-21 09:38:41 -0700779 updateChildrenLayersEnabled(false);
Michael Jurkad74c9842011-07-10 12:44:21 -0700780 } else {
781 clearChildrenCache();
782 }
783
Winson Chung3bc21c32012-01-20 13:59:18 -0800784
785 if (mDragController.isDragging()) {
786 if (isSmall()) {
787 // If we are in springloaded mode, then force an event to check if the current touch
788 // is under a new page (to scroll to)
Winson Chung25460a12013-04-01 18:21:28 -0700789 mDragController.forceTouchMove();
Winson Chung3bc21c32012-01-20 13:59:18 -0800790 }
791 } else {
792 // If we are not mid-dragging, hide the page outlines if we are on a large screen
Daniel Sandlercc8befa2013-06-11 14:45:48 -0400793 if (LauncherAppState.isScreenLarge()) {
Winson Chung007c6982011-06-14 13:27:53 -0700794 hideOutlines();
795 }
Winson Chung1afedc32012-01-23 16:14:56 -0800796
797 // Hide the scroll indicator as you pan the page
798 if (!mDragController.isDragging()) {
799 hideScrollingIndicator(false);
800 }
Patrick Dubroy1262e362010-10-06 15:49:50 -0700801 }
Adam Cohen26976d92011-03-22 15:33:33 -0700802
803 if (mDelayedResizeRunnable != null) {
804 mDelayedResizeRunnable.run();
805 mDelayedResizeRunnable = null;
806 }
Winson Chungf0c6ae02012-03-21 16:10:31 -0700807
808 if (mDelayedSnapToPageRunnable != null) {
809 mDelayedSnapToPageRunnable.run();
810 mDelayedSnapToPageRunnable = null;
811 }
Michael Jurka0142d492010-08-25 17:46:15 -0700812 }
813
814 @Override
815 protected void notifyPageSwitchListener() {
816 super.notifyPageSwitchListener();
Michael Jurka0142d492010-08-25 17:46:15 -0700817 Launcher.setScreen(mCurrentPage);
818 };
819
Michael Jurkac5b262c2011-01-12 20:24:50 -0800820 // As a ratio of screen height, the total distance we want the parallax effect to span
Michael Jurkac5b262c2011-01-12 20:24:50 -0800821 // horizontally
822 private float wallpaperTravelToScreenWidthRatio(int width, int height) {
823 float aspectRatio = width / (float) height;
824
825 // At an aspect ratio of 16/10, the wallpaper parallax effect should span 1.5 * screen width
826 // At an aspect ratio of 10/16, the wallpaper parallax effect should span 1.2 * screen width
827 // We will use these two data points to extrapolate how much the wallpaper parallax effect
828 // to span (ie travel) at any aspect ratio:
829
830 final float ASPECT_RATIO_LANDSCAPE = 16/10f;
831 final float ASPECT_RATIO_PORTRAIT = 10/16f;
832 final float WALLPAPER_WIDTH_TO_SCREEN_RATIO_LANDSCAPE = 1.5f;
833 final float WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT = 1.2f;
834
835 // To find out the desired width at different aspect ratios, we use the following two
836 // formulas, where the coefficient on x is the aspect ratio (width/height):
837 // (16/10)x + y = 1.5
838 // (10/16)x + y = 1.2
839 // We solve for x and y and end up with a final formula:
840 final float x =
841 (WALLPAPER_WIDTH_TO_SCREEN_RATIO_LANDSCAPE - WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT) /
842 (ASPECT_RATIO_LANDSCAPE - ASPECT_RATIO_PORTRAIT);
843 final float y = WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT - x * ASPECT_RATIO_PORTRAIT;
844 return x * aspectRatio + y;
845 }
846
847 // The range of scroll values for Workspace
848 private int getScrollRange() {
849 return getChildOffset(getChildCount() - 1) - getChildOffset(0);
850 }
851
852 protected void setWallpaperDimension() {
Michael Jurka9f5331c2012-06-20 14:02:10 -0700853 Point minDims = new Point();
854 Point maxDims = new Point();
855 mLauncher.getWindowManager().getDefaultDisplay().getCurrentSizeRange(minDims, maxDims);
856
857 final int maxDim = Math.max(maxDims.x, maxDims.y);
858 final int minDim = Math.min(minDims.x, minDims.y);
Michael Jurkac5b262c2011-01-12 20:24:50 -0800859
860 // We need to ensure that there is enough extra space in the wallpaper for the intended
861 // parallax effects
Daniel Sandlercc8befa2013-06-11 14:45:48 -0400862 if (LauncherAppState.isScreenLarge()) {
Michael Jurkaa6471802011-09-22 14:39:16 -0700863 mWallpaperWidth = (int) (maxDim * wallpaperTravelToScreenWidthRatio(maxDim, minDim));
Michael Jurka193080b2011-10-28 16:08:53 -0700864 mWallpaperHeight = maxDim;
Michael Jurkaa6471802011-09-22 14:39:16 -0700865 } else {
Michael Jurka16706982011-09-26 16:39:22 -0700866 mWallpaperWidth = Math.max((int) (minDim * WALLPAPER_SCREENS_SPAN), maxDim);
Michael Jurkaa6471802011-09-22 14:39:16 -0700867 mWallpaperHeight = maxDim;
868 }
Winson Chungf7640c82011-02-28 13:47:29 -0800869 new Thread("setWallpaperDimension") {
870 public void run() {
871 mWallpaperManager.suggestDesiredDimensions(mWallpaperWidth, mWallpaperHeight);
872 }
873 }.start();
Michael Jurkac5b262c2011-01-12 20:24:50 -0800874 }
875
Michael Jurkaab1983f2011-01-18 15:50:17 -0800876 private float wallpaperOffsetForCurrentScroll() {
Michael Jurkaab1983f2011-01-18 15:50:17 -0800877 // Set wallpaper offset steps (1 / (number of screens - 1))
Michael Jurka193080b2011-10-28 16:08:53 -0700878 mWallpaperManager.setWallpaperOffsetSteps(1.0f / (getChildCount() - 1), 1.0f);
Michael Jurkaab1983f2011-01-18 15:50:17 -0800879
Michael Jurka193080b2011-10-28 16:08:53 -0700880 // For the purposes of computing the scrollRange and overScrollOffset, we assume
881 // that mLayoutScale is 1. This means that when we're in spring-loaded mode,
Adam Cohenbeff8c62011-08-31 17:46:01 -0700882 // there's no discrepancy between the wallpaper offset for a given page.
883 float layoutScale = mLayoutScale;
884 mLayoutScale = 1f;
Michael Jurka09d6eb02011-01-28 16:05:09 -0800885 int scrollRange = getScrollRange();
Michael Jurka09d6eb02011-01-28 16:05:09 -0800886
Adam Cohenbeff8c62011-08-31 17:46:01 -0700887 // Again, we adjust the wallpaper offset to be consistent between values of mLayoutScale
Michael Jurka8b805b12012-04-18 14:23:14 -0700888 float adjustedScrollX = Math.max(0, Math.min(getScrollX(), mMaxScrollX));
Adam Cohenb5ba0972011-09-07 18:02:31 -0700889 adjustedScrollX *= mWallpaperScrollRatio;
Adam Cohenbeff8c62011-08-31 17:46:01 -0700890 mLayoutScale = layoutScale;
891
Michael Jurkaab1983f2011-01-18 15:50:17 -0800892 float scrollProgress =
Michael Jurka193080b2011-10-28 16:08:53 -0700893 adjustedScrollX / (float) scrollRange;
Michael Jurka95515372012-02-29 14:13:01 -0800894
Daniel Sandlercc8befa2013-06-11 14:45:48 -0400895 if (LauncherAppState.isScreenLarge() && mIsStaticWallpaper) {
Michael Jurka95515372012-02-29 14:13:01 -0800896 // The wallpaper travel width is how far, from left to right, the wallpaper will move
897 // at this orientation. On tablets in portrait mode we don't move all the way to the
898 // edges of the wallpaper, or otherwise the parallax effect would be too strong.
899 int wallpaperTravelWidth = Math.min(mWallpaperTravelWidth, mWallpaperWidth);
900
901 float offsetInDips = wallpaperTravelWidth * scrollProgress +
902 (mWallpaperWidth - wallpaperTravelWidth) / 2; // center it
903 float offset = offsetInDips / (float) mWallpaperWidth;
904 return offset;
905 } else {
906 return scrollProgress;
907 }
Michael Jurkaab1983f2011-01-18 15:50:17 -0800908 }
Michael Jurka95515372012-02-29 14:13:01 -0800909
Michael Jurkaab1983f2011-01-18 15:50:17 -0800910 private void syncWallpaperOffsetWithScroll() {
Winson Chungb46a2d12011-04-22 14:13:05 -0700911 final boolean enableWallpaperEffects = isHardwareAccelerated();
912 if (enableWallpaperEffects) {
Michael Jurkaab1983f2011-01-18 15:50:17 -0800913 mWallpaperOffset.setFinalX(wallpaperOffsetForCurrentScroll());
Michael Jurkac5b262c2011-01-12 20:24:50 -0800914 }
915 }
916
917 public void updateWallpaperOffsetImmediately() {
918 mUpdateWallpaperOffsetImmediately = true;
919 }
920
Michael Jurkaab1983f2011-01-18 15:50:17 -0800921 private void updateWallpaperOffsets() {
922 boolean updateNow = false;
923 boolean keepUpdating = true;
924 if (mUpdateWallpaperOffsetImmediately) {
925 updateNow = true;
926 keepUpdating = false;
927 mWallpaperOffset.jumpToFinal();
928 mUpdateWallpaperOffsetImmediately = false;
Michael Jurkac5b262c2011-01-12 20:24:50 -0800929 } else {
Michael Jurkaab1983f2011-01-18 15:50:17 -0800930 updateNow = keepUpdating = mWallpaperOffset.computeScrollOffset();
Michael Jurkac5b262c2011-01-12 20:24:50 -0800931 }
Michael Jurkaab1983f2011-01-18 15:50:17 -0800932 if (updateNow) {
Michael Jurka9c6fbed2011-03-02 17:41:34 -0800933 if (mWindowToken != null) {
934 mWallpaperManager.setWallpaperOffsets(mWindowToken,
Michael Jurkaab1983f2011-01-18 15:50:17 -0800935 mWallpaperOffset.getCurrX(), mWallpaperOffset.getCurrY());
936 }
Michael Jurkac5b262c2011-01-12 20:24:50 -0800937 }
Michael Jurkaab1983f2011-01-18 15:50:17 -0800938 if (keepUpdating) {
Michael Jurka7372c592012-01-16 04:21:35 -0800939 invalidate();
Michael Jurkac5b262c2011-01-12 20:24:50 -0800940 }
Michael Jurkaab1983f2011-01-18 15:50:17 -0800941 }
942
Adam Cohenbeff8c62011-08-31 17:46:01 -0700943 @Override
944 protected void updateCurrentPageScroll() {
945 super.updateCurrentPageScroll();
Adam Cohen5037a0b2011-09-01 13:10:40 -0700946 computeWallpaperScrollRatio(mCurrentPage);
Adam Cohenbeff8c62011-08-31 17:46:01 -0700947 }
948
949 @Override
950 protected void snapToPage(int whichPage) {
951 super.snapToPage(whichPage);
Adam Cohen5037a0b2011-09-01 13:10:40 -0700952 computeWallpaperScrollRatio(whichPage);
Adam Cohenbeff8c62011-08-31 17:46:01 -0700953 }
954
Winson Chungf0c6ae02012-03-21 16:10:31 -0700955 @Override
956 protected void snapToPage(int whichPage, int duration) {
957 super.snapToPage(whichPage, duration);
958 computeWallpaperScrollRatio(whichPage);
959 }
960
961 protected void snapToPage(int whichPage, Runnable r) {
962 if (mDelayedSnapToPageRunnable != null) {
963 mDelayedSnapToPageRunnable.run();
964 }
965 mDelayedSnapToPageRunnable = r;
966 snapToPage(whichPage, SLOW_PAGE_SNAP_ANIMATION_DURATION);
967 }
968
Adam Cohen5037a0b2011-09-01 13:10:40 -0700969 private void computeWallpaperScrollRatio(int page) {
Adam Cohenbeff8c62011-08-31 17:46:01 -0700970 // Here, we determine what the desired scroll would be with and without a layout scale,
971 // and compute a ratio between the two. This allows us to adjust the wallpaper offset
972 // as though there is no layout scale.
973 float layoutScale = mLayoutScale;
Adam Cohen5037a0b2011-09-01 13:10:40 -0700974 int scaled = getChildOffset(page) - getRelativeChildOffset(page);
Adam Cohenbeff8c62011-08-31 17:46:01 -0700975 mLayoutScale = 1.0f;
Adam Cohen5037a0b2011-09-01 13:10:40 -0700976 float unscaled = getChildOffset(page) - getRelativeChildOffset(page);
Adam Cohenbeff8c62011-08-31 17:46:01 -0700977 mLayoutScale = layoutScale;
978 if (scaled > 0) {
979 mWallpaperScrollRatio = (1.0f * unscaled) / scaled;
980 } else {
981 mWallpaperScrollRatio = 1f;
982 }
983 }
984
Michael Jurkaab1983f2011-01-18 15:50:17 -0800985 class WallpaperOffsetInterpolator {
986 float mFinalHorizontalWallpaperOffset = 0.0f;
987 float mFinalVerticalWallpaperOffset = 0.5f;
988 float mHorizontalWallpaperOffset = 0.0f;
989 float mVerticalWallpaperOffset = 0.5f;
990 long mLastWallpaperOffsetUpdateTime;
Michael Jurkaca5b8362011-01-27 13:23:26 -0800991 boolean mIsMovingFast;
992 boolean mOverrideHorizontalCatchupConstant;
993 float mHorizontalCatchupConstant = 0.35f;
994 float mVerticalCatchupConstant = 0.35f;
Michael Jurkaab1983f2011-01-18 15:50:17 -0800995
996 public WallpaperOffsetInterpolator() {
997 }
998
Michael Jurkaca5b8362011-01-27 13:23:26 -0800999 public void setOverrideHorizontalCatchupConstant(boolean override) {
1000 mOverrideHorizontalCatchupConstant = override;
1001 }
1002
1003 public void setHorizontalCatchupConstant(float f) {
1004 mHorizontalCatchupConstant = f;
1005 }
1006
1007 public void setVerticalCatchupConstant(float f) {
1008 mVerticalCatchupConstant = f;
1009 }
1010
Michael Jurkaab1983f2011-01-18 15:50:17 -08001011 public boolean computeScrollOffset() {
1012 if (Float.compare(mHorizontalWallpaperOffset, mFinalHorizontalWallpaperOffset) == 0 &&
1013 Float.compare(mVerticalWallpaperOffset, mFinalVerticalWallpaperOffset) == 0) {
Michael Jurkaca5b8362011-01-27 13:23:26 -08001014 mIsMovingFast = false;
Michael Jurkaab1983f2011-01-18 15:50:17 -08001015 return false;
1016 }
Michael Jurka84f2ce72012-04-13 15:08:01 -07001017 boolean isLandscape = mDisplaySize.x > mDisplaySize.y;
Michael Jurkaab1983f2011-01-18 15:50:17 -08001018
1019 long currentTime = System.currentTimeMillis();
1020 long timeSinceLastUpdate = currentTime - mLastWallpaperOffsetUpdateTime;
1021 timeSinceLastUpdate = Math.min((long) (1000/30f), timeSinceLastUpdate);
1022 timeSinceLastUpdate = Math.max(1L, timeSinceLastUpdate);
Michael Jurkaca5b8362011-01-27 13:23:26 -08001023
1024 float xdiff = Math.abs(mFinalHorizontalWallpaperOffset - mHorizontalWallpaperOffset);
1025 if (!mIsMovingFast && xdiff > 0.07) {
1026 mIsMovingFast = true;
1027 }
1028
1029 float fractionToCatchUpIn1MsHorizontal;
1030 if (mOverrideHorizontalCatchupConstant) {
1031 fractionToCatchUpIn1MsHorizontal = mHorizontalCatchupConstant;
1032 } else if (mIsMovingFast) {
1033 fractionToCatchUpIn1MsHorizontal = isLandscape ? 0.5f : 0.75f;
1034 } else {
1035 // slow
1036 fractionToCatchUpIn1MsHorizontal = isLandscape ? 0.27f : 0.5f;
1037 }
1038 float fractionToCatchUpIn1MsVertical = mVerticalCatchupConstant;
1039
Michael Jurkaca5b8362011-01-27 13:23:26 -08001040 fractionToCatchUpIn1MsHorizontal /= 33f;
1041 fractionToCatchUpIn1MsVertical /= 33f;
Michael Jurkaab1983f2011-01-18 15:50:17 -08001042
1043 final float UPDATE_THRESHOLD = 0.00001f;
1044 float hOffsetDelta = mFinalHorizontalWallpaperOffset - mHorizontalWallpaperOffset;
1045 float vOffsetDelta = mFinalVerticalWallpaperOffset - mVerticalWallpaperOffset;
Michael Jurkaca5b8362011-01-27 13:23:26 -08001046 boolean jumpToFinalValue = Math.abs(hOffsetDelta) < UPDATE_THRESHOLD &&
1047 Math.abs(vOffsetDelta) < UPDATE_THRESHOLD;
Michael Jurkaa6471802011-09-22 14:39:16 -07001048
1049 // Don't have any lag between workspace and wallpaper on non-large devices
Daniel Sandlercc8befa2013-06-11 14:45:48 -04001050 if (!LauncherAppState.isScreenLarge() || jumpToFinalValue) {
Michael Jurkaab1983f2011-01-18 15:50:17 -08001051 mHorizontalWallpaperOffset = mFinalHorizontalWallpaperOffset;
1052 mVerticalWallpaperOffset = mFinalVerticalWallpaperOffset;
1053 } else {
1054 float percentToCatchUpVertical =
Michael Jurkaca5b8362011-01-27 13:23:26 -08001055 Math.min(1.0f, timeSinceLastUpdate * fractionToCatchUpIn1MsVertical);
Michael Jurkaab1983f2011-01-18 15:50:17 -08001056 float percentToCatchUpHorizontal =
Michael Jurkaca5b8362011-01-27 13:23:26 -08001057 Math.min(1.0f, timeSinceLastUpdate * fractionToCatchUpIn1MsHorizontal);
Michael Jurkaab1983f2011-01-18 15:50:17 -08001058 mHorizontalWallpaperOffset += percentToCatchUpHorizontal * hOffsetDelta;
1059 mVerticalWallpaperOffset += percentToCatchUpVertical * vOffsetDelta;
1060 }
Michael Jurkaca5b8362011-01-27 13:23:26 -08001061
Michael Jurkaab1983f2011-01-18 15:50:17 -08001062 mLastWallpaperOffsetUpdateTime = System.currentTimeMillis();
1063 return true;
1064 }
1065
1066 public float getCurrX() {
1067 return mHorizontalWallpaperOffset;
1068 }
1069
1070 public float getFinalX() {
1071 return mFinalHorizontalWallpaperOffset;
1072 }
1073
1074 public float getCurrY() {
1075 return mVerticalWallpaperOffset;
1076 }
1077
1078 public float getFinalY() {
1079 return mFinalVerticalWallpaperOffset;
1080 }
1081
1082 public void setFinalX(float x) {
1083 mFinalHorizontalWallpaperOffset = Math.max(0f, Math.min(x, 1.0f));
1084 }
1085
1086 public void setFinalY(float y) {
1087 mFinalVerticalWallpaperOffset = Math.max(0f, Math.min(y, 1.0f));
1088 }
1089
1090 public void jumpToFinal() {
1091 mHorizontalWallpaperOffset = mFinalHorizontalWallpaperOffset;
1092 mVerticalWallpaperOffset = mFinalVerticalWallpaperOffset;
1093 }
Dianne Hackborn8f573952009-08-10 23:21:09 -07001094 }
Winson Chungaafa03c2010-06-11 17:34:16 -07001095
Michael Jurka340c5f32010-10-21 16:49:19 -07001096 @Override
1097 public void computeScroll() {
1098 super.computeScroll();
Adam Cohenbeff8c62011-08-31 17:46:01 -07001099 syncWallpaperOffsetWithScroll();
Michael Jurka340c5f32010-10-21 16:49:19 -07001100 }
1101
Patrick Dubroy94f78a52011-02-28 17:39:16 -08001102 void showOutlines() {
Michael Jurkad74c9842011-07-10 12:44:21 -07001103 if (!isSmall() && !mIsSwitchingState) {
Winson Chung9171e6d2010-11-17 17:39:27 -08001104 if (mChildrenOutlineFadeOutAnimation != null) mChildrenOutlineFadeOutAnimation.cancel();
1105 if (mChildrenOutlineFadeInAnimation != null) mChildrenOutlineFadeInAnimation.cancel();
Michael Jurka2ecf9952012-06-18 12:52:28 -07001106 mChildrenOutlineFadeInAnimation = LauncherAnimUtils.ofFloat(this, "childrenOutlineAlpha", 1.0f);
Winson Chung9171e6d2010-11-17 17:39:27 -08001107 mChildrenOutlineFadeInAnimation.setDuration(CHILDREN_OUTLINE_FADE_IN_DURATION);
1108 mChildrenOutlineFadeInAnimation.start();
Michael Jurka3e7c7632010-10-02 16:01:03 -07001109 }
Adam Cohenf34bab52010-09-30 14:11:56 -07001110 }
1111
Patrick Dubroy94f78a52011-02-28 17:39:16 -08001112 void hideOutlines() {
Michael Jurkad74c9842011-07-10 12:44:21 -07001113 if (!isSmall() && !mIsSwitchingState) {
Winson Chung9171e6d2010-11-17 17:39:27 -08001114 if (mChildrenOutlineFadeInAnimation != null) mChildrenOutlineFadeInAnimation.cancel();
1115 if (mChildrenOutlineFadeOutAnimation != null) mChildrenOutlineFadeOutAnimation.cancel();
Michael Jurka2ecf9952012-06-18 12:52:28 -07001116 mChildrenOutlineFadeOutAnimation = LauncherAnimUtils.ofFloat(this, "childrenOutlineAlpha", 0.0f);
Winson Chung9171e6d2010-11-17 17:39:27 -08001117 mChildrenOutlineFadeOutAnimation.setDuration(CHILDREN_OUTLINE_FADE_OUT_DURATION);
1118 mChildrenOutlineFadeOutAnimation.setStartDelay(CHILDREN_OUTLINE_FADE_OUT_DELAY);
1119 mChildrenOutlineFadeOutAnimation.start();
Michael Jurka3e7c7632010-10-02 16:01:03 -07001120 }
Adam Cohenf34bab52010-09-30 14:11:56 -07001121 }
1122
Patrick Dubroy94f78a52011-02-28 17:39:16 -08001123 public void showOutlinesTemporarily() {
1124 if (!mIsPageMoving && !isTouchActive()) {
1125 snapToPage(mCurrentPage);
1126 }
1127 }
1128
Winson Chung9171e6d2010-11-17 17:39:27 -08001129 public void setChildrenOutlineAlpha(float alpha) {
1130 mChildrenOutlineAlpha = alpha;
Adam Cohenf34bab52010-09-30 14:11:56 -07001131 for (int i = 0; i < getChildCount(); i++) {
1132 CellLayout cl = (CellLayout) getChildAt(i);
1133 cl.setBackgroundAlpha(alpha);
1134 }
1135 }
1136
Winson Chung9171e6d2010-11-17 17:39:27 -08001137 public float getChildrenOutlineAlpha() {
1138 return mChildrenOutlineAlpha;
1139 }
1140
Michael Jurka9c6fbed2011-03-02 17:41:34 -08001141 void disableBackground() {
1142 mDrawBackground = false;
1143 }
1144 void enableBackground() {
1145 mDrawBackground = true;
1146 }
1147
Michael Jurka7bdb25a2011-08-03 15:16:44 -07001148 private void animateBackgroundGradient(float finalAlpha, boolean animated) {
Winson Chungb4b7fa72010-11-18 14:38:53 -08001149 if (mBackground == null) return;
Michael Jurkab9e14972011-07-25 17:57:40 -07001150 if (mBackgroundFadeInAnimation != null) {
1151 mBackgroundFadeInAnimation.cancel();
1152 mBackgroundFadeInAnimation = null;
1153 }
1154 if (mBackgroundFadeOutAnimation != null) {
1155 mBackgroundFadeOutAnimation.cancel();
1156 mBackgroundFadeOutAnimation = null;
1157 }
Michael Jurka7bdb25a2011-08-03 15:16:44 -07001158 float startAlpha = getBackgroundAlpha();
1159 if (finalAlpha != startAlpha) {
1160 if (animated) {
Michael Jurkaf1ad6082013-03-13 12:55:46 +01001161 mBackgroundFadeOutAnimation =
1162 LauncherAnimUtils.ofFloat(this, startAlpha, finalAlpha);
Michael Jurka7bdb25a2011-08-03 15:16:44 -07001163 mBackgroundFadeOutAnimation.addUpdateListener(new AnimatorUpdateListener() {
1164 public void onAnimationUpdate(ValueAnimator animation) {
1165 setBackgroundAlpha(((Float) animation.getAnimatedValue()).floatValue());
1166 }
1167 });
1168 mBackgroundFadeOutAnimation.setInterpolator(new DecelerateInterpolator(1.5f));
1169 mBackgroundFadeOutAnimation.setDuration(BACKGROUND_FADE_OUT_DURATION);
1170 mBackgroundFadeOutAnimation.start();
1171 } else {
1172 setBackgroundAlpha(finalAlpha);
1173 }
Michael Jurkab9e14972011-07-25 17:57:40 -07001174 }
Winson Chung9171e6d2010-11-17 17:39:27 -08001175 }
1176
1177 public void setBackgroundAlpha(float alpha) {
Michael Jurka9c6fbed2011-03-02 17:41:34 -08001178 if (alpha != mBackgroundAlpha) {
1179 mBackgroundAlpha = alpha;
1180 invalidate();
1181 }
Winson Chung9171e6d2010-11-17 17:39:27 -08001182 }
1183
Adam Cohenf34bab52010-09-30 14:11:56 -07001184 public float getBackgroundAlpha() {
1185 return mBackgroundAlpha;
1186 }
1187
Adam Cohen68d73932010-11-15 10:50:58 -08001188 float backgroundAlphaInterpolator(float r) {
1189 float pivotA = 0.1f;
1190 float pivotB = 0.4f;
1191 if (r < pivotA) {
1192 return 0;
1193 } else if (r > pivotB) {
1194 return 1.0f;
1195 } else {
1196 return (r - pivotA)/(pivotB - pivotA);
1197 }
1198 }
1199
Michael Jurkaa3d30ad2012-05-08 13:43:43 -07001200 private void updatePageAlphaValues(int screenCenter) {
Michael Jurka869390b2012-05-06 15:55:19 -07001201 boolean isInOverscroll = mOverScrollX < 0 || mOverScrollX > mMaxScrollX;
1202 if (mWorkspaceFadeInAdjacentScreens &&
1203 mState == State.NORMAL &&
1204 !mIsSwitchingState &&
1205 !isInOverscroll) {
1206 for (int i = 0; i < getChildCount(); i++) {
1207 CellLayout child = (CellLayout) getChildAt(i);
1208 if (child != null) {
1209 float scrollProgress = getScrollProgress(screenCenter, child, i);
Adam Cohen73894962011-10-31 13:17:17 -07001210 float alpha = 1 - Math.abs(scrollProgress);
Michael Jurka869390b2012-05-06 15:55:19 -07001211 child.getShortcutsAndWidgets().setAlpha(alpha);
Michael Jurkaa3d30ad2012-05-08 13:43:43 -07001212 if (!mIsDragOccuring) {
1213 child.setBackgroundAlphaMultiplier(
1214 backgroundAlphaInterpolator(Math.abs(scrollProgress)));
1215 } else {
1216 child.setBackgroundAlphaMultiplier(1f);
1217 }
Adam Cohen73894962011-10-31 13:17:17 -07001218 }
Adam Cohenf34bab52010-09-30 14:11:56 -07001219 }
1220 }
Michael Jurkaa3d30ad2012-05-08 13:43:43 -07001221 }
1222
1223 private void setChildrenBackgroundAlphaMultipliers(float a) {
1224 for (int i = 0; i < getChildCount(); i++) {
1225 CellLayout child = (CellLayout) getChildAt(i);
1226 child.setBackgroundAlphaMultiplier(a);
1227 }
1228 }
1229
1230 @Override
1231 protected void screenScrolled(int screenCenter) {
Winson Chung52aee602013-01-30 12:01:02 -08001232 final boolean isRtl = isLayoutRtl();
Michael Jurkaa3d30ad2012-05-08 13:43:43 -07001233 super.screenScrolled(screenCenter);
1234
1235 updatePageAlphaValues(screenCenter);
Michael Jurkad51f33a2012-06-28 15:35:26 -07001236 enableHwLayersOnVisiblePages();
Adam Cohenf34bab52010-09-30 14:11:56 -07001237
Adam Cohenebea84d2011-11-09 17:20:41 -08001238 if (mOverScrollX < 0 || mOverScrollX > mMaxScrollX) {
Winson Chung52aee602013-01-30 12:01:02 -08001239 int index = 0;
1240 float pivotX = 0f;
1241 final float leftBiasedPivot = 0.25f;
1242 final float rightBiasedPivot = 0.75f;
1243 final int lowerIndex = 0;
1244 final int upperIndex = getChildCount() - 1;
1245 if (isRtl) {
1246 index = mOverScrollX < 0 ? upperIndex : lowerIndex;
1247 pivotX = (index == 0 ? leftBiasedPivot : rightBiasedPivot);
1248 } else {
1249 index = mOverScrollX < 0 ? lowerIndex : upperIndex;
1250 pivotX = (index == 0 ? rightBiasedPivot : leftBiasedPivot);
1251 }
1252
Adam Cohenb5ba0972011-09-07 18:02:31 -07001253 CellLayout cl = (CellLayout) getChildAt(index);
1254 float scrollProgress = getScrollProgress(screenCenter, cl, index);
Winson Chung52aee602013-01-30 12:01:02 -08001255 final boolean isLeftPage = (isRtl ? index > 0 : index == 0);
1256 cl.setOverScrollAmount(Math.abs(scrollProgress), isLeftPage);
1257 float rotation = -WORKSPACE_OVERSCROLL_ROTATION * scrollProgress;
Adam Cohenb5ba0972011-09-07 18:02:31 -07001258 cl.setRotationY(rotation);
Adam Cohen21b41102011-11-01 17:29:52 -07001259 setFadeForOverScroll(Math.abs(scrollProgress));
Michael Jurkab06d95f2012-04-02 06:26:53 -07001260 if (!mOverscrollTransformsSet) {
1261 mOverscrollTransformsSet = true;
Adam Cohen94309882012-06-08 16:24:56 -07001262 cl.setCameraDistance(mDensity * mCameraDistance);
Winson Chung52aee602013-01-30 12:01:02 -08001263 cl.setPivotX(cl.getMeasuredWidth() * pivotX);
Michael Jurkab06d95f2012-04-02 06:26:53 -07001264 cl.setPivotY(cl.getMeasuredHeight() * 0.5f);
1265 cl.setOverscrollTransformsDirty(true);
1266 }
Adam Cohenb5ba0972011-09-07 18:02:31 -07001267 } else {
Adam Cohen21b41102011-11-01 17:29:52 -07001268 if (mOverscrollFade != 0) {
1269 setFadeForOverScroll(0);
1270 }
Michael Jurkab06d95f2012-04-02 06:26:53 -07001271 if (mOverscrollTransformsSet) {
1272 mOverscrollTransformsSet = false;
Adam Cohenebea84d2011-11-09 17:20:41 -08001273 ((CellLayout) getChildAt(0)).resetOverscrollTransforms();
1274 ((CellLayout) getChildAt(getChildCount() - 1)).resetOverscrollTransforms();
Adam Cohen7842d7f2011-09-12 15:28:15 -07001275 }
Adam Cohenb5ba0972011-09-07 18:02:31 -07001276 }
1277 }
1278
1279 @Override
Adam Cohenb5ba0972011-09-07 18:02:31 -07001280 protected void overScroll(float amount) {
Michael Jurka869390b2012-05-06 15:55:19 -07001281 acceleratedOverScroll(amount);
Adam Cohenb5ba0972011-09-07 18:02:31 -07001282 }
1283
Joe Onorato00acb122009-08-04 16:04:30 -04001284 protected void onAttachedToWindow() {
1285 super.onAttachedToWindow();
Michael Jurka9c6fbed2011-03-02 17:41:34 -08001286 mWindowToken = getWindowToken();
Joe Onorato956091b2010-02-19 12:47:40 -08001287 computeScroll();
Michael Jurka9c6fbed2011-03-02 17:41:34 -08001288 mDragController.setWindowToken(mWindowToken);
1289 }
1290
1291 protected void onDetachedFromWindow() {
1292 mWindowToken = null;
Joe Onorato00acb122009-08-04 16:04:30 -04001293 }
1294
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001295 @Override
Michael Jurka28750fb2010-09-24 17:43:49 -07001296 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
Michael Jurkac5b262c2011-01-12 20:24:50 -08001297 if (mFirstLayout && mCurrentPage >= 0 && mCurrentPage < getChildCount()) {
1298 mUpdateWallpaperOffsetImmediately = true;
1299 }
Michael Jurka0142d492010-08-25 17:46:15 -07001300 super.onLayout(changed, left, top, right, bottom);
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001301 }
1302
1303 @Override
Winson Chung9171e6d2010-11-17 17:39:27 -08001304 protected void onDraw(Canvas canvas) {
Michael Jurkaab1983f2011-01-18 15:50:17 -08001305 updateWallpaperOffsets();
Michael Jurkac5b262c2011-01-12 20:24:50 -08001306
Winson Chung9171e6d2010-11-17 17:39:27 -08001307 // Draw the background gradient if necessary
Michael Jurka9c6fbed2011-03-02 17:41:34 -08001308 if (mBackground != null && mBackgroundAlpha > 0.0f && mDrawBackground) {
Winson Chung8d006d52010-11-29 15:55:29 -08001309 int alpha = (int) (mBackgroundAlpha * 255);
Winson Chungf0ea4d32011-06-06 14:27:16 -07001310 mBackground.setAlpha(alpha);
Michael Jurka8b805b12012-04-18 14:23:14 -07001311 mBackground.setBounds(getScrollX(), 0, getScrollX() + getMeasuredWidth(),
Winson Chungf0ea4d32011-06-06 14:27:16 -07001312 getMeasuredHeight());
1313 mBackground.draw(canvas);
Winson Chung9171e6d2010-11-17 17:39:27 -08001314 }
Adam Cohen073a46f2011-05-17 16:28:09 -07001315
Winson Chung9171e6d2010-11-17 17:39:27 -08001316 super.onDraw(canvas);
Winson Chungb8b2a5a2012-07-12 17:55:31 -07001317
1318 // Call back to LauncherModel to finish binding after the first draw
Romain Guyeeacd562012-10-10 18:47:33 -07001319 post(mBindPages);
Winson Chung9171e6d2010-11-17 17:39:27 -08001320 }
1321
Adam Cohen21b41102011-11-01 17:29:52 -07001322 boolean isDrawingBackgroundGradient() {
1323 return (mBackground != null && mBackgroundAlpha > 0.0f && mDrawBackground);
1324 }
1325
Michael Jurkadfab7f02011-11-18 13:01:04 -08001326 @Override
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001327 protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
Joe Onorato67886212009-09-14 19:05:05 -04001328 if (!mLauncher.isAllAppsVisible()) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001329 final Folder openFolder = getOpenFolder();
1330 if (openFolder != null) {
1331 return openFolder.requestFocus(direction, previouslyFocusedRect);
1332 } else {
Michael Jurka0142d492010-08-25 17:46:15 -07001333 return super.onRequestFocusInDescendants(direction, previouslyFocusedRect);
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001334 }
1335 }
1336 return false;
1337 }
1338
1339 @Override
Winson Chung97d85d22011-04-13 11:27:36 -07001340 public int getDescendantFocusability() {
Michael Jurkad74c9842011-07-10 12:44:21 -07001341 if (isSmall()) {
Winson Chung97d85d22011-04-13 11:27:36 -07001342 return ViewGroup.FOCUS_BLOCK_DESCENDANTS;
1343 }
1344 return super.getDescendantFocusability();
1345 }
1346
1347 @Override
Romain Guyc2e24c02009-06-01 16:11:41 -07001348 public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
Joe Onorato67886212009-09-14 19:05:05 -04001349 if (!mLauncher.isAllAppsVisible()) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001350 final Folder openFolder = getOpenFolder();
Michael Jurka0142d492010-08-25 17:46:15 -07001351 if (openFolder != null) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001352 openFolder.addFocusables(views, direction);
Michael Jurka0142d492010-08-25 17:46:15 -07001353 } else {
1354 super.addFocusables(views, direction, focusableMode);
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001355 }
1356 }
1357 }
1358
Michael Jurkad74c9842011-07-10 12:44:21 -07001359 public boolean isSmall() {
Adam Cohen3384c7b2011-07-17 15:48:21 -07001360 return mState == State.SMALL || mState == State.SPRING_LOADED;
Michael Jurkad74c9842011-07-10 12:44:21 -07001361 }
1362
Michael Jurka0142d492010-08-25 17:46:15 -07001363 void enableChildrenCache(int fromPage, int toPage) {
1364 if (fromPage > toPage) {
1365 final int temp = fromPage;
1366 fromPage = toPage;
1367 toPage = temp;
Mike Cleron3a2b3f22009-11-05 17:17:42 -08001368 }
Winson Chungaafa03c2010-06-11 17:34:16 -07001369
Michael Jurkadee05892010-07-27 10:01:56 -07001370 final int screenCount = getChildCount();
Adam Powellfea5d022010-04-29 11:42:45 -07001371
Michael Jurka0142d492010-08-25 17:46:15 -07001372 fromPage = Math.max(fromPage, 0);
1373 toPage = Math.min(toPage, screenCount - 1);
Adam Powellfea5d022010-04-29 11:42:45 -07001374
Michael Jurka0142d492010-08-25 17:46:15 -07001375 for (int i = fromPage; i <= toPage; i++) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001376 final CellLayout layout = (CellLayout) getChildAt(i);
1377 layout.setChildrenDrawnWithCacheEnabled(true);
1378 layout.setChildrenDrawingCacheEnabled(true);
1379 }
1380 }
1381
1382 void clearChildrenCache() {
Michael Jurkadee05892010-07-27 10:01:56 -07001383 final int screenCount = getChildCount();
1384 for (int i = 0; i < screenCount; i++) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001385 final CellLayout layout = (CellLayout) getChildAt(i);
1386 layout.setChildrenDrawnWithCacheEnabled(false);
Adam Cohen8182e5b2011-08-01 15:43:31 -07001387 // In software mode, we don't want the items to continue to be drawn into bitmaps
1388 if (!isHardwareAccelerated()) {
1389 layout.setChildrenDrawingCacheEnabled(false);
1390 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001391 }
1392 }
1393
Michael Jurka3a0469d2012-06-21 09:38:41 -07001394
1395 private void updateChildrenLayersEnabled(boolean force) {
Adam Cohen19f37922012-03-21 11:59:11 -07001396 boolean small = mState == State.SMALL || mIsSwitchingState;
Michael Jurka3a0469d2012-06-21 09:38:41 -07001397 boolean enableChildrenLayers = force || small || mAnimatingViewIntoPlace || isPageMoving();
Michael Jurkad74c9842011-07-10 12:44:21 -07001398
1399 if (enableChildrenLayers != mChildrenLayersEnabled) {
1400 mChildrenLayersEnabled = enableChildrenLayers;
Michael Jurkad51f33a2012-06-28 15:35:26 -07001401 if (mChildrenLayersEnabled) {
1402 enableHwLayersOnVisiblePages();
1403 } else {
1404 for (int i = 0; i < getPageCount(); i++) {
1405 final CellLayout cl = (CellLayout) getChildAt(i);
1406 cl.disableHardwareLayers();
1407 }
1408 }
1409 }
1410 }
1411
1412 private void enableHwLayersOnVisiblePages() {
1413 if (mChildrenLayersEnabled) {
1414 final int screenCount = getChildCount();
1415 getVisiblePages(mTempVisiblePagesRange);
1416 int leftScreen = mTempVisiblePagesRange[0];
1417 int rightScreen = mTempVisiblePagesRange[1];
1418 if (leftScreen == rightScreen) {
1419 // make sure we're caching at least two pages always
1420 if (rightScreen < screenCount - 1) {
1421 rightScreen++;
1422 } else if (leftScreen > 0) {
1423 leftScreen--;
1424 }
1425 }
1426 for (int i = 0; i < screenCount; i++) {
Michael Jurka47639b92013-01-14 12:42:27 +01001427 final CellLayout layout = (CellLayout) getPageAt(i);
Michael Jurkad51f33a2012-06-28 15:35:26 -07001428 if (!(leftScreen <= i && i <= rightScreen && shouldDrawChild(layout))) {
1429 layout.disableHardwareLayers();
1430 }
1431 }
1432 for (int i = 0; i < screenCount; i++) {
Michael Jurka47639b92013-01-14 12:42:27 +01001433 final CellLayout layout = (CellLayout) getPageAt(i);
Michael Jurkad51f33a2012-06-28 15:35:26 -07001434 if (leftScreen <= i && i <= rightScreen && shouldDrawChild(layout)) {
1435 layout.enableHardwareLayers();
1436 }
Michael Jurkad74c9842011-07-10 12:44:21 -07001437 }
Michael Jurkace7e05f2011-02-01 22:02:35 -08001438 }
Michael Jurkace7e05f2011-02-01 22:02:35 -08001439 }
1440
Michael Jurka3a0469d2012-06-21 09:38:41 -07001441 public void buildPageHardwareLayers() {
1442 // force layers to be enabled just for the call to buildLayer
1443 updateChildrenLayersEnabled(true);
1444 if (getWindowToken() != null) {
1445 final int childCount = getChildCount();
1446 for (int i = 0; i < childCount; i++) {
1447 CellLayout cl = (CellLayout) getChildAt(i);
Michael Jurkad51f33a2012-06-28 15:35:26 -07001448 cl.buildHardwareLayer();
Michael Jurka3a0469d2012-06-21 09:38:41 -07001449 }
1450 }
1451 updateChildrenLayersEnabled(false);
1452 }
1453
Jeff Brown1d0867c2010-12-02 18:27:39 -08001454 protected void onWallpaperTap(MotionEvent ev) {
1455 final int[] position = mTempCell;
1456 getLocationOnScreen(position);
1457
1458 int pointerIndex = ev.getActionIndex();
1459 position[0] += (int) ev.getX(pointerIndex);
1460 position[1] += (int) ev.getY(pointerIndex);
1461
1462 mWallpaperManager.sendWallpaperCommand(getWindowToken(),
1463 ev.getAction() == MotionEvent.ACTION_UP
1464 ? WallpaperManager.COMMAND_TAP : WallpaperManager.COMMAND_SECONDARY_TAP,
1465 position[0], position[1], 0, null);
1466 }
1467
Adam Cohen61033d32010-11-15 18:29:44 -08001468 /*
1469 * This interpolator emulates the rate at which the perceived scale of an object changes
1470 * as its distance from a camera increases. When this interpolator is applied to a scale
1471 * animation on a view, it evokes the sense that the object is shrinking due to moving away
Andrew Flynn0dca1ec2012-02-29 13:33:22 -08001472 * from the camera.
Adam Cohen61033d32010-11-15 18:29:44 -08001473 */
1474 static class ZInterpolator implements TimeInterpolator {
1475 private float focalLength;
1476
1477 public ZInterpolator(float foc) {
1478 focalLength = foc;
1479 }
1480
Adam Coheneed565d2010-11-15 11:30:05 -08001481 public float getInterpolation(float input) {
1482 return (1.0f - focalLength / (focalLength + input)) /
Adam Cohen61033d32010-11-15 18:29:44 -08001483 (1.0f - focalLength / (focalLength + 1.0f));
Adam Cohencbbaf982010-11-12 14:50:33 -08001484 }
1485 }
1486
Adam Cohen61033d32010-11-15 18:29:44 -08001487 /*
1488 * The exact reverse of ZInterpolator.
1489 */
1490 static class InverseZInterpolator implements TimeInterpolator {
1491 private ZInterpolator zInterpolator;
1492 public InverseZInterpolator(float foc) {
1493 zInterpolator = new ZInterpolator(foc);
1494 }
Adam Cohencbbaf982010-11-12 14:50:33 -08001495 public float getInterpolation(float input) {
Adam Cohen61033d32010-11-15 18:29:44 -08001496 return 1 - zInterpolator.getInterpolation(1 - input);
Adam Cohencbbaf982010-11-12 14:50:33 -08001497 }
1498 }
1499
Adam Cohen61033d32010-11-15 18:29:44 -08001500 /*
1501 * ZInterpolator compounded with an ease-out.
1502 */
1503 static class ZoomOutInterpolator implements TimeInterpolator {
Adam Cohenb64d36e2011-10-17 21:48:02 -07001504 private final DecelerateInterpolator decelerate = new DecelerateInterpolator(0.75f);
1505 private final ZInterpolator zInterpolator = new ZInterpolator(0.13f);
Adam Cohen61033d32010-11-15 18:29:44 -08001506
1507 public float getInterpolation(float input) {
1508 return decelerate.getInterpolation(zInterpolator.getInterpolation(input));
1509 }
1510 }
1511
1512 /*
1513 * InvereZInterpolator compounded with an ease-out.
1514 */
1515 static class ZoomInInterpolator implements TimeInterpolator {
1516 private final InverseZInterpolator inverseZInterpolator = new InverseZInterpolator(0.35f);
1517 private final DecelerateInterpolator decelerate = new DecelerateInterpolator(3.0f);
1518
1519 public float getInterpolation(float input) {
1520 return decelerate.getInterpolation(inverseZInterpolator.getInterpolation(input));
1521 }
1522 }
1523
Adam Cohen61033d32010-11-15 18:29:44 -08001524 private final ZoomInInterpolator mZoomInInterpolator = new ZoomInInterpolator();
Michael Jurka3e7c7632010-10-02 16:01:03 -07001525
Michael Jurka3e7c7632010-10-02 16:01:03 -07001526 /*
Adam Cohen66396872011-04-15 17:50:36 -07001527 *
1528 * We call these methods (onDragStartedWithItemSpans/onDragStartedWithSize) whenever we
1529 * start a drag in Launcher, regardless of whether the drag has ever entered the Workspace
1530 *
1531 * These methods mark the appropriate pages as accepting drops (which alters their visual
1532 * appearance).
1533 *
1534 */
1535 public void onDragStartedWithItem(View v) {
Adam Cohen66396872011-04-15 17:50:36 -07001536 final Canvas canvas = new Canvas();
1537
Adam Cohen66396872011-04-15 17:50:36 -07001538 // The outline is used to visualize where the item will land if dropped
Adam Cohend41fbf52012-02-16 23:53:59 -08001539 mDragOutline = createDragOutline(v, canvas, DRAG_BITMAP_PADDING);
Adam Cohen66396872011-04-15 17:50:36 -07001540 }
1541
Michael Jurka8c3339b2012-06-14 16:18:21 -07001542 public void onDragStartedWithItem(PendingAddItemInfo info, Bitmap b, boolean clipAlpha) {
Michael Jurkad3ef3062010-11-23 16:23:58 -08001543 final Canvas canvas = new Canvas();
1544
Michael Jurka038f9d82011-11-03 13:50:45 -07001545 int[] size = estimateItemSize(info.spanX, info.spanY, info, false);
Adam Cohen66396872011-04-15 17:50:36 -07001546
Michael Jurkad3ef3062010-11-23 16:23:58 -08001547 // The outline is used to visualize where the item will land if dropped
Adam Cohend41fbf52012-02-16 23:53:59 -08001548 mDragOutline = createDragOutline(b, canvas, DRAG_BITMAP_PADDING, size[0],
Michael Jurka8c3339b2012-06-14 16:18:21 -07001549 size[1], clipAlpha);
Michael Jurka3e7c7632010-10-02 16:01:03 -07001550 }
1551
Patrick Dubroy758a9232011-03-03 19:54:56 -08001552 public void exitWidgetResizeMode() {
Adam Cohen716b51e2011-06-30 12:09:54 -07001553 DragLayer dragLayer = mLauncher.getDragLayer();
Adam Cohen67882692011-03-11 15:29:03 -08001554 dragLayer.clearAllResizeFrames();
Patrick Dubroy758a9232011-03-03 19:54:56 -08001555 }
1556
Adam Cohen4b285c52011-07-21 14:24:06 -07001557 private void initAnimationArrays() {
1558 final int childCount = getChildCount();
1559 if (mOldTranslationXs != null) return;
1560 mOldTranslationXs = new float[childCount];
1561 mOldTranslationYs = new float[childCount];
1562 mOldScaleXs = new float[childCount];
1563 mOldScaleYs = new float[childCount];
1564 mOldBackgroundAlphas = new float[childCount];
Adam Cohen4b285c52011-07-21 14:24:06 -07001565 mOldAlphas = new float[childCount];
Adam Cohen4b285c52011-07-21 14:24:06 -07001566 mNewTranslationXs = new float[childCount];
1567 mNewTranslationYs = new float[childCount];
1568 mNewScaleXs = new float[childCount];
1569 mNewScaleYs = new float[childCount];
1570 mNewBackgroundAlphas = new float[childCount];
Adam Cohen4b285c52011-07-21 14:24:06 -07001571 mNewAlphas = new float[childCount];
1572 mNewRotationYs = new float[childCount];
1573 }
1574
Michael Jurka2a4b1a82011-12-07 14:00:02 -08001575 Animator getChangeStateAnimation(final State state, boolean animated) {
1576 return getChangeStateAnimation(state, animated, 0);
Adam Cohen7777d962011-08-18 18:58:38 -07001577 }
1578
Michael Jurka2a4b1a82011-12-07 14:00:02 -08001579 Animator getChangeStateAnimation(final State state, boolean animated, int delay) {
Michael Jurkabdf78552011-10-31 14:34:25 -07001580 if (mState == state) {
Michael Jurka2a4b1a82011-12-07 14:00:02 -08001581 return null;
Michael Jurka99633da2011-07-27 22:40:17 -07001582 }
1583
Winson Chung1b7c1d32011-10-25 12:09:38 -07001584 // Initialize animation arrays for the first time if necessary
1585 initAnimationArrays();
1586
Michael Jurka2ecf9952012-06-18 12:52:28 -07001587 AnimatorSet anim = animated ? LauncherAnimUtils.createAnimatorSet() : null;
Adam Lesinski6b879f02010-11-04 16:15:23 -07001588
Adam Cohen7777d962011-08-18 18:58:38 -07001589 // Stop any scrolling, move to the current page right away
Winson Chung360e63f2012-04-27 13:48:05 -07001590 setCurrentPage(getNextPage());
Winson Chungde1af762011-07-21 16:44:07 -07001591
Winson Chung1b7c1d32011-10-25 12:09:38 -07001592 final State oldState = mState;
1593 final boolean oldStateIsNormal = (oldState == State.NORMAL);
Michael Jurka4ff7d792012-04-02 03:46:50 -07001594 final boolean oldStateIsSpringLoaded = (oldState == State.SPRING_LOADED);
Winson Chung1b7c1d32011-10-25 12:09:38 -07001595 final boolean oldStateIsSmall = (oldState == State.SMALL);
Adam Cohen7777d962011-08-18 18:58:38 -07001596 mState = state;
Winson Chung1b7c1d32011-10-25 12:09:38 -07001597 final boolean stateIsNormal = (state == State.NORMAL);
1598 final boolean stateIsSpringLoaded = (state == State.SPRING_LOADED);
1599 final boolean stateIsSmall = (state == State.SMALL);
1600 float finalScaleFactor = 1.0f;
1601 float finalBackgroundAlpha = stateIsSpringLoaded ? 1.0f : 0f;
1602 float translationX = 0;
1603 float translationY = 0;
Adam Cohen7777d962011-08-18 18:58:38 -07001604 boolean zoomIn = true;
Adam Cohenbeff8c62011-08-31 17:46:01 -07001605
Adam Cohen7777d962011-08-18 18:58:38 -07001606 if (state != State.NORMAL) {
Winson Chung1b7c1d32011-10-25 12:09:38 -07001607 finalScaleFactor = mSpringLoadedShrinkFactor - (stateIsSmall ? 0.1f : 0);
Winson Chung8aad6102012-05-11 16:27:49 -07001608 setPageSpacing(mSpringLoadedPageSpacing);
Winson Chung1b7c1d32011-10-25 12:09:38 -07001609 if (oldStateIsNormal && stateIsSmall) {
Adam Cohen7777d962011-08-18 18:58:38 -07001610 zoomIn = false;
Adam Cohen7777d962011-08-18 18:58:38 -07001611 setLayoutScale(finalScaleFactor);
Michael Jurka3a0469d2012-06-21 09:38:41 -07001612 updateChildrenLayersEnabled(false);
Michael Jurkaca5b8362011-01-27 13:23:26 -08001613 } else {
Adam Cohencff6af82011-09-13 14:51:53 -07001614 finalBackgroundAlpha = 1.0f;
Adam Cohen7777d962011-08-18 18:58:38 -07001615 setLayoutScale(finalScaleFactor);
1616 }
1617 } else {
Michael Jurka37990b42012-09-25 15:14:30 -07001618 setPageSpacing(mOriginalPageSpacing);
Adam Cohen7777d962011-08-18 18:58:38 -07001619 setLayoutScale(1.0f);
Adam Cohen7777d962011-08-18 18:58:38 -07001620 }
1621
Andrew Flynn0dca1ec2012-02-29 13:33:22 -08001622 final int duration = zoomIn ?
Adam Cohen7777d962011-08-18 18:58:38 -07001623 getResources().getInteger(R.integer.config_workspaceUnshrinkTime) :
1624 getResources().getInteger(R.integer.config_appsCustomizeWorkspaceShrinkTime);
Winson Chung1b7c1d32011-10-25 12:09:38 -07001625 for (int i = 0; i < getChildCount(); i++) {
1626 final CellLayout cl = (CellLayout) getChildAt(i);
Michael Jurka869390b2012-05-06 15:55:19 -07001627 float finalAlpha = (!mWorkspaceFadeInAdjacentScreens || stateIsSpringLoaded ||
Winson Chung1b7c1d32011-10-25 12:09:38 -07001628 (i == mCurrentPage)) ? 1f : 0f;
Michael Jurka869390b2012-05-06 15:55:19 -07001629 float currentAlpha = cl.getShortcutsAndWidgets().getAlpha();
1630 float initialAlpha = currentAlpha;
Adam Cohen7777d962011-08-18 18:58:38 -07001631
Winson Chung1b7c1d32011-10-25 12:09:38 -07001632 // Determine the pages alpha during the state transition
1633 if ((oldStateIsSmall && stateIsNormal) ||
1634 (oldStateIsNormal && stateIsSmall)) {
1635 // To/from workspace - only show the current page unless the transition is not
Michael Jurka4ff7d792012-04-02 03:46:50 -07001636 // animated and the animation end callback below doesn't run;
1637 // or, if we're in spring-loaded mode
1638 if (i == mCurrentPage || !animated || oldStateIsSpringLoaded) {
Winson Chung1b7c1d32011-10-25 12:09:38 -07001639 finalAlpha = 1f;
Winson Chung1b7c1d32011-10-25 12:09:38 -07001640 } else {
1641 initialAlpha = 0f;
1642 finalAlpha = 0f;
1643 }
Adam Cohen7777d962011-08-18 18:58:38 -07001644 }
1645
Winson Chung1b7c1d32011-10-25 12:09:38 -07001646 mOldAlphas[i] = initialAlpha;
1647 mNewAlphas[i] = finalAlpha;
Adam Cohen7777d962011-08-18 18:58:38 -07001648 if (animated) {
1649 mOldTranslationXs[i] = cl.getTranslationX();
1650 mOldTranslationYs[i] = cl.getTranslationY();
1651 mOldScaleXs[i] = cl.getScaleX();
1652 mOldScaleYs[i] = cl.getScaleY();
1653 mOldBackgroundAlphas[i] = cl.getBackgroundAlpha();
Adam Cohen7777d962011-08-18 18:58:38 -07001654
1655 mNewTranslationXs[i] = translationX;
1656 mNewTranslationYs[i] = translationY;
1657 mNewScaleXs[i] = finalScaleFactor;
1658 mNewScaleYs[i] = finalScaleFactor;
1659 mNewBackgroundAlphas[i] = finalBackgroundAlpha;
Adam Cohen7777d962011-08-18 18:58:38 -07001660 } else {
1661 cl.setTranslationX(translationX);
1662 cl.setTranslationY(translationY);
1663 cl.setScaleX(finalScaleFactor);
1664 cl.setScaleY(finalScaleFactor);
Winson Chung1b7c1d32011-10-25 12:09:38 -07001665 cl.setBackgroundAlpha(finalBackgroundAlpha);
Michael Jurkaa52570f2012-03-20 03:18:20 -07001666 cl.setShortcutAndWidgetAlpha(finalAlpha);
Adam Cohen7777d962011-08-18 18:58:38 -07001667 }
Michael Jurkadee05892010-07-27 10:01:56 -07001668 }
Winson Chung8d006d52010-11-29 15:55:29 -08001669
Adam Cohen7777d962011-08-18 18:58:38 -07001670 if (animated) {
Michael Jurka7407d2a2011-12-12 21:48:38 -08001671 for (int index = 0; index < getChildCount(); index++) {
1672 final int i = index;
1673 final CellLayout cl = (CellLayout) getChildAt(i);
Michael Jurka869390b2012-05-06 15:55:19 -07001674 float currentAlpha = cl.getShortcutsAndWidgets().getAlpha();
Michael Jurka2a4b1a82011-12-07 14:00:02 -08001675 if (mOldAlphas[i] == 0 && mNewAlphas[i] == 0) {
Michael Jurka7372c592012-01-16 04:21:35 -08001676 cl.setTranslationX(mNewTranslationXs[i]);
1677 cl.setTranslationY(mNewTranslationYs[i]);
1678 cl.setScaleX(mNewScaleXs[i]);
1679 cl.setScaleY(mNewScaleYs[i]);
1680 cl.setBackgroundAlpha(mNewBackgroundAlphas[i]);
Michael Jurkaa52570f2012-03-20 03:18:20 -07001681 cl.setShortcutAndWidgetAlpha(mNewAlphas[i]);
Michael Jurka7372c592012-01-16 04:21:35 -08001682 cl.setRotationY(mNewRotationYs[i]);
Michael Jurka7407d2a2011-12-12 21:48:38 -08001683 } else {
1684 LauncherViewPropertyAnimator a = new LauncherViewPropertyAnimator(cl);
1685 a.translationX(mNewTranslationXs[i])
1686 .translationY(mNewTranslationYs[i])
1687 .scaleX(mNewScaleXs[i])
1688 .scaleY(mNewScaleYs[i])
1689 .setDuration(duration)
1690 .setInterpolator(mZoomInInterpolator);
Michael Jurka7407d2a2011-12-12 21:48:38 -08001691 anim.play(a);
Michael Jurkaa52570f2012-03-20 03:18:20 -07001692
Michael Jurka869390b2012-05-06 15:55:19 -07001693 if (mOldAlphas[i] != mNewAlphas[i] || currentAlpha != mNewAlphas[i]) {
Michael Jurka6c8a5792012-03-22 05:24:37 -07001694 LauncherViewPropertyAnimator alphaAnim =
1695 new LauncherViewPropertyAnimator(cl.getShortcutsAndWidgets());
Michael Jurkaa52570f2012-03-20 03:18:20 -07001696 alphaAnim.alpha(mNewAlphas[i])
1697 .setDuration(duration)
1698 .setInterpolator(mZoomInInterpolator);
1699 anim.play(alphaAnim);
1700 }
Michael Jurka7407d2a2011-12-12 21:48:38 -08001701 if (mOldBackgroundAlphas[i] != 0 ||
Michael Jurka869390b2012-05-06 15:55:19 -07001702 mNewBackgroundAlphas[i] != 0) {
Michael Jurkaf1ad6082013-03-13 12:55:46 +01001703 ValueAnimator bgAnim =
1704 LauncherAnimUtils.ofFloat(cl, 0f, 1f).setDuration(duration);
Michael Jurka7407d2a2011-12-12 21:48:38 -08001705 bgAnim.setInterpolator(mZoomInInterpolator);
1706 bgAnim.addUpdateListener(new LauncherAnimatorUpdateListener() {
1707 public void onAnimationUpdate(float a, float b) {
Michael Jurka7372c592012-01-16 04:21:35 -08001708 cl.setBackgroundAlpha(
Michael Jurka7407d2a2011-12-12 21:48:38 -08001709 a * mOldBackgroundAlphas[i] +
1710 b * mNewBackgroundAlphas[i]);
Michael Jurka7407d2a2011-12-12 21:48:38 -08001711 }
1712 });
1713 anim.play(bgAnim);
1714 }
Michael Jurka2a4b1a82011-12-07 14:00:02 -08001715 }
1716 }
Michael Jurka2a4b1a82011-12-07 14:00:02 -08001717 anim.setStartDelay(delay);
Adam Cohen7777d962011-08-18 18:58:38 -07001718 }
1719
Winson Chung1b7c1d32011-10-25 12:09:38 -07001720 if (stateIsSpringLoaded) {
Michael Jurka7bdb25a2011-08-03 15:16:44 -07001721 // Right now we're covered by Apps Customize
1722 // Show the background gradient immediately, so the gradient will
1723 // be showing once AppsCustomize disappears
1724 animateBackgroundGradient(getResources().getInteger(
1725 R.integer.config_appsCustomizeSpringLoadedBgAlpha) / 100f, false);
1726 } else {
1727 // Fade the background gradient away
1728 animateBackgroundGradient(0f, true);
1729 }
Michael Jurka2a4b1a82011-12-07 14:00:02 -08001730 return anim;
Michael Jurkadee05892010-07-27 10:01:56 -07001731 }
1732
Michael Jurkabed61d22012-02-14 22:51:29 -08001733 @Override
Michael Jurkaa35e35a2012-04-26 15:04:28 -07001734 public void onLauncherTransitionPrepare(Launcher l, boolean animated, boolean toWorkspace) {
Michael Jurkabed61d22012-02-14 22:51:29 -08001735 mIsSwitchingState = true;
Michael Jurka315d38e2013-03-07 13:15:10 +01001736 updateChildrenLayersEnabled(false);
Michael Jurka72db6d72012-03-23 08:06:02 -07001737 cancelScrollingIndicatorAnimations();
Michael Jurkabed61d22012-02-14 22:51:29 -08001738 }
1739
1740 @Override
Michael Jurkaa35e35a2012-04-26 15:04:28 -07001741 public void onLauncherTransitionStart(Launcher l, boolean animated, boolean toWorkspace) {
1742 }
1743
1744 @Override
Winson Chung70442722012-02-10 15:43:22 -08001745 public void onLauncherTransitionStep(Launcher l, float t) {
1746 mTransitionProgress = t;
1747 }
1748
1749 @Override
Michael Jurkabed61d22012-02-14 22:51:29 -08001750 public void onLauncherTransitionEnd(Launcher l, boolean animated, boolean toWorkspace) {
1751 mIsSwitchingState = false;
1752 mWallpaperOffset.setOverrideHorizontalCatchupConstant(false);
Michael Jurka3a0469d2012-06-21 09:38:41 -07001753 updateChildrenLayersEnabled(false);
Michael Jurkabed61d22012-02-14 22:51:29 -08001754 // The code in getChangeStateAnimation to determine initialAlpha and finalAlpha will ensure
1755 // ensure that only the current page is visible during (and subsequently, after) the
1756 // transition animation. If fade adjacent pages is disabled, then re-enable the page
1757 // visibility after the transition animation.
Michael Jurka869390b2012-05-06 15:55:19 -07001758 if (!mWorkspaceFadeInAdjacentScreens) {
Michael Jurkabed61d22012-02-14 22:51:29 -08001759 for (int i = 0; i < getChildCount(); i++) {
1760 final CellLayout cl = (CellLayout) getChildAt(i);
Michael Jurkaa52570f2012-03-20 03:18:20 -07001761 cl.setShortcutAndWidgetAlpha(1f);
Michael Jurkabed61d22012-02-14 22:51:29 -08001762 }
1763 }
1764 }
1765
1766 @Override
1767 public View getContent() {
1768 return this;
1769 }
1770
Joe Onorato4be866d2010-10-10 11:26:02 -07001771 /**
1772 * Draw the View v into the given Canvas.
1773 *
1774 * @param v the view to draw
1775 * @param destCanvas the canvas to draw on
1776 * @param padding the horizontal and vertical padding to use when drawing
1777 */
Adam Cohenac8c8762011-07-13 11:15:27 -07001778 private void drawDragView(View v, Canvas destCanvas, int padding, boolean pruneToDrawable) {
Joe Onorato4be866d2010-10-10 11:26:02 -07001779 final Rect clipRect = mTempRect;
1780 v.getDrawingRect(clipRect);
1781
Adam Cohen099f60d2011-08-23 21:07:26 -07001782 boolean textVisible = false;
1783
Adam Cohenac8c8762011-07-13 11:15:27 -07001784 destCanvas.save();
1785 if (v instanceof TextView && pruneToDrawable) {
1786 Drawable d = ((TextView) v).getCompoundDrawables()[1];
1787 clipRect.set(0, 0, d.getIntrinsicWidth() + padding, d.getIntrinsicHeight() + padding);
1788 destCanvas.translate(padding / 2, padding / 2);
1789 d.draw(destCanvas);
1790 } else {
1791 if (v instanceof FolderIcon) {
Adam Cohen099f60d2011-08-23 21:07:26 -07001792 // For FolderIcons the text can bleed into the icon area, and so we need to
1793 // hide the text completely (which can't be achieved by clipping).
1794 if (((FolderIcon) v).getTextVisible()) {
1795 ((FolderIcon) v).setTextVisible(false);
1796 textVisible = true;
1797 }
Adam Cohenac8c8762011-07-13 11:15:27 -07001798 } else if (v instanceof BubbleTextView) {
1799 final BubbleTextView tv = (BubbleTextView) v;
1800 clipRect.bottom = tv.getExtendedPaddingTop() - (int) BubbleTextView.PADDING_V +
1801 tv.getLayout().getLineTop(0);
1802 } else if (v instanceof TextView) {
1803 final TextView tv = (TextView) v;
1804 clipRect.bottom = tv.getExtendedPaddingTop() - tv.getCompoundDrawablePadding() +
1805 tv.getLayout().getLineTop(0);
1806 }
1807 destCanvas.translate(-v.getScrollX() + padding / 2, -v.getScrollY() + padding / 2);
1808 destCanvas.clipRect(clipRect, Op.REPLACE);
1809 v.draw(destCanvas);
Adam Cohen099f60d2011-08-23 21:07:26 -07001810
1811 // Restore text visibility of FolderIcon if necessary
1812 if (textVisible) {
1813 ((FolderIcon) v).setTextVisible(true);
1814 }
Adam Cohenac8c8762011-07-13 11:15:27 -07001815 }
1816 destCanvas.restore();
1817 }
1818
1819 /**
1820 * Returns a new bitmap to show when the given View is being dragged around.
1821 * Responsibility for the bitmap is transferred to the caller.
1822 */
1823 public Bitmap createDragBitmap(View v, Canvas canvas, int padding) {
Adam Cohenac8c8762011-07-13 11:15:27 -07001824 Bitmap b;
1825
1826 if (v instanceof TextView) {
1827 Drawable d = ((TextView) v).getCompoundDrawables()[1];
1828 b = Bitmap.createBitmap(d.getIntrinsicWidth() + padding,
1829 d.getIntrinsicHeight() + padding, Bitmap.Config.ARGB_8888);
1830 } else {
1831 b = Bitmap.createBitmap(
1832 v.getWidth() + padding, v.getHeight() + padding, Bitmap.Config.ARGB_8888);
Joe Onorato4be866d2010-10-10 11:26:02 -07001833 }
1834
Adam Cohenac8c8762011-07-13 11:15:27 -07001835 canvas.setBitmap(b);
1836 drawDragView(v, canvas, padding, true);
Adam Cohenaaf473c2011-08-03 12:02:47 -07001837 canvas.setBitmap(null);
Joe Onorato4be866d2010-10-10 11:26:02 -07001838
Adam Cohenac8c8762011-07-13 11:15:27 -07001839 return b;
Joe Onorato4be866d2010-10-10 11:26:02 -07001840 }
1841
1842 /**
1843 * Returns a new bitmap to be used as the object outline, e.g. to visualize the drop location.
1844 * Responsibility for the bitmap is transferred to the caller.
1845 */
1846 private Bitmap createDragOutline(View v, Canvas canvas, int padding) {
Winson Chungea359c62011-08-03 17:06:35 -07001847 final int outlineColor = getResources().getColor(android.R.color.holo_blue_light);
Joe Onorato4be866d2010-10-10 11:26:02 -07001848 final Bitmap b = Bitmap.createBitmap(
1849 v.getWidth() + padding, v.getHeight() + padding, Bitmap.Config.ARGB_8888);
1850
1851 canvas.setBitmap(b);
Winson Chungb8c69f32011-10-19 21:36:08 -07001852 drawDragView(v, canvas, padding, true);
Adam Cohen5bb50bd2010-12-03 11:39:55 -08001853 mOutlineHelper.applyMediumExpensiveOutlineWithBlur(b, canvas, outlineColor, outlineColor);
Adam Cohenaaf473c2011-08-03 12:02:47 -07001854 canvas.setBitmap(null);
Joe Onorato4be866d2010-10-10 11:26:02 -07001855 return b;
1856 }
1857
1858 /**
Michael Jurkad3ef3062010-11-23 16:23:58 -08001859 * Returns a new bitmap to be used as the object outline, e.g. to visualize the drop location.
1860 * Responsibility for the bitmap is transferred to the caller.
1861 */
Peter Ng8db70002011-10-25 15:40:08 -07001862 private Bitmap createDragOutline(Bitmap orig, Canvas canvas, int padding, int w, int h,
Michael Jurka8c3339b2012-06-14 16:18:21 -07001863 boolean clipAlpha) {
Winson Chungea359c62011-08-03 17:06:35 -07001864 final int outlineColor = getResources().getColor(android.R.color.holo_blue_light);
Michael Jurkaf12c75c2011-01-25 22:41:40 -08001865 final Bitmap b = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
Michael Jurkad3ef3062010-11-23 16:23:58 -08001866 canvas.setBitmap(b);
Michael Jurkaf12c75c2011-01-25 22:41:40 -08001867
1868 Rect src = new Rect(0, 0, orig.getWidth(), orig.getHeight());
1869 float scaleFactor = Math.min((w - padding) / (float) orig.getWidth(),
1870 (h - padding) / (float) orig.getHeight());
1871 int scaledWidth = (int) (scaleFactor * orig.getWidth());
1872 int scaledHeight = (int) (scaleFactor * orig.getHeight());
1873 Rect dst = new Rect(0, 0, scaledWidth, scaledHeight);
1874
1875 // center the image
1876 dst.offset((w - scaledWidth) / 2, (h - scaledHeight) / 2);
1877
Winson Chung1120e032011-11-22 16:11:31 -08001878 canvas.drawBitmap(orig, src, dst, null);
Peter Ng8db70002011-10-25 15:40:08 -07001879 mOutlineHelper.applyMediumExpensiveOutlineWithBlur(b, canvas, outlineColor, outlineColor,
Michael Jurka8c3339b2012-06-14 16:18:21 -07001880 clipAlpha);
Adam Cohenaaf473c2011-08-03 12:02:47 -07001881 canvas.setBitmap(null);
Michael Jurkad3ef3062010-11-23 16:23:58 -08001882
1883 return b;
1884 }
1885
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001886 void startDrag(CellLayout.CellInfo cellInfo) {
1887 View child = cellInfo.cell;
Winson Chungaafa03c2010-06-11 17:34:16 -07001888
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001889 // Make sure the drag was started by a long press as opposed to a long click.
Bjorn Bringert7984c942009-12-09 15:38:25 +00001890 if (!child.isInTouchMode()) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001891 return;
1892 }
Winson Chungaafa03c2010-06-11 17:34:16 -07001893
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001894 mDragInfo = cellInfo;
Adam Cohend41fbf52012-02-16 23:53:59 -08001895 child.setVisibility(INVISIBLE);
Adam Cohen482ed822012-03-02 14:15:13 -08001896 CellLayout layout = (CellLayout) child.getParent().getParent();
1897 layout.prepareChildForDrag(child);
Joe Onorato4be866d2010-10-10 11:26:02 -07001898
1899 child.clearFocus();
1900 child.setPressed(false);
1901
1902 final Canvas canvas = new Canvas();
1903
1904 // The outline is used to visualize where the item will land if dropped
Adam Cohend41fbf52012-02-16 23:53:59 -08001905 mDragOutline = createDragOutline(child, canvas, DRAG_BITMAP_PADDING);
Adam Cohenac8c8762011-07-13 11:15:27 -07001906 beginDragShared(child, this);
1907 }
1908
1909 public void beginDragShared(View child, DragSource source) {
Winson Chungb8c69f32011-10-19 21:36:08 -07001910 Resources r = getResources();
1911
Joe Onorato4be866d2010-10-10 11:26:02 -07001912 // The drag bitmap follows the touch point around on the screen
Adam Cohend41fbf52012-02-16 23:53:59 -08001913 final Bitmap b = createDragBitmap(child, new Canvas(), DRAG_BITMAP_PADDING);
Joe Onorato4be866d2010-10-10 11:26:02 -07001914
1915 final int bmpWidth = b.getWidth();
Winson Chungeecf02d2012-03-02 17:14:58 -08001916 final int bmpHeight = b.getHeight();
Adam Cohene3e27a82011-04-15 12:07:39 -07001917
Adam Cohen307fe232012-08-16 17:55:58 -07001918 float scale = mLauncher.getDragLayer().getLocationInDragLayer(child, mTempXY);
Winson Chungeecf02d2012-03-02 17:14:58 -08001919 int dragLayerX =
Adam Cohen307fe232012-08-16 17:55:58 -07001920 Math.round(mTempXY[0] - (bmpWidth - scale * child.getWidth()) / 2);
Winson Chungeecf02d2012-03-02 17:14:58 -08001921 int dragLayerY =
Adam Cohen307fe232012-08-16 17:55:58 -07001922 Math.round(mTempXY[1] - (bmpHeight - scale * bmpHeight) / 2
Winson Chungeecf02d2012-03-02 17:14:58 -08001923 - DRAG_BITMAP_PADDING / 2);
Adam Cohene3e27a82011-04-15 12:07:39 -07001924
Winson Chungb8c69f32011-10-19 21:36:08 -07001925 Point dragVisualizeOffset = null;
Adam Cohene3e27a82011-04-15 12:07:39 -07001926 Rect dragRect = null;
Winson Chungb8c69f32011-10-19 21:36:08 -07001927 if (child instanceof BubbleTextView || child instanceof PagedViewIcon) {
1928 int iconSize = r.getDimensionPixelSize(R.dimen.app_icon_size);
1929 int iconPaddingTop = r.getDimensionPixelSize(R.dimen.app_icon_padding_top);
Adam Cohene3e27a82011-04-15 12:07:39 -07001930 int top = child.getPaddingTop();
1931 int left = (bmpWidth - iconSize) / 2;
1932 int right = left + iconSize;
1933 int bottom = top + iconSize;
Adam Cohenfc53cd22011-07-20 15:45:11 -07001934 dragLayerY += top;
Winson Chungb8c69f32011-10-19 21:36:08 -07001935 // Note: The drag region is used to calculate drag layer offsets, but the
1936 // dragVisualizeOffset in addition to the dragRect (the size) to position the outline.
Adam Cohend41fbf52012-02-16 23:53:59 -08001937 dragVisualizeOffset = new Point(-DRAG_BITMAP_PADDING / 2,
1938 iconPaddingTop - DRAG_BITMAP_PADDING / 2);
Adam Cohene3e27a82011-04-15 12:07:39 -07001939 dragRect = new Rect(left, top, right, bottom);
Adam Cohen0e4857c2011-06-30 17:05:14 -07001940 } else if (child instanceof FolderIcon) {
Winson Chungb8c69f32011-10-19 21:36:08 -07001941 int previewSize = r.getDimensionPixelSize(R.dimen.folder_preview_size);
Adam Cohen0e4857c2011-06-30 17:05:14 -07001942 dragRect = new Rect(0, 0, child.getWidth(), previewSize);
Adam Cohene3e27a82011-04-15 12:07:39 -07001943 }
1944
Winson Chung1e9cbfe2011-09-30 16:52:26 -07001945 // Clear the pressed state if necessary
1946 if (child instanceof BubbleTextView) {
1947 BubbleTextView icon = (BubbleTextView) child;
1948 icon.clearPressedOrFocusedBackground();
1949 }
1950
Adam Cohenac8c8762011-07-13 11:15:27 -07001951 mDragController.startDrag(b, dragLayerX, dragLayerY, source, child.getTag(),
Adam Cohen307fe232012-08-16 17:55:58 -07001952 DragController.DRAG_ACTION_MOVE, dragVisualizeOffset, dragRect, scale);
Joe Onorato4be866d2010-10-10 11:26:02 -07001953 b.recycle();
Winson Chung1afedc32012-01-23 16:14:56 -08001954
1955 // Show the scrolling indicator when you pick up an item
1956 showScrollingIndicator(false);
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001957 }
1958
Winson Chung3d503fb2011-07-13 17:25:49 -07001959 void addApplicationShortcut(ShortcutInfo info, CellLayout target, long container, int screen,
1960 int cellX, int cellY, boolean insertAtFirst, int intersectX, int intersectY) {
1961 View view = mLauncher.createShortcut(R.layout.application, target, (ShortcutInfo) info);
Michael Jurka0280c3b2010-09-17 15:00:07 -07001962
1963 final int[] cellXY = new int[2];
Winson Chung3d503fb2011-07-13 17:25:49 -07001964 target.findCellForSpanThatIntersects(cellXY, 1, 1, intersectX, intersectY);
1965 addInScreen(view, container, screen, cellXY[0], cellXY[1], 1, 1, insertAtFirst);
1966 LauncherModel.addOrMoveItemInDatabase(mLauncher, info, container, screen, cellXY[0],
1967 cellXY[1]);
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001968 }
1969
Adam Cohen4b285c52011-07-21 14:24:06 -07001970 public boolean transitionStateShouldAllowDrop() {
Adam Cohen1b36dc32012-02-13 19:27:37 -08001971 return ((!isSwitchingState() || mTransitionProgress > 0.5f) && mState != State.SMALL);
Adam Cohen4b285c52011-07-21 14:24:06 -07001972 }
1973
Patrick Dubroycd68ff52010-10-28 17:57:05 -07001974 /**
1975 * {@inheritDoc}
1976 */
Adam Cohencb3382b2011-05-24 14:07:08 -07001977 public boolean acceptDrop(DragObject d) {
Patrick Dubroycd68ff52010-10-28 17:57:05 -07001978 // If it's an external drop (e.g. from All Apps), check if it should be accepted
Adam Cohenc6cc61d2012-04-04 12:47:08 -07001979 CellLayout dropTargetLayout = mDropToLayout;
Adam Cohencb3382b2011-05-24 14:07:08 -07001980 if (d.dragSource != this) {
Patrick Dubroycd68ff52010-10-28 17:57:05 -07001981 // Don't accept the drop if we're not over a screen at time of drop
Adam Cohenc6cc61d2012-04-04 12:47:08 -07001982 if (dropTargetLayout == null) {
Patrick Dubroycd68ff52010-10-28 17:57:05 -07001983 return false;
1984 }
Adam Cohen4b285c52011-07-21 14:24:06 -07001985 if (!transitionStateShouldAllowDrop()) return false;
Patrick Dubroycd68ff52010-10-28 17:57:05 -07001986
Adam Cohena65beee2011-06-27 21:32:23 -07001987 mDragViewVisualCenter = getDragViewVisualCenter(d.x, d.y, d.xOffset, d.yOffset,
1988 d.dragView, mDragViewVisualCenter);
1989
Adam Cohen2e9f4fb2011-08-30 22:46:55 -07001990 // We want the point to be mapped to the dragTarget.
Adam Cohenc6cc61d2012-04-04 12:47:08 -07001991 if (mLauncher.isHotseatLayout(dropTargetLayout)) {
Adam Cohen307fe232012-08-16 17:55:58 -07001992 mapPointFromSelfToHotseatLayout(mLauncher.getHotseat(), mDragViewVisualCenter);
Adam Cohen2e9f4fb2011-08-30 22:46:55 -07001993 } else {
Adam Cohenc6cc61d2012-04-04 12:47:08 -07001994 mapPointFromSelfToChild(dropTargetLayout, mDragViewVisualCenter, null);
Adam Cohen2e9f4fb2011-08-30 22:46:55 -07001995 }
1996
Winson Chung557d6ed2011-07-08 15:34:52 -07001997 int spanX = 1;
1998 int spanY = 1;
Winson Chung557d6ed2011-07-08 15:34:52 -07001999 if (mDragInfo != null) {
2000 final CellLayout.CellInfo dragCellInfo = mDragInfo;
2001 spanX = dragCellInfo.spanX;
2002 spanY = dragCellInfo.spanY;
Winson Chung557d6ed2011-07-08 15:34:52 -07002003 } else {
2004 final ItemInfo dragInfo = (ItemInfo) d.dragInfo;
2005 spanX = dragInfo.spanX;
2006 spanY = dragInfo.spanY;
2007 }
Patrick Dubroycd68ff52010-10-28 17:57:05 -07002008
Adam Cohend41fbf52012-02-16 23:53:59 -08002009 int minSpanX = spanX;
2010 int minSpanY = spanY;
2011 if (d.dragInfo instanceof PendingAddWidgetInfo) {
2012 minSpanX = ((PendingAddWidgetInfo) d.dragInfo).minSpanX;
2013 minSpanY = ((PendingAddWidgetInfo) d.dragInfo).minSpanY;
2014 }
Adam Cohen482ed822012-03-02 14:15:13 -08002015
Adam Cohena65beee2011-06-27 21:32:23 -07002016 mTargetCell = findNearestArea((int) mDragViewVisualCenter[0],
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002017 (int) mDragViewVisualCenter[1], minSpanX, minSpanY, dropTargetLayout,
Adam Cohenf0777b92012-02-28 14:02:45 -08002018 mTargetCell);
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002019 float distance = dropTargetLayout.getDistanceFromCell(mDragViewVisualCenter[0],
Adam Cohen482ed822012-03-02 14:15:13 -08002020 mDragViewVisualCenter[1], mTargetCell);
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002021 if (willCreateUserFolder((ItemInfo) d.dragInfo, dropTargetLayout,
Adam Cohen482ed822012-03-02 14:15:13 -08002022 mTargetCell, distance, true)) {
Adam Cohena65beee2011-06-27 21:32:23 -07002023 return true;
2024 }
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002025 if (willAddToExistingUserFolder((ItemInfo) d.dragInfo, dropTargetLayout,
Adam Cohen482ed822012-03-02 14:15:13 -08002026 mTargetCell, distance)) {
Adam Cohena65beee2011-06-27 21:32:23 -07002027 return true;
2028 }
2029
Adam Cohen482ed822012-03-02 14:15:13 -08002030 int[] resultSpan = new int[2];
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002031 mTargetCell = dropTargetLayout.createArea((int) mDragViewVisualCenter[0],
Adam Cohen482ed822012-03-02 14:15:13 -08002032 (int) mDragViewVisualCenter[1], minSpanX, minSpanY, spanX, spanY,
2033 null, mTargetCell, resultSpan, CellLayout.MODE_ACCEPT_DROP);
2034 boolean foundCell = mTargetCell[0] >= 0 && mTargetCell[1] >= 0;
2035
Patrick Dubroycd68ff52010-10-28 17:57:05 -07002036 // Don't accept the drop if there's no room for the item
Adam Cohen482ed822012-03-02 14:15:13 -08002037 if (!foundCell) {
Winson Chung96ef4092011-11-22 12:25:14 -08002038 // Don't show the message if we are dropping on the AllApps button and the hotseat
2039 // is full
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002040 boolean isHotseat = mLauncher.isHotseatLayout(dropTargetLayout);
Winson Chung93eef082012-03-23 15:59:27 -07002041 if (mTargetCell != null && isHotseat) {
Winson Chung96ef4092011-11-22 12:25:14 -08002042 Hotseat hotseat = mLauncher.getHotseat();
Andrew Flynn0dca1ec2012-02-29 13:33:22 -08002043 if (hotseat.isAllAppsButtonRank(
Winson Chung96ef4092011-11-22 12:25:14 -08002044 hotseat.getOrderInHotseat(mTargetCell[0], mTargetCell[1]))) {
2045 return false;
2046 }
2047 }
2048
Winson Chung93eef082012-03-23 15:59:27 -07002049 mLauncher.showOutOfSpaceMessage(isHotseat);
Patrick Dubroycd68ff52010-10-28 17:57:05 -07002050 return false;
2051 }
2052 }
2053 return true;
2054 }
2055
Adam Cohen482ed822012-03-02 14:15:13 -08002056 boolean willCreateUserFolder(ItemInfo info, CellLayout target, int[] targetCell, float
2057 distance, boolean considerTimeout) {
2058 if (distance > mMaxDistanceForFolderCreation) return false;
Adam Cohena65beee2011-06-27 21:32:23 -07002059 View dropOverView = target.getChildAt(targetCell[0], targetCell[1]);
2060
Adam Cohen19f37922012-03-21 11:59:11 -07002061 if (dropOverView != null) {
2062 CellLayout.LayoutParams lp = (CellLayout.LayoutParams) dropOverView.getLayoutParams();
2063 if (lp.useTmpCoords && (lp.tmpCellX != lp.cellX || lp.tmpCellY != lp.tmpCellY)) {
2064 return false;
2065 }
2066 }
2067
Winson Chung3d503fb2011-07-13 17:25:49 -07002068 boolean hasntMoved = false;
2069 if (mDragInfo != null) {
Adam Cohen482ed822012-03-02 14:15:13 -08002070 hasntMoved = dropOverView == mDragInfo.cell;
Winson Chung3d503fb2011-07-13 17:25:49 -07002071 }
Adam Cohene0310962011-04-18 16:15:31 -07002072
Adam Cohena65beee2011-06-27 21:32:23 -07002073 if (dropOverView == null || hasntMoved || (considerTimeout && !mCreateUserFolderOnDrop)) {
2074 return false;
2075 }
Adam Cohene0310962011-04-18 16:15:31 -07002076
Adam Cohena65beee2011-06-27 21:32:23 -07002077 boolean aboveShortcut = (dropOverView.getTag() instanceof ShortcutInfo);
Adam Cohene0310962011-04-18 16:15:31 -07002078 boolean willBecomeShortcut =
Adam Cohenc0dcf592011-06-01 15:30:43 -07002079 (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
2080 info.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT);
Adam Cohene0310962011-04-18 16:15:31 -07002081
2082 return (aboveShortcut && willBecomeShortcut);
2083 }
2084
Adam Cohen482ed822012-03-02 14:15:13 -08002085 boolean willAddToExistingUserFolder(Object dragInfo, CellLayout target, int[] targetCell,
2086 float distance) {
2087 if (distance > mMaxDistanceForFolderCreation) return false;
Adam Cohena65beee2011-06-27 21:32:23 -07002088 View dropOverView = target.getChildAt(targetCell[0], targetCell[1]);
Adam Cohen19f37922012-03-21 11:59:11 -07002089
2090 if (dropOverView != null) {
2091 CellLayout.LayoutParams lp = (CellLayout.LayoutParams) dropOverView.getLayoutParams();
2092 if (lp.useTmpCoords && (lp.tmpCellX != lp.cellX || lp.tmpCellY != lp.tmpCellY)) {
2093 return false;
2094 }
2095 }
2096
Adam Cohena65beee2011-06-27 21:32:23 -07002097 if (dropOverView instanceof FolderIcon) {
2098 FolderIcon fi = (FolderIcon) dropOverView;
2099 if (fi.acceptDrop(dragInfo)) {
2100 return true;
2101 }
2102 }
2103 return false;
2104 }
2105
Winson Chung3d503fb2011-07-13 17:25:49 -07002106 boolean createUserFolderIfNecessary(View newView, long container, CellLayout target,
Adam Cohen482ed822012-03-02 14:15:13 -08002107 int[] targetCell, float distance, boolean external, DragView dragView,
2108 Runnable postAnimationRunnable) {
2109 if (distance > mMaxDistanceForFolderCreation) return false;
Adam Cohenc0dcf592011-06-01 15:30:43 -07002110 View v = target.getChildAt(targetCell[0], targetCell[1]);
Adam Cohen19f37922012-03-21 11:59:11 -07002111
Winson Chungec9a0a42011-07-20 20:42:13 -07002112 boolean hasntMoved = false;
2113 if (mDragInfo != null) {
2114 CellLayout cellParent = getParentCellLayoutForView(mDragInfo.cell);
2115 hasntMoved = (mDragInfo.cellX == targetCell[0] &&
2116 mDragInfo.cellY == targetCell[1]) && (cellParent == target);
2117 }
Adam Cohen10b17372011-04-15 14:21:25 -07002118
Adam Cohen19072da2011-05-31 14:30:45 -07002119 if (v == null || hasntMoved || !mCreateUserFolderOnDrop) return false;
2120 mCreateUserFolderOnDrop = false;
Adam Cohenc0dcf592011-06-01 15:30:43 -07002121 final int screen = (targetCell == null) ? mDragInfo.screen : indexOfChild(target);
Adam Cohen10b17372011-04-15 14:21:25 -07002122
2123 boolean aboveShortcut = (v.getTag() instanceof ShortcutInfo);
2124 boolean willBecomeShortcut = (newView.getTag() instanceof ShortcutInfo);
2125
2126 if (aboveShortcut && willBecomeShortcut) {
2127 ShortcutInfo sourceInfo = (ShortcutInfo) newView.getTag();
2128 ShortcutInfo destInfo = (ShortcutInfo) v.getTag();
2129 // if the drag started here, we need to remove it from the workspace
2130 if (!external) {
Winson Chung3d503fb2011-07-13 17:25:49 -07002131 getParentCellLayoutForView(mDragInfo.cell).removeView(mDragInfo.cell);
Adam Cohen10b17372011-04-15 14:21:25 -07002132 }
2133
Adam Cohend0445262011-07-04 23:53:22 -07002134 Rect folderLocation = new Rect();
Adam Cohenac8c8762011-07-13 11:15:27 -07002135 float scale = mLauncher.getDragLayer().getDescendantRectRelativeToSelf(v, folderLocation);
Adam Cohen10b17372011-04-15 14:21:25 -07002136 target.removeView(v);
Adam Cohend0445262011-07-04 23:53:22 -07002137
Winson Chung3d503fb2011-07-13 17:25:49 -07002138 FolderIcon fi =
2139 mLauncher.addFolder(target, container, screen, targetCell[0], targetCell[1]);
Adam Cohena9cf38f2011-05-02 15:36:58 -07002140 destInfo.cellX = -1;
2141 destInfo.cellY = -1;
2142 sourceInfo.cellX = -1;
2143 sourceInfo.cellY = -1;
Adam Cohend0445262011-07-04 23:53:22 -07002144
Adam Cohen558baaf2011-08-15 15:22:57 -07002145 // If the dragView is null, we can't animate
2146 boolean animate = dragView != null;
2147 if (animate) {
2148 fi.performCreateAnimation(destInfo, v, sourceInfo, dragView, folderLocation, scale,
2149 postAnimationRunnable);
2150 } else {
2151 fi.addItem(destInfo);
2152 fi.addItem(sourceInfo);
2153 }
Adam Cohen10b17372011-04-15 14:21:25 -07002154 return true;
2155 }
2156 return false;
2157 }
2158
Adam Cohena65beee2011-06-27 21:32:23 -07002159 boolean addToExistingFolderIfNecessary(View newView, CellLayout target, int[] targetCell,
Adam Cohen482ed822012-03-02 14:15:13 -08002160 float distance, DragObject d, boolean external) {
2161 if (distance > mMaxDistanceForFolderCreation) return false;
2162
Adam Cohena65beee2011-06-27 21:32:23 -07002163 View dropOverView = target.getChildAt(targetCell[0], targetCell[1]);
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002164 if (!mAddToExistingFolderOnDrop) return false;
2165 mAddToExistingFolderOnDrop = false;
Adam Cohen19f37922012-03-21 11:59:11 -07002166
Adam Cohenc0dcf592011-06-01 15:30:43 -07002167 if (dropOverView instanceof FolderIcon) {
2168 FolderIcon fi = (FolderIcon) dropOverView;
Adam Cohen3e8f8112011-07-02 18:03:00 -07002169 if (fi.acceptDrop(d.dragInfo)) {
2170 fi.onDrop(d);
Adam Cohenc0dcf592011-06-01 15:30:43 -07002171
2172 // if the drag started here, we need to remove it from the workspace
2173 if (!external) {
Winson Chung3d503fb2011-07-13 17:25:49 -07002174 getParentCellLayoutForView(mDragInfo.cell).removeView(mDragInfo.cell);
Adam Cohenc0dcf592011-06-01 15:30:43 -07002175 }
2176 return true;
2177 }
2178 }
2179 return false;
2180 }
2181
Adam Cohend41fbf52012-02-16 23:53:59 -08002182 public void onDrop(final DragObject d) {
Adam Cohencb3382b2011-05-24 14:07:08 -07002183 mDragViewVisualCenter = getDragViewVisualCenter(d.x, d.y, d.xOffset, d.yOffset, d.dragView,
Adam Cohene3e27a82011-04-15 12:07:39 -07002184 mDragViewVisualCenter);
2185
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002186 CellLayout dropTargetLayout = mDropToLayout;
2187
Adam Cohene3e27a82011-04-15 12:07:39 -07002188 // We want the point to be mapped to the dragTarget.
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002189 if (dropTargetLayout != null) {
2190 if (mLauncher.isHotseatLayout(dropTargetLayout)) {
Adam Cohenbb00ff22012-07-12 15:43:01 -07002191 mapPointFromSelfToHotseatLayout(mLauncher.getHotseat(), mDragViewVisualCenter);
Winson Chung3d503fb2011-07-13 17:25:49 -07002192 } else {
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002193 mapPointFromSelfToChild(dropTargetLayout, mDragViewVisualCenter, null);
Winson Chung3d503fb2011-07-13 17:25:49 -07002194 }
Adam Cohenba781612011-05-09 14:37:39 -07002195 }
Michael Jurkac6ee42e2010-09-30 12:04:50 -07002196
Adam Cohened51cc92011-08-01 20:28:08 -07002197 int snapScreen = -1;
Adam Cohend41fbf52012-02-16 23:53:59 -08002198 boolean resizeOnDrop = false;
Adam Cohencb3382b2011-05-24 14:07:08 -07002199 if (d.dragSource != this) {
Adam Cohene3e27a82011-04-15 12:07:39 -07002200 final int[] touchXY = new int[] { (int) mDragViewVisualCenter[0],
2201 (int) mDragViewVisualCenter[1] };
Adam Cohen3e8f8112011-07-02 18:03:00 -07002202 onDropExternal(touchXY, d.dragInfo, dropTargetLayout, false, d);
Patrick Dubroyce34a972010-10-19 10:34:32 -07002203 } else if (mDragInfo != null) {
Patrick Dubroyce34a972010-10-19 10:34:32 -07002204 final View cell = mDragInfo.cell;
Patrick Dubroy54fa3b92010-11-17 12:18:45 -08002205
Adam Cohend41fbf52012-02-16 23:53:59 -08002206 Runnable resizeRunnable = null;
Winson Chungea359c62011-08-03 17:06:35 -07002207 if (dropTargetLayout != null) {
Winson Chung3d503fb2011-07-13 17:25:49 -07002208 // Move internally
Winson Chung40e882b2011-07-21 19:01:11 -07002209 boolean hasMovedLayouts = (getParentCellLayoutForView(cell) != dropTargetLayout);
2210 boolean hasMovedIntoHotseat = mLauncher.isHotseatLayout(dropTargetLayout);
2211 long container = hasMovedIntoHotseat ?
Winson Chung3d503fb2011-07-13 17:25:49 -07002212 LauncherSettings.Favorites.CONTAINER_HOTSEAT :
2213 LauncherSettings.Favorites.CONTAINER_DESKTOP;
2214 int screen = (mTargetCell[0] < 0) ?
2215 mDragInfo.screen : indexOfChild(dropTargetLayout);
Adam Cohenc0dcf592011-06-01 15:30:43 -07002216 int spanX = mDragInfo != null ? mDragInfo.spanX : 1;
2217 int spanY = mDragInfo != null ? mDragInfo.spanY : 1;
2218 // First we find the cell nearest to point at which the item is
2219 // dropped, without any consideration to whether there is an item there.
Adam Cohen482ed822012-03-02 14:15:13 -08002220
Adam Cohenc0dcf592011-06-01 15:30:43 -07002221 mTargetCell = findNearestArea((int) mDragViewVisualCenter[0], (int)
2222 mDragViewVisualCenter[1], spanX, spanY, dropTargetLayout, mTargetCell);
Adam Cohen482ed822012-03-02 14:15:13 -08002223 float distance = dropTargetLayout.getDistanceFromCell(mDragViewVisualCenter[0],
2224 mDragViewVisualCenter[1], mTargetCell);
2225
Adam Cohenc0dcf592011-06-01 15:30:43 -07002226 // If the item being dropped is a shortcut and the nearest drop
Adam Cohen76078c42011-06-09 15:06:52 -07002227 // cell also contains a shortcut, then create a folder with the two shortcuts.
Winson Chung1c4cf4a2011-07-29 14:49:10 -07002228 if (!mInScrollArea && createUserFolderIfNecessary(cell, container,
Adam Cohen482ed822012-03-02 14:15:13 -08002229 dropTargetLayout, mTargetCell, distance, false, d.dragView, null)) {
Adam Cohenc0dcf592011-06-01 15:30:43 -07002230 return;
2231 }
2232
Adam Cohen482ed822012-03-02 14:15:13 -08002233 if (addToExistingFolderIfNecessary(cell, dropTargetLayout, mTargetCell,
2234 distance, d, false)) {
Adam Cohendf035382011-04-11 17:22:04 -07002235 return;
2236 }
2237
2238 // Aside from the special case where we're dropping a shortcut onto a shortcut,
2239 // we need to find the nearest cell location that is vacant
Adam Cohend41fbf52012-02-16 23:53:59 -08002240 ItemInfo item = (ItemInfo) d.dragInfo;
2241 int minSpanX = item.spanX;
2242 int minSpanY = item.spanY;
2243 if (item.minSpanX > 0 && item.minSpanY > 0) {
2244 minSpanX = item.minSpanX;
2245 minSpanY = item.minSpanY;
2246 }
Adam Cohen482ed822012-03-02 14:15:13 -08002247
Adam Cohend41fbf52012-02-16 23:53:59 -08002248 int[] resultSpan = new int[2];
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002249 mTargetCell = dropTargetLayout.createArea((int) mDragViewVisualCenter[0],
Adam Cohen482ed822012-03-02 14:15:13 -08002250 (int) mDragViewVisualCenter[1], minSpanX, minSpanY, spanX, spanY, cell,
2251 mTargetCell, resultSpan, CellLayout.MODE_ON_DROP);
2252
Adam Cohend41fbf52012-02-16 23:53:59 -08002253 boolean foundCell = mTargetCell[0] >= 0 && mTargetCell[1] >= 0;
Adam Cohen9e05a5e2012-09-10 15:53:09 -07002254
Adam Cohenaaa5c212012-10-05 18:14:31 -07002255 // if the widget resizes on drop
Adam Cohen9e05a5e2012-09-10 15:53:09 -07002256 if (foundCell && (cell instanceof AppWidgetHostView) &&
Adam Cohenaaa5c212012-10-05 18:14:31 -07002257 (resultSpan[0] != item.spanX || resultSpan[1] != item.spanY)) {
Adam Cohend41fbf52012-02-16 23:53:59 -08002258 resizeOnDrop = true;
2259 item.spanX = resultSpan[0];
2260 item.spanY = resultSpan[1];
Adam Cohen7bdfc972012-05-22 16:50:35 -07002261 AppWidgetHostView awhv = (AppWidgetHostView) cell;
2262 AppWidgetResizeFrame.updateWidgetSizeRanges(awhv, mLauncher, resultSpan[0],
2263 resultSpan[1]);
Adam Cohend41fbf52012-02-16 23:53:59 -08002264 }
Adam Cohendf035382011-04-11 17:22:04 -07002265
Michael Jurka7cfc2822011-08-02 20:19:24 -07002266 if (mCurrentPage != screen && !hasMovedIntoHotseat) {
Adam Cohened51cc92011-08-01 20:28:08 -07002267 snapScreen = screen;
Patrick Dubroy54fa3b92010-11-17 12:18:45 -08002268 snapToPage(screen);
2269 }
2270
Adam Cohend41fbf52012-02-16 23:53:59 -08002271 if (foundCell) {
2272 final ItemInfo info = (ItemInfo) cell.getTag();
Winson Chung40e882b2011-07-21 19:01:11 -07002273 if (hasMovedLayouts) {
Patrick Dubroy94383362010-10-29 15:03:24 -07002274 // Reparent the view
Winson Chung3d503fb2011-07-13 17:25:49 -07002275 getParentCellLayoutForView(cell).removeView(cell);
2276 addInScreen(cell, container, screen, mTargetCell[0], mTargetCell[1],
Adam Cohend41fbf52012-02-16 23:53:59 -08002277 info.spanX, info.spanY);
Patrick Dubroy94383362010-10-29 15:03:24 -07002278 }
2279
2280 // update the item's position after drop
Patrick Dubroy94383362010-10-29 15:03:24 -07002281 CellLayout.LayoutParams lp = (CellLayout.LayoutParams) cell.getLayoutParams();
Adam Cohen19f37922012-03-21 11:59:11 -07002282 lp.cellX = lp.tmpCellX = mTargetCell[0];
2283 lp.cellY = lp.tmpCellY = mTargetCell[1];
Adam Cohend41fbf52012-02-16 23:53:59 -08002284 lp.cellHSpan = item.spanX;
2285 lp.cellVSpan = item.spanY;
Adam Cohen19f37922012-03-21 11:59:11 -07002286 lp.isLockedToGrid = true;
Winson Chung3d503fb2011-07-13 17:25:49 -07002287 cell.setId(LauncherModel.getCellLayoutChildId(container, mDragInfo.screen,
Patrick Dubroy94383362010-10-29 15:03:24 -07002288 mTargetCell[0], mTargetCell[1], mDragInfo.spanX, mDragInfo.spanY));
2289
Winson Chung3d503fb2011-07-13 17:25:49 -07002290 if (container != LauncherSettings.Favorites.CONTAINER_HOTSEAT &&
2291 cell instanceof LauncherAppWidgetHostView) {
Adam Cohend4844c32011-02-18 19:25:06 -08002292 final CellLayout cellLayout = dropTargetLayout;
2293 // We post this call so that the widget has a chance to be placed
2294 // in its final location
2295
2296 final LauncherAppWidgetHostView hostView = (LauncherAppWidgetHostView) cell;
2297 AppWidgetProviderInfo pinfo = hostView.getAppWidgetInfo();
Adam Cohenc0a5df92012-04-02 16:53:26 -07002298 if (pinfo != null &&
2299 pinfo.resizeMode != AppWidgetProviderInfo.RESIZE_NONE) {
Adam Cohend41fbf52012-02-16 23:53:59 -08002300 final Runnable addResizeFrame = new Runnable() {
Adam Cohend4844c32011-02-18 19:25:06 -08002301 public void run() {
Adam Cohen716b51e2011-06-30 12:09:54 -07002302 DragLayer dragLayer = mLauncher.getDragLayer();
Adam Cohenc0dcf592011-06-01 15:30:43 -07002303 dragLayer.addResizeFrame(info, hostView, cellLayout);
Adam Cohend4844c32011-02-18 19:25:06 -08002304 }
Adam Cohen26976d92011-03-22 15:33:33 -07002305 };
Adam Cohend41fbf52012-02-16 23:53:59 -08002306 resizeRunnable = (new Runnable() {
Adam Cohen26976d92011-03-22 15:33:33 -07002307 public void run() {
2308 if (!isPageMoving()) {
Adam Cohend41fbf52012-02-16 23:53:59 -08002309 addResizeFrame.run();
Adam Cohen26976d92011-03-22 15:33:33 -07002310 } else {
Adam Cohend41fbf52012-02-16 23:53:59 -08002311 mDelayedResizeRunnable = addResizeFrame;
Adam Cohen26976d92011-03-22 15:33:33 -07002312 }
2313 }
Adam Cohend4844c32011-02-18 19:25:06 -08002314 });
2315 }
2316 }
2317
Winson Chung3d503fb2011-07-13 17:25:49 -07002318 LauncherModel.moveItemInDatabase(mLauncher, info, container, screen, lp.cellX,
2319 lp.cellY);
Adam Cohend41fbf52012-02-16 23:53:59 -08002320 } else {
2321 // If we can't find a drop location, we return the item to its original position
2322 CellLayout.LayoutParams lp = (CellLayout.LayoutParams) cell.getLayoutParams();
2323 mTargetCell[0] = lp.cellX;
2324 mTargetCell[1] = lp.cellY;
Adam Cohenf1dcdf62012-05-10 16:51:52 -07002325 CellLayout layout = (CellLayout) cell.getParent().getParent();
2326 layout.markCellsAsOccupiedForView(cell);
Patrick Dubroycd68ff52010-10-28 17:57:05 -07002327 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -08002328 }
Patrick Dubroyce34a972010-10-19 10:34:32 -07002329
Michael Jurka8c920dd2011-01-20 14:16:56 -08002330 final CellLayout parent = (CellLayout) cell.getParent().getParent();
Adam Cohend41fbf52012-02-16 23:53:59 -08002331 final Runnable finalResizeRunnable = resizeRunnable;
Patrick Dubroyce34a972010-10-19 10:34:32 -07002332 // Prepare it to be animated into its new position
2333 // This must be called after the view has been re-parented
Adam Cohend41fbf52012-02-16 23:53:59 -08002334 final Runnable onCompleteRunnable = new Runnable() {
Michael Jurkad74c9842011-07-10 12:44:21 -07002335 @Override
2336 public void run() {
2337 mAnimatingViewIntoPlace = false;
Michael Jurka3a0469d2012-06-21 09:38:41 -07002338 updateChildrenLayersEnabled(false);
Adam Cohend41fbf52012-02-16 23:53:59 -08002339 if (finalResizeRunnable != null) {
2340 finalResizeRunnable.run();
2341 }
Michael Jurkad74c9842011-07-10 12:44:21 -07002342 }
2343 };
2344 mAnimatingViewIntoPlace = true;
Adam Cohenfc53cd22011-07-20 15:45:11 -07002345 if (d.dragView.hasDrawn()) {
Adam Cohend41fbf52012-02-16 23:53:59 -08002346 final ItemInfo info = (ItemInfo) cell.getTag();
2347 if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET) {
2348 int animationType = resizeOnDrop ? ANIMATE_INTO_POSITION_AND_RESIZE :
2349 ANIMATE_INTO_POSITION_AND_DISAPPEAR;
2350 animateWidgetDrop(info, parent, d.dragView,
2351 onCompleteRunnable, animationType, cell, false);
2352 } else {
Adam Cohen85b467b2012-02-29 15:38:46 -08002353 int duration = snapScreen < 0 ? -1 : ADJACENT_SCREEN_DROP_DURATION;
2354 mLauncher.getDragLayer().animateViewIntoPosition(d.dragView, cell, duration,
2355 onCompleteRunnable, this);
Adam Cohend41fbf52012-02-16 23:53:59 -08002356 }
Adam Cohenfc53cd22011-07-20 15:45:11 -07002357 } else {
Winson Chung7bd1bbb2012-02-13 18:29:29 -08002358 d.deferDragViewCleanupPostAnimation = false;
Adam Cohenfc53cd22011-07-20 15:45:11 -07002359 cell.setVisibility(VISIBLE);
2360 }
Adam Cohen716b51e2011-06-30 12:09:54 -07002361 parent.onDropChild(cell);
The Android Open Source Project31dd5032009-03-03 19:32:27 -08002362 }
2363 }
2364
Adam Cohened51cc92011-08-01 20:28:08 -07002365 public void setFinalScrollForPageChange(int screen) {
2366 if (screen >= 0) {
2367 mSavedScrollX = getScrollX();
2368 CellLayout cl = (CellLayout) getChildAt(screen);
2369 mSavedTranslationX = cl.getTranslationX();
2370 mSavedRotationY = cl.getRotationY();
2371 final int newX = getChildOffset(screen) - getRelativeChildOffset(screen);
2372 setScrollX(newX);
2373 cl.setTranslationX(0f);
2374 cl.setRotationY(0f);
2375 }
2376 }
2377
2378 public void resetFinalScrollForPageChange(int screen) {
2379 if (screen >= 0) {
2380 CellLayout cl = (CellLayout) getChildAt(screen);
2381 setScrollX(mSavedScrollX);
2382 cl.setTranslationX(mSavedTranslationX);
2383 cl.setRotationY(mSavedRotationY);
2384 }
2385 }
2386
Adam Cohen76078c42011-06-09 15:06:52 -07002387 public void getViewLocationRelativeToSelf(View v, int[] location) {
Adam Cohen8dfcba42011-07-07 16:38:18 -07002388 getLocationInWindow(location);
Adam Cohene3e27a82011-04-15 12:07:39 -07002389 int x = location[0];
2390 int y = location[1];
2391
Adam Cohen8dfcba42011-07-07 16:38:18 -07002392 v.getLocationInWindow(location);
Adam Cohene3e27a82011-04-15 12:07:39 -07002393 int vX = location[0];
2394 int vY = location[1];
2395
2396 location[0] = vX - x;
2397 location[1] = vY - y;
2398 }
2399
Adam Cohencb3382b2011-05-24 14:07:08 -07002400 public void onDragEnter(DragObject d) {
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002401 mDragEnforcer.onDragEnter();
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002402 mCreateUserFolderOnDrop = false;
2403 mAddToExistingFolderOnDrop = false;
2404
2405 mDropToLayout = null;
2406 CellLayout layout = getCurrentDropLayout();
2407 setCurrentDropLayout(layout);
2408 setCurrentDragOverlappingLayout(layout);
Winson Chungb26f3d62011-06-02 10:49:29 -07002409
Winson Chungc07918d2011-07-01 15:35:26 -07002410 // Because we don't have space in the Phone UI (the CellLayouts run to the edge) we
2411 // don't need to show the outlines
Daniel Sandlercc8befa2013-06-11 14:45:48 -04002412 if (LauncherAppState.isScreenLarge()) {
Winson Chungc07918d2011-07-01 15:35:26 -07002413 showOutlines();
Michael Jurkad718d6a2010-10-14 15:35:17 -07002414 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -08002415 }
2416
Adam Cohena897f392012-04-27 18:12:05 -07002417 static Rect getCellLayoutMetrics(Launcher launcher, int orientation) {
2418 Resources res = launcher.getResources();
2419 Display display = launcher.getWindowManager().getDefaultDisplay();
2420 Point smallestSize = new Point();
2421 Point largestSize = new Point();
2422 display.getCurrentSizeRange(smallestSize, largestSize);
2423 if (orientation == CellLayout.LANDSCAPE) {
2424 if (mLandscapeCellLayoutMetrics == null) {
2425 int paddingLeft = res.getDimensionPixelSize(R.dimen.workspace_left_padding_land);
2426 int paddingRight = res.getDimensionPixelSize(R.dimen.workspace_right_padding_land);
2427 int paddingTop = res.getDimensionPixelSize(R.dimen.workspace_top_padding_land);
2428 int paddingBottom = res.getDimensionPixelSize(R.dimen.workspace_bottom_padding_land);
2429 int width = largestSize.x - paddingLeft - paddingRight;
2430 int height = smallestSize.y - paddingTop - paddingBottom;
2431 mLandscapeCellLayoutMetrics = new Rect();
2432 CellLayout.getMetrics(mLandscapeCellLayoutMetrics, res,
2433 width, height, LauncherModel.getCellCountX(), LauncherModel.getCellCountY(),
2434 orientation);
2435 }
2436 return mLandscapeCellLayoutMetrics;
2437 } else if (orientation == CellLayout.PORTRAIT) {
2438 if (mPortraitCellLayoutMetrics == null) {
2439 int paddingLeft = res.getDimensionPixelSize(R.dimen.workspace_left_padding_land);
2440 int paddingRight = res.getDimensionPixelSize(R.dimen.workspace_right_padding_land);
2441 int paddingTop = res.getDimensionPixelSize(R.dimen.workspace_top_padding_land);
2442 int paddingBottom = res.getDimensionPixelSize(R.dimen.workspace_bottom_padding_land);
2443 int width = smallestSize.x - paddingLeft - paddingRight;
2444 int height = largestSize.y - paddingTop - paddingBottom;
2445 mPortraitCellLayoutMetrics = new Rect();
2446 CellLayout.getMetrics(mPortraitCellLayoutMetrics, res,
2447 width, height, LauncherModel.getCellCountX(), LauncherModel.getCellCountY(),
2448 orientation);
2449 }
2450 return mPortraitCellLayoutMetrics;
2451 }
2452 return null;
2453 }
2454
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002455 public void onDragExit(DragObject d) {
2456 mDragEnforcer.onDragExit();
Winson Chungc07918d2011-07-01 15:35:26 -07002457
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002458 // Here we store the final page that will be dropped to, if the workspace in fact
2459 // receives the drop
2460 if (mInScrollArea) {
Winson Chungcc1cfe42012-06-18 15:09:17 -07002461 if (isPageMoving()) {
2462 // If the user drops while the page is scrolling, we should use that page as the
2463 // destination instead of the page that is being hovered over.
2464 mDropToLayout = (CellLayout) getPageAt(getNextPage());
2465 } else {
2466 mDropToLayout = mDragOverlappingLayout;
2467 }
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002468 } else {
2469 mDropToLayout = mDragTargetLayout;
2470 }
2471
2472 if (mDragMode == DRAG_MODE_CREATE_FOLDER) {
2473 mCreateUserFolderOnDrop = true;
2474 } else if (mDragMode == DRAG_MODE_ADD_TO_FOLDER) {
2475 mAddToExistingFolderOnDrop = true;
Adam Cohen482ed822012-03-02 14:15:13 -08002476 }
2477
Winson Chungc07918d2011-07-01 15:35:26 -07002478 // Reset the scroll area and previous drag target
2479 onResetScrollArea();
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002480 setCurrentDropLayout(null);
2481 setCurrentDragOverlappingLayout(null);
Winson Chungc07918d2011-07-01 15:35:26 -07002482
Adam Cohen74c28d12011-11-18 14:17:11 -08002483 mSpringLoadedDragController.cancel();
Winson Chungc07918d2011-07-01 15:35:26 -07002484
2485 if (!mIsPageMoving) {
2486 hideOutlines();
2487 }
2488 }
2489
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002490 void setCurrentDropLayout(CellLayout layout) {
2491 if (mDragTargetLayout != null) {
2492 mDragTargetLayout.revertTempState();
2493 mDragTargetLayout.onDragExit();
2494 }
2495 mDragTargetLayout = layout;
2496 if (mDragTargetLayout != null) {
2497 mDragTargetLayout.onDragEnter();
2498 }
2499 cleanupReorder(true);
2500 cleanupFolderCreation();
2501 setCurrentDropOverCell(-1, -1);
2502 }
2503
2504 void setCurrentDragOverlappingLayout(CellLayout layout) {
2505 if (mDragOverlappingLayout != null) {
2506 mDragOverlappingLayout.setIsDragOverlapping(false);
2507 }
2508 mDragOverlappingLayout = layout;
2509 if (mDragOverlappingLayout != null) {
2510 mDragOverlappingLayout.setIsDragOverlapping(true);
2511 }
2512 invalidate();
2513 }
2514
2515 void setCurrentDropOverCell(int x, int y) {
2516 if (x != mDragOverX || y != mDragOverY) {
2517 mDragOverX = x;
2518 mDragOverY = y;
2519 setDragMode(DRAG_MODE_NONE);
2520 }
2521 }
2522
2523 void setDragMode(int dragMode) {
2524 if (dragMode != mDragMode) {
2525 if (dragMode == DRAG_MODE_NONE) {
2526 cleanupAddToFolder();
2527 // We don't want to cancel the re-order alarm every time the target cell changes
2528 // as this feels to slow / unresponsive.
2529 cleanupReorder(false);
2530 cleanupFolderCreation();
2531 } else if (dragMode == DRAG_MODE_ADD_TO_FOLDER) {
2532 cleanupReorder(true);
2533 cleanupFolderCreation();
2534 } else if (dragMode == DRAG_MODE_CREATE_FOLDER) {
2535 cleanupAddToFolder();
2536 cleanupReorder(true);
2537 } else if (dragMode == DRAG_MODE_REORDER) {
2538 cleanupAddToFolder();
2539 cleanupFolderCreation();
2540 }
2541 mDragMode = dragMode;
2542 }
2543 }
2544
2545 private void cleanupFolderCreation() {
2546 if (mDragFolderRingAnimator != null) {
2547 mDragFolderRingAnimator.animateToNaturalState();
2548 }
2549 mFolderCreationAlarm.cancelAlarm();
2550 }
2551
2552 private void cleanupAddToFolder() {
2553 if (mDragOverFolderIcon != null) {
2554 mDragOverFolderIcon.onDragExit(null);
2555 mDragOverFolderIcon = null;
2556 }
2557 }
2558
2559 private void cleanupReorder(boolean cancelAlarm) {
2560 // Any pending reorders are canceled
2561 if (cancelAlarm) {
2562 mReorderAlarm.cancelAlarm();
2563 }
2564 mLastReorderX = -1;
2565 mLastReorderY = -1;
Winson Chungc07918d2011-07-01 15:35:26 -07002566 }
2567
Adam Cohencb3382b2011-05-24 14:07:08 -07002568 public DropTarget getDropTargetDelegate(DragObject d) {
Patrick Dubroy440c3602010-07-13 17:50:32 -07002569 return null;
2570 }
2571
Michael Jurka4516c112010-10-07 15:13:47 -07002572 /*
2573 *
2574 * Convert the 2D coordinate xy from the parent View's coordinate space to this CellLayout's
2575 * coordinate space. The argument xy is modified with the return result.
2576 *
2577 */
2578 void mapPointFromSelfToChild(View v, float[] xy) {
2579 mapPointFromSelfToChild(v, xy, null);
2580 }
2581
2582 /*
2583 *
2584 * Convert the 2D coordinate xy from the parent View's coordinate space to this CellLayout's
2585 * coordinate space. The argument xy is modified with the return result.
2586 *
2587 * if cachedInverseMatrix is not null, this method will just use that matrix instead of
Michael Jurkad718d6a2010-10-14 15:35:17 -07002588 * computing it itself; we use this to avoid redundant matrix inversions in
Michael Jurka4516c112010-10-07 15:13:47 -07002589 * findMatchingPageForDragOver
2590 *
2591 */
2592 void mapPointFromSelfToChild(View v, float[] xy, Matrix cachedInverseMatrix) {
2593 if (cachedInverseMatrix == null) {
2594 v.getMatrix().invert(mTempInverseMatrix);
2595 cachedInverseMatrix = mTempInverseMatrix;
2596 }
Michael Jurka8b805b12012-04-18 14:23:14 -07002597 int scrollX = getScrollX();
Winson Chung3bc21c32012-01-20 13:59:18 -08002598 if (mNextPage != INVALID_PAGE) {
2599 scrollX = mScroller.getFinalX();
2600 }
2601 xy[0] = xy[0] + scrollX - v.getLeft();
Michael Jurka8b805b12012-04-18 14:23:14 -07002602 xy[1] = xy[1] + getScrollY() - v.getTop();
Michael Jurka4516c112010-10-07 15:13:47 -07002603 cachedInverseMatrix.mapPoints(xy);
2604 }
2605
Winson Chung3d503fb2011-07-13 17:25:49 -07002606
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002607 void mapPointFromSelfToHotseatLayout(Hotseat hotseat, float[] xy) {
Adam Cohen307fe232012-08-16 17:55:58 -07002608 hotseat.getLayout().getMatrix().invert(mTempInverseMatrix);
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002609 xy[0] = xy[0] - hotseat.getLeft() - hotseat.getLayout().getLeft();
2610 xy[1] = xy[1] - hotseat.getTop() - hotseat.getLayout().getTop();
Adam Cohen307fe232012-08-16 17:55:58 -07002611 mTempInverseMatrix.mapPoints(xy);
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002612 }
2613
Winson Chung3d503fb2011-07-13 17:25:49 -07002614 /*
Michael Jurka4516c112010-10-07 15:13:47 -07002615 *
2616 * Convert the 2D coordinate xy from this CellLayout's coordinate space to
2617 * the parent View's coordinate space. The argument xy is modified with the return result.
2618 *
2619 */
2620 void mapPointFromChildToSelf(View v, float[] xy) {
2621 v.getMatrix().mapPoints(xy);
Michael Jurka8b805b12012-04-18 14:23:14 -07002622 int scrollX = getScrollX();
Winson Chung3bc21c32012-01-20 13:59:18 -08002623 if (mNextPage != INVALID_PAGE) {
2624 scrollX = mScroller.getFinalX();
2625 }
2626 xy[0] -= (scrollX - v.getLeft());
Michael Jurka8b805b12012-04-18 14:23:14 -07002627 xy[1] -= (getScrollY() - v.getTop());
Michael Jurka4516c112010-10-07 15:13:47 -07002628 }
2629
Adam Cohene3e27a82011-04-15 12:07:39 -07002630 static private float squaredDistance(float[] point1, float[] point2) {
Michael Jurka4516c112010-10-07 15:13:47 -07002631 float distanceX = point1[0] - point2[0];
2632 float distanceY = point2[1] - point2[1];
2633 return distanceX * distanceX + distanceY * distanceY;
Adam Cohene3e27a82011-04-15 12:07:39 -07002634 }
Michael Jurka0280c3b2010-09-17 15:00:07 -07002635
Michael Jurka4516c112010-10-07 15:13:47 -07002636 /*
2637 *
2638 * Returns true if the passed CellLayout cl overlaps with dragView
2639 *
2640 */
2641 boolean overlaps(CellLayout cl, DragView dragView,
2642 int dragViewX, int dragViewY, Matrix cachedInverseMatrix) {
2643 // Transform the coordinates of the item being dragged to the CellLayout's coordinates
2644 final float[] draggedItemTopLeft = mTempDragCoordinates;
Michael Jurkaf12c75c2011-01-25 22:41:40 -08002645 draggedItemTopLeft[0] = dragViewX;
2646 draggedItemTopLeft[1] = dragViewY;
Michael Jurka4516c112010-10-07 15:13:47 -07002647 final float[] draggedItemBottomRight = mTempDragBottomRightCoordinates;
Michael Jurkaf12c75c2011-01-25 22:41:40 -08002648 draggedItemBottomRight[0] = draggedItemTopLeft[0] + dragView.getDragRegionWidth();
2649 draggedItemBottomRight[1] = draggedItemTopLeft[1] + dragView.getDragRegionHeight();
Michael Jurkaa63c4522010-08-19 13:52:27 -07002650
Michael Jurka4516c112010-10-07 15:13:47 -07002651 // Transform the dragged item's top left coordinates
2652 // to the CellLayout's local coordinates
2653 mapPointFromSelfToChild(cl, draggedItemTopLeft, cachedInverseMatrix);
2654 float overlapRegionLeft = Math.max(0f, draggedItemTopLeft[0]);
2655 float overlapRegionTop = Math.max(0f, draggedItemTopLeft[1]);
2656
2657 if (overlapRegionLeft <= cl.getWidth() && overlapRegionTop >= 0) {
2658 // Transform the dragged item's bottom right coordinates
2659 // to the CellLayout's local coordinates
2660 mapPointFromSelfToChild(cl, draggedItemBottomRight, cachedInverseMatrix);
2661 float overlapRegionRight = Math.min(cl.getWidth(), draggedItemBottomRight[0]);
2662 float overlapRegionBottom = Math.min(cl.getHeight(), draggedItemBottomRight[1]);
2663
2664 if (overlapRegionRight >= 0 && overlapRegionBottom <= cl.getHeight()) {
2665 float overlap = (overlapRegionRight - overlapRegionLeft) *
2666 (overlapRegionBottom - overlapRegionTop);
2667 if (overlap > 0) {
2668 return true;
2669 }
2670 }
2671 }
2672 return false;
2673 }
2674
2675 /*
2676 *
2677 * This method returns the CellLayout that is currently being dragged to. In order to drag
2678 * to a CellLayout, either the touch point must be directly over the CellLayout, or as a second
2679 * strategy, we see if the dragView is overlapping any CellLayout and choose the closest one
2680 *
2681 * Return null if no CellLayout is currently being dragged over
2682 *
2683 */
2684 private CellLayout findMatchingPageForDragOver(
Adam Cohen00618752011-07-20 12:06:04 -07002685 DragView dragView, float originX, float originY, boolean exact) {
Michael Jurka4516c112010-10-07 15:13:47 -07002686 // We loop through all the screens (ie CellLayouts) and see which ones overlap
2687 // with the item being dragged and then choose the one that's closest to the touch point
Michael Jurkaa63c4522010-08-19 13:52:27 -07002688 final int screenCount = getChildCount();
2689 CellLayout bestMatchingScreen = null;
Michael Jurka0280c3b2010-09-17 15:00:07 -07002690 float smallestDistSoFar = Float.MAX_VALUE;
Michael Jurka4516c112010-10-07 15:13:47 -07002691
Michael Jurkaa63c4522010-08-19 13:52:27 -07002692 for (int i = 0; i < screenCount; i++) {
Winson Chung3d503fb2011-07-13 17:25:49 -07002693 CellLayout cl = (CellLayout) getChildAt(i);
Michael Jurkaa63c4522010-08-19 13:52:27 -07002694
Adam Cohen00618752011-07-20 12:06:04 -07002695 final float[] touchXy = {originX, originY};
Michael Jurka4516c112010-10-07 15:13:47 -07002696 // Transform the touch coordinates to the CellLayout's local coordinates
2697 // If the touch point is within the bounds of the cell layout, we can return immediately
Michael Jurka0280c3b2010-09-17 15:00:07 -07002698 cl.getMatrix().invert(mTempInverseMatrix);
Michael Jurka4516c112010-10-07 15:13:47 -07002699 mapPointFromSelfToChild(cl, touchXy, mTempInverseMatrix);
Michael Jurkaa63c4522010-08-19 13:52:27 -07002700
Michael Jurka4516c112010-10-07 15:13:47 -07002701 if (touchXy[0] >= 0 && touchXy[0] <= cl.getWidth() &&
2702 touchXy[1] >= 0 && touchXy[1] <= cl.getHeight()) {
2703 return cl;
2704 }
Michael Jurkaa63c4522010-08-19 13:52:27 -07002705
Winson Chung96ef4092011-11-22 12:25:14 -08002706 if (!exact) {
Michael Jurka4516c112010-10-07 15:13:47 -07002707 // Get the center of the cell layout in screen coordinates
2708 final float[] cellLayoutCenter = mTempCellLayoutCenterCoordinates;
2709 cellLayoutCenter[0] = cl.getWidth()/2;
2710 cellLayoutCenter[1] = cl.getHeight()/2;
2711 mapPointFromChildToSelf(cl, cellLayoutCenter);
Michael Jurka0280c3b2010-09-17 15:00:07 -07002712
Adam Cohen00618752011-07-20 12:06:04 -07002713 touchXy[0] = originX;
2714 touchXy[1] = originY;
Michael Jurka0280c3b2010-09-17 15:00:07 -07002715
Michael Jurka4516c112010-10-07 15:13:47 -07002716 // Calculate the distance between the center of the CellLayout
2717 // and the touch point
2718 float dist = squaredDistance(touchXy, cellLayoutCenter);
2719
2720 if (dist < smallestDistSoFar) {
Michael Jurka0280c3b2010-09-17 15:00:07 -07002721 smallestDistSoFar = dist;
Michael Jurkaa63c4522010-08-19 13:52:27 -07002722 bestMatchingScreen = cl;
Michael Jurkaa63c4522010-08-19 13:52:27 -07002723 }
Michael Jurka4516c112010-10-07 15:13:47 -07002724 }
Michael Jurkaa63c4522010-08-19 13:52:27 -07002725 }
Michael Jurkaa63c4522010-08-19 13:52:27 -07002726 return bestMatchingScreen;
2727 }
2728
Adam Cohene3e27a82011-04-15 12:07:39 -07002729 // This is used to compute the visual center of the dragView. This point is then
2730 // used to visualize drop locations and determine where to drop an item. The idea is that
2731 // the visual center represents the user's interpretation of where the item is, and hence
2732 // is the appropriate point to use when determining drop location.
2733 private float[] getDragViewVisualCenter(int x, int y, int xOffset, int yOffset,
2734 DragView dragView, float[] recycle) {
2735 float res[];
2736 if (recycle == null) {
2737 res = new float[2];
2738 } else {
2739 res = recycle;
2740 }
2741
2742 // First off, the drag view has been shifted in a way that is not represented in the
2743 // x and y values or the x/yOffsets. Here we account for that shift.
2744 x += getResources().getDimensionPixelSize(R.dimen.dragViewOffsetX);
2745 y += getResources().getDimensionPixelSize(R.dimen.dragViewOffsetY);
2746
2747 // These represent the visual top and left of drag view if a dragRect was provided.
2748 // If a dragRect was not provided, then they correspond to the actual view left and
2749 // top, as the dragRect is in that case taken to be the entire dragView.
2750 // R.dimen.dragViewOffsetY.
2751 int left = x - xOffset;
2752 int top = y - yOffset;
2753
2754 // In order to find the visual center, we shift by half the dragRect
2755 res[0] = left + dragView.getDragRegion().width() / 2;
2756 res[1] = top + dragView.getDragRegion().height() / 2;
2757
2758 return res;
2759 }
2760
Winson Chungea359c62011-08-03 17:06:35 -07002761 private boolean isDragWidget(DragObject d) {
2762 return (d.dragInfo instanceof LauncherAppWidgetInfo ||
2763 d.dragInfo instanceof PendingAddWidgetInfo);
2764 }
2765 private boolean isExternalDragWidget(DragObject d) {
2766 return d.dragSource != this && isDragWidget(d);
2767 }
2768
Adam Cohencb3382b2011-05-24 14:07:08 -07002769 public void onDragOver(DragObject d) {
Winson Chungc07918d2011-07-01 15:35:26 -07002770 // Skip drag over events while we are dragging over side pages
Adam Cohen82ac8a22012-02-14 16:27:49 -08002771 if (mInScrollArea || mIsSwitchingState || mState == State.SMALL) return;
Winson Chungc07918d2011-07-01 15:35:26 -07002772
Winson Chung4afe9b32011-07-27 17:46:20 -07002773 Rect r = new Rect();
Winson Chung3d503fb2011-07-13 17:25:49 -07002774 CellLayout layout = null;
Winson Chungc07918d2011-07-01 15:35:26 -07002775 ItemInfo item = (ItemInfo) d.dragInfo;
2776
2777 // Ensure that we have proper spans for the item that we are dropping
2778 if (item.spanX < 0 || item.spanY < 0) throw new RuntimeException("Improper spans found");
Adam Cohen00618752011-07-20 12:06:04 -07002779 mDragViewVisualCenter = getDragViewVisualCenter(d.x, d.y, d.xOffset, d.yOffset,
Winson Chung4afe9b32011-07-27 17:46:20 -07002780 d.dragView, mDragViewVisualCenter);
Adam Cohen00618752011-07-20 12:06:04 -07002781
Adam Cohen482ed822012-03-02 14:15:13 -08002782 final View child = (mDragInfo == null) ? null : mDragInfo.cell;
Winson Chungc07918d2011-07-01 15:35:26 -07002783 // Identify whether we have dragged over a side page
Michael Jurkad74c9842011-07-10 12:44:21 -07002784 if (isSmall()) {
Winson Chungea359c62011-08-03 17:06:35 -07002785 if (mLauncher.getHotseat() != null && !isExternalDragWidget(d)) {
Winson Chung4afe9b32011-07-27 17:46:20 -07002786 mLauncher.getHotseat().getHitRect(r);
2787 if (r.contains(d.x, d.y)) {
2788 layout = mLauncher.getHotseat().getLayout();
2789 }
2790 }
2791 if (layout == null) {
Winson Chung96ef4092011-11-22 12:25:14 -08002792 layout = findMatchingPageForDragOver(d.dragView, d.x, d.y, false);
Winson Chung4afe9b32011-07-27 17:46:20 -07002793 }
Winson Chungc07918d2011-07-01 15:35:26 -07002794 if (layout != mDragTargetLayout) {
Winson Chungc07918d2011-07-01 15:35:26 -07002795
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002796 setCurrentDropLayout(layout);
2797 setCurrentDragOverlappingLayout(layout);
Winson Chungc07918d2011-07-01 15:35:26 -07002798
Michael Jurkad74c9842011-07-10 12:44:21 -07002799 boolean isInSpringLoadedMode = (mState == State.SPRING_LOADED);
Winson Chungc07918d2011-07-01 15:35:26 -07002800 if (isInSpringLoadedMode) {
Winson Chung4afe9b32011-07-27 17:46:20 -07002801 if (mLauncher.isHotseatLayout(layout)) {
2802 mSpringLoadedDragController.cancel();
2803 } else {
2804 mSpringLoadedDragController.setAlarm(mDragTargetLayout);
2805 }
Winson Chungc07918d2011-07-01 15:35:26 -07002806 }
2807 }
2808 } else {
Winson Chung3d503fb2011-07-13 17:25:49 -07002809 // Test to see if we are over the hotseat otherwise just use the current page
Winson Chungea359c62011-08-03 17:06:35 -07002810 if (mLauncher.getHotseat() != null && !isDragWidget(d)) {
Winson Chung3d503fb2011-07-13 17:25:49 -07002811 mLauncher.getHotseat().getHitRect(r);
2812 if (r.contains(d.x, d.y)) {
2813 layout = mLauncher.getHotseat().getLayout();
2814 }
2815 }
2816 if (layout == null) {
2817 layout = getCurrentDropLayout();
2818 }
Winson Chungc07918d2011-07-01 15:35:26 -07002819 if (layout != mDragTargetLayout) {
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002820 setCurrentDropLayout(layout);
2821 setCurrentDragOverlappingLayout(layout);
Winson Chungc07918d2011-07-01 15:35:26 -07002822 }
2823 }
2824
2825 // Handle the drag over
2826 if (mDragTargetLayout != null) {
Winson Chungc07918d2011-07-01 15:35:26 -07002827 // We want the point to be mapped to the dragTarget.
Winson Chung3d503fb2011-07-13 17:25:49 -07002828 if (mLauncher.isHotseatLayout(mDragTargetLayout)) {
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002829 mapPointFromSelfToHotseatLayout(mLauncher.getHotseat(), mDragViewVisualCenter);
Winson Chung3d503fb2011-07-13 17:25:49 -07002830 } else {
2831 mapPointFromSelfToChild(mDragTargetLayout, mDragViewVisualCenter, null);
2832 }
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002833
Winson Chungc07918d2011-07-01 15:35:26 -07002834 ItemInfo info = (ItemInfo) d.dragInfo;
Patrick Dubroy1262e362010-10-06 15:49:50 -07002835
Winson Chungc07918d2011-07-01 15:35:26 -07002836 mTargetCell = findNearestArea((int) mDragViewVisualCenter[0],
Adam Cohend024f982012-05-23 18:26:45 -07002837 (int) mDragViewVisualCenter[1], item.spanX, item.spanY,
2838 mDragTargetLayout, mTargetCell);
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002839
2840 setCurrentDropOverCell(mTargetCell[0], mTargetCell[1]);
2841
Adam Cohen482ed822012-03-02 14:15:13 -08002842 float targetCellDistance = mDragTargetLayout.getDistanceFromCell(
2843 mDragViewVisualCenter[0], mDragViewVisualCenter[1], mTargetCell);
2844
Winson Chungc07918d2011-07-01 15:35:26 -07002845 final View dragOverView = mDragTargetLayout.getChildAt(mTargetCell[0],
2846 mTargetCell[1]);
Winson Chung785d2eb2011-04-14 16:08:02 -07002847
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002848 manageFolderFeedback(info, mDragTargetLayout, mTargetCell,
2849 targetCellDistance, dragOverView);
Adam Cohen482ed822012-03-02 14:15:13 -08002850
2851 int minSpanX = item.spanX;
2852 int minSpanY = item.spanY;
2853 if (item.minSpanX > 0 && item.minSpanY > 0) {
2854 minSpanX = item.minSpanX;
2855 minSpanY = item.minSpanY;
2856 }
2857
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002858 boolean nearestDropOccupied = mDragTargetLayout.isNearestDropLocationOccupied((int)
2859 mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1], item.spanX,
2860 item.spanY, child, mTargetCell);
2861
2862 if (!nearestDropOccupied) {
Adam Cohen19f37922012-03-21 11:59:11 -07002863 mDragTargetLayout.visualizeDropLocation(child, mDragOutline,
2864 (int) mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1],
2865 mTargetCell[0], mTargetCell[1], item.spanX, item.spanY, false,
2866 d.dragView.getDragVisualizeOffset(), d.dragView.getDragRegion());
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002867 } else if ((mDragMode == DRAG_MODE_NONE || mDragMode == DRAG_MODE_REORDER)
Adam Cohend024f982012-05-23 18:26:45 -07002868 && !mReorderAlarm.alarmPending() && (mLastReorderX != mTargetCell[0] ||
2869 mLastReorderY != mTargetCell[1])) {
2870
Adam Cohen19f37922012-03-21 11:59:11 -07002871 // Otherwise, if we aren't adding to or creating a folder and there's no pending
2872 // reorder, then we schedule a reorder
Adam Cohen482ed822012-03-02 14:15:13 -08002873 ReorderAlarmListener listener = new ReorderAlarmListener(mDragViewVisualCenter,
2874 minSpanX, minSpanY, item.spanX, item.spanY, d.dragView, child);
2875 mReorderAlarm.setOnAlarmListener(listener);
2876 mReorderAlarm.setAlarm(REORDER_TIMEOUT);
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002877 }
2878
2879 if (mDragMode == DRAG_MODE_CREATE_FOLDER || mDragMode == DRAG_MODE_ADD_TO_FOLDER ||
2880 !nearestDropOccupied) {
2881 if (mDragTargetLayout != null) {
2882 mDragTargetLayout.revertTempState();
Michael Jurkad3ef3062010-11-23 16:23:58 -08002883 }
2884 }
Adam Cohen482ed822012-03-02 14:15:13 -08002885 }
2886 }
2887
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002888 private void manageFolderFeedback(ItemInfo info, CellLayout targetLayout,
2889 int[] targetCell, float distance, View dragOverView) {
Adam Cohen482ed822012-03-02 14:15:13 -08002890 boolean userFolderPending = willCreateUserFolder(info, targetLayout, targetCell, distance,
2891 false);
2892
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002893 if (mDragMode == DRAG_MODE_NONE && userFolderPending &&
2894 !mFolderCreationAlarm.alarmPending()) {
Adam Cohen482ed822012-03-02 14:15:13 -08002895 mFolderCreationAlarm.setOnAlarmListener(new
2896 FolderCreationAlarmListener(targetLayout, targetCell[0], targetCell[1]));
2897 mFolderCreationAlarm.setAlarm(FOLDER_CREATION_TIMEOUT);
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002898 return;
Adam Cohen482ed822012-03-02 14:15:13 -08002899 }
2900
2901 boolean willAddToFolder =
2902 willAddToExistingUserFolder(info, targetLayout, targetCell, distance);
2903
2904 if (willAddToFolder && mDragMode == DRAG_MODE_NONE) {
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002905 mDragOverFolderIcon = ((FolderIcon) dragOverView);
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002906 mDragOverFolderIcon.onDragEnter(info);
Adam Cohen482ed822012-03-02 14:15:13 -08002907 if (targetLayout != null) {
2908 targetLayout.clearDragOutlines();
Winson Chungc07918d2011-07-01 15:35:26 -07002909 }
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002910 setDragMode(DRAG_MODE_ADD_TO_FOLDER);
2911 return;
Patrick Dubroy976ebec2010-08-04 20:03:37 -07002912 }
Adam Cohen482ed822012-03-02 14:15:13 -08002913
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002914 if (mDragMode == DRAG_MODE_ADD_TO_FOLDER && !willAddToFolder) {
2915 setDragMode(DRAG_MODE_NONE);
2916 }
2917 if (mDragMode == DRAG_MODE_CREATE_FOLDER && !userFolderPending) {
2918 setDragMode(DRAG_MODE_NONE);
Adam Cohen482ed822012-03-02 14:15:13 -08002919 }
2920
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002921 return;
Adam Cohenc0dcf592011-06-01 15:30:43 -07002922 }
2923
Adam Cohen19072da2011-05-31 14:30:45 -07002924 class FolderCreationAlarmListener implements OnAlarmListener {
Adam Cohen69ce2e52011-07-03 19:25:21 -07002925 CellLayout layout;
2926 int cellX;
2927 int cellY;
Adam Cohen19072da2011-05-31 14:30:45 -07002928
Adam Cohen69ce2e52011-07-03 19:25:21 -07002929 public FolderCreationAlarmListener(CellLayout layout, int cellX, int cellY) {
2930 this.layout = layout;
2931 this.cellX = cellX;
2932 this.cellY = cellY;
Adam Cohen19072da2011-05-31 14:30:45 -07002933 }
2934
2935 public void onAlarm(Alarm alarm) {
Adam Cohen19072da2011-05-31 14:30:45 -07002936 if (mDragFolderRingAnimator == null) {
2937 mDragFolderRingAnimator = new FolderRingAnimator(mLauncher, null);
2938 }
Adam Cohen69ce2e52011-07-03 19:25:21 -07002939 mDragFolderRingAnimator.setCell(cellX, cellY);
2940 mDragFolderRingAnimator.setCellLayout(layout);
Adam Cohen19072da2011-05-31 14:30:45 -07002941 mDragFolderRingAnimator.animateToAcceptState();
Adam Cohen69ce2e52011-07-03 19:25:21 -07002942 layout.showFolderAccept(mDragFolderRingAnimator);
2943 layout.clearDragOutlines();
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002944 setDragMode(DRAG_MODE_CREATE_FOLDER);
Adam Cohen482ed822012-03-02 14:15:13 -08002945 }
2946 }
2947
2948 class ReorderAlarmListener implements OnAlarmListener {
2949 float[] dragViewCenter;
2950 int minSpanX, minSpanY, spanX, spanY;
2951 DragView dragView;
2952 View child;
2953
2954 public ReorderAlarmListener(float[] dragViewCenter, int minSpanX, int minSpanY, int spanX,
2955 int spanY, DragView dragView, View child) {
2956 this.dragViewCenter = dragViewCenter;
2957 this.minSpanX = minSpanX;
2958 this.minSpanY = minSpanY;
2959 this.spanX = spanX;
2960 this.spanY = spanY;
2961 this.child = child;
2962 this.dragView = dragView;
2963 }
2964
2965 public void onAlarm(Alarm alarm) {
2966 int[] resultSpan = new int[2];
Adam Cohen19f37922012-03-21 11:59:11 -07002967 mTargetCell = findNearestArea((int) mDragViewVisualCenter[0],
2968 (int) mDragViewVisualCenter[1], spanX, spanY, mDragTargetLayout, mTargetCell);
2969 mLastReorderX = mTargetCell[0];
2970 mLastReorderY = mTargetCell[1];
2971
Adam Cohen482ed822012-03-02 14:15:13 -08002972 mTargetCell = mDragTargetLayout.createArea((int) mDragViewVisualCenter[0],
2973 (int) mDragViewVisualCenter[1], minSpanX, minSpanY, spanX, spanY,
2974 child, mTargetCell, resultSpan, CellLayout.MODE_DRAG_OVER);
2975
Adam Cohen19f37922012-03-21 11:59:11 -07002976 if (mTargetCell[0] < 0 || mTargetCell[1] < 0) {
2977 mDragTargetLayout.revertTempState();
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002978 } else {
2979 setDragMode(DRAG_MODE_REORDER);
Adam Cohen19f37922012-03-21 11:59:11 -07002980 }
Adam Cohen482ed822012-03-02 14:15:13 -08002981
Adam Cohen482ed822012-03-02 14:15:13 -08002982 boolean resize = resultSpan[0] != spanX || resultSpan[1] != spanY;
2983 mDragTargetLayout.visualizeDropLocation(child, mDragOutline,
2984 (int) mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1],
2985 mTargetCell[0], mTargetCell[1], resultSpan[0], resultSpan[1], resize,
2986 dragView.getDragVisualizeOffset(), dragView.getDragRegion());
Adam Cohen19072da2011-05-31 14:30:45 -07002987 }
2988 }
2989
Winson Chunga34abf82010-11-12 12:10:35 -08002990 @Override
2991 public void getHitRect(Rect outRect) {
2992 // We want the workspace to have the whole area of the display (it will find the correct
2993 // cell layout to drop to in the existing drag/drop logic.
Michael Jurka84f2ce72012-04-13 15:08:01 -07002994 outRect.set(0, 0, mDisplaySize.x, mDisplaySize.y);
Winson Chunga34abf82010-11-12 12:10:35 -08002995 }
2996
Patrick Dubroy2b9ff372010-09-07 17:49:27 -07002997 /**
2998 * Add the item specified by dragInfo to the given layout.
Patrick Dubroy2b9ff372010-09-07 17:49:27 -07002999 * @return true if successful
3000 */
Adam Cohen120980b2010-12-08 11:05:37 -08003001 public boolean addExternalItemToScreen(ItemInfo dragInfo, CellLayout layout) {
3002 if (layout.findCellForSpan(mTempEstimate, dragInfo.spanX, dragInfo.spanY)) {
Patrick Dubroybbaa75c2011-03-08 18:47:40 -08003003 onDropExternal(dragInfo.dropPos, (ItemInfo) dragInfo, (CellLayout) layout, false);
Patrick Dubroy2b9ff372010-09-07 17:49:27 -07003004 return true;
3005 }
Winson Chung93eef082012-03-23 15:59:27 -07003006 mLauncher.showOutOfSpaceMessage(mLauncher.isHotseatLayout(layout));
Patrick Dubroy2b9ff372010-09-07 17:49:27 -07003007 return false;
3008 }
3009
Adam Cohend5e42732011-03-28 17:33:39 -07003010 private void onDropExternal(int[] touchXY, Object dragInfo,
3011 CellLayout cellLayout, boolean insertAtFirst) {
Adam Cohene3e27a82011-04-15 12:07:39 -07003012 onDropExternal(touchXY, dragInfo, cellLayout, insertAtFirst, null);
Adam Cohend5e42732011-03-28 17:33:39 -07003013 }
3014
Adam Cohen120980b2010-12-08 11:05:37 -08003015 /**
3016 * Drop an item that didn't originate on one of the workspace screens.
3017 * It may have come from Launcher (e.g. from all apps or customize), or it may have
3018 * come from another app altogether.
3019 *
3020 * NOTE: This can also be called when we are outside of a drag event, when we want
3021 * to add an item to one of the workspace screens.
3022 */
Winson Chung557d6ed2011-07-08 15:34:52 -07003023 private void onDropExternal(final int[] touchXY, final Object dragInfo,
3024 final CellLayout cellLayout, boolean insertAtFirst, DragObject d) {
3025 final Runnable exitSpringLoadedRunnable = new Runnable() {
3026 @Override
3027 public void run() {
Adam Cohened66b2b2012-01-23 17:28:51 -08003028 mLauncher.exitSpringLoadedDragModeDelayed(true, false, null);
Winson Chung557d6ed2011-07-08 15:34:52 -07003029 }
3030 };
Adam Cohenb7e16182011-07-15 17:55:02 -07003031
3032 ItemInfo info = (ItemInfo) dragInfo;
3033 int spanX = info.spanX;
3034 int spanY = info.spanY;
3035 if (mDragInfo != null) {
3036 spanX = mDragInfo.spanX;
3037 spanY = mDragInfo.spanY;
3038 }
3039
Winson Chung3d503fb2011-07-13 17:25:49 -07003040 final long container = mLauncher.isHotseatLayout(cellLayout) ?
3041 LauncherSettings.Favorites.CONTAINER_HOTSEAT :
3042 LauncherSettings.Favorites.CONTAINER_DESKTOP;
Winson Chung557d6ed2011-07-08 15:34:52 -07003043 final int screen = indexOfChild(cellLayout);
Winson Chung3d503fb2011-07-13 17:25:49 -07003044 if (!mLauncher.isHotseatLayout(cellLayout) && screen != mCurrentPage
3045 && mState != State.SPRING_LOADED) {
Adam Cohen76078c42011-06-09 15:06:52 -07003046 snapToPage(screen);
3047 }
Adam Cohenb7e16182011-07-15 17:55:02 -07003048
3049 if (info instanceof PendingAddItemInfo) {
3050 final PendingAddItemInfo pendingInfo = (PendingAddItemInfo) dragInfo;
3051
Adam Cohen558baaf2011-08-15 15:22:57 -07003052 boolean findNearestVacantCell = true;
3053 if (pendingInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) {
3054 mTargetCell = findNearestArea((int) touchXY[0], (int) touchXY[1], spanX, spanY,
3055 cellLayout, mTargetCell);
Adam Cohen482ed822012-03-02 14:15:13 -08003056 float distance = cellLayout.getDistanceFromCell(mDragViewVisualCenter[0],
3057 mDragViewVisualCenter[1], mTargetCell);
Adam Cohenc6cc61d2012-04-04 12:47:08 -07003058 if (willCreateUserFolder((ItemInfo) d.dragInfo, cellLayout, mTargetCell,
Adam Cohen482ed822012-03-02 14:15:13 -08003059 distance, true) || willAddToExistingUserFolder((ItemInfo) d.dragInfo,
Adam Cohenc6cc61d2012-04-04 12:47:08 -07003060 cellLayout, mTargetCell, distance)) {
Adam Cohen558baaf2011-08-15 15:22:57 -07003061 findNearestVacantCell = false;
3062 }
3063 }
Adam Cohen482ed822012-03-02 14:15:13 -08003064
Adam Cohend41fbf52012-02-16 23:53:59 -08003065 final ItemInfo item = (ItemInfo) d.dragInfo;
Adam Cohenaaa5c212012-10-05 18:14:31 -07003066 boolean updateWidgetSize = false;
Adam Cohen558baaf2011-08-15 15:22:57 -07003067 if (findNearestVacantCell) {
Adam Cohen482ed822012-03-02 14:15:13 -08003068 int minSpanX = item.spanX;
3069 int minSpanY = item.spanY;
3070 if (item.minSpanX > 0 && item.minSpanY > 0) {
3071 minSpanX = item.minSpanX;
3072 minSpanY = item.minSpanY;
3073 }
Adam Cohend41fbf52012-02-16 23:53:59 -08003074 int[] resultSpan = new int[2];
Adam Cohenc6cc61d2012-04-04 12:47:08 -07003075 mTargetCell = cellLayout.createArea((int) mDragViewVisualCenter[0],
Adam Cohen482ed822012-03-02 14:15:13 -08003076 (int) mDragViewVisualCenter[1], minSpanX, minSpanY, info.spanX, info.spanY,
3077 null, mTargetCell, resultSpan, CellLayout.MODE_ON_DROP_EXTERNAL);
Adam Cohen9e05a5e2012-09-10 15:53:09 -07003078
3079 if (resultSpan[0] != item.spanX || resultSpan[1] != item.spanY) {
3080 updateWidgetSize = true;
3081 }
Adam Cohend41fbf52012-02-16 23:53:59 -08003082 item.spanX = resultSpan[0];
3083 item.spanY = resultSpan[1];
Adam Cohen558baaf2011-08-15 15:22:57 -07003084 }
3085
Adam Cohenb7e16182011-07-15 17:55:02 -07003086 Runnable onAnimationCompleteRunnable = new Runnable() {
Winson Chung557d6ed2011-07-08 15:34:52 -07003087 @Override
3088 public void run() {
3089 // When dragging and dropping from customization tray, we deal with creating
3090 // widgets/shortcuts/folders in a slightly different way
Adam Cohenb7e16182011-07-15 17:55:02 -07003091 switch (pendingInfo.itemType) {
Winson Chung557d6ed2011-07-08 15:34:52 -07003092 case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
Adam Cohend41fbf52012-02-16 23:53:59 -08003093 int span[] = new int[2];
3094 span[0] = item.spanX;
3095 span[1] = item.spanY;
Adam Cohenb7e16182011-07-15 17:55:02 -07003096 mLauncher.addAppWidgetFromDrop((PendingAddWidgetInfo) pendingInfo,
Adam Cohend41fbf52012-02-16 23:53:59 -08003097 container, screen, mTargetCell, span, null);
Winson Chung557d6ed2011-07-08 15:34:52 -07003098 break;
3099 case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
Adam Cohenb7e16182011-07-15 17:55:02 -07003100 mLauncher.processShortcutFromDrop(pendingInfo.componentName,
Winson Chung3d503fb2011-07-13 17:25:49 -07003101 container, screen, mTargetCell, null);
Winson Chung557d6ed2011-07-08 15:34:52 -07003102 break;
3103 default:
Adam Cohenb7e16182011-07-15 17:55:02 -07003104 throw new IllegalStateException("Unknown item type: " +
3105 pendingInfo.itemType);
Winson Chung557d6ed2011-07-08 15:34:52 -07003106 }
Winson Chung557d6ed2011-07-08 15:34:52 -07003107 }
Adam Cohenb7e16182011-07-15 17:55:02 -07003108 };
Adam Cohend41fbf52012-02-16 23:53:59 -08003109 View finalView = pendingInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET
3110 ? ((PendingAddWidgetInfo) pendingInfo).boundWidget : null;
Adam Cohen9e05a5e2012-09-10 15:53:09 -07003111
3112 if (finalView instanceof AppWidgetHostView && updateWidgetSize) {
3113 AppWidgetHostView awhv = (AppWidgetHostView) finalView;
3114 AppWidgetResizeFrame.updateWidgetSizeRanges(awhv, mLauncher, item.spanX,
3115 item.spanY);
3116 }
3117
Adam Cohend41fbf52012-02-16 23:53:59 -08003118 int animationStyle = ANIMATE_INTO_POSITION_AND_DISAPPEAR;
3119 if (pendingInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET &&
3120 ((PendingAddWidgetInfo) pendingInfo).info.configure != null) {
3121 animationStyle = ANIMATE_INTO_POSITION_AND_REMAIN;
3122 }
3123 animateWidgetDrop(info, cellLayout, d.dragView, onAnimationCompleteRunnable,
3124 animationStyle, finalView, true);
Patrick Dubroy6569f2c2010-07-12 14:25:18 -07003125 } else {
Michael Jurka9c6de3d2010-11-23 16:23:58 -08003126 // This is for other drag/drop cases, like dragging from All Apps
Michael Jurka9c6de3d2010-11-23 16:23:58 -08003127 View view = null;
3128
3129 switch (info.itemType) {
3130 case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
3131 case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
3132 if (info.container == NO_ID && info instanceof ApplicationInfo) {
3133 // Came from all apps -- make a copy
Michael Jurkac9d95c52011-08-29 14:03:34 -07003134 info = new ShortcutInfo((ApplicationInfo) info);
Michael Jurka9c6de3d2010-11-23 16:23:58 -08003135 }
3136 view = mLauncher.createShortcut(R.layout.application, cellLayout,
3137 (ShortcutInfo) info);
3138 break;
Adam Cohendf2cc412011-04-27 16:56:57 -07003139 case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
Adam Cohenc0dcf592011-06-01 15:30:43 -07003140 view = FolderIcon.fromXml(R.layout.folder_icon, mLauncher, cellLayout,
3141 (FolderInfo) info, mIconCache);
Michael Jurka9c6de3d2010-11-23 16:23:58 -08003142 break;
3143 default:
3144 throw new IllegalStateException("Unknown item type: " + info.itemType);
3145 }
3146
Adam Cohenc0dcf592011-06-01 15:30:43 -07003147 // First we find the cell nearest to point at which the item is
3148 // dropped, without any consideration to whether there is an item there.
3149 if (touchXY != null) {
3150 mTargetCell = findNearestArea((int) touchXY[0], (int) touchXY[1], spanX, spanY,
3151 cellLayout, mTargetCell);
Adam Cohen482ed822012-03-02 14:15:13 -08003152 float distance = cellLayout.getDistanceFromCell(mDragViewVisualCenter[0],
3153 mDragViewVisualCenter[1], mTargetCell);
Winson Chung557d6ed2011-07-08 15:34:52 -07003154 d.postAnimationRunnable = exitSpringLoadedRunnable;
Adam Cohen482ed822012-03-02 14:15:13 -08003155 if (createUserFolderIfNecessary(view, container, cellLayout, mTargetCell, distance,
3156 true, d.dragView, d.postAnimationRunnable)) {
Adam Cohenc0dcf592011-06-01 15:30:43 -07003157 return;
3158 }
Adam Cohen482ed822012-03-02 14:15:13 -08003159 if (addToExistingFolderIfNecessary(view, cellLayout, mTargetCell, distance, d,
3160 true)) {
Adam Cohenc0dcf592011-06-01 15:30:43 -07003161 return;
3162 }
Adam Cohen10b17372011-04-15 14:21:25 -07003163 }
3164
Michael Jurkac4e772e2011-02-10 13:32:01 -08003165 if (touchXY != null) {
Michael Jurka9c6de3d2010-11-23 16:23:58 -08003166 // when dragging and dropping, just find the closest free spot
Adam Cohenc6cc61d2012-04-04 12:47:08 -07003167 mTargetCell = cellLayout.createArea((int) mDragViewVisualCenter[0],
Adam Cohen482ed822012-03-02 14:15:13 -08003168 (int) mDragViewVisualCenter[1], 1, 1, 1, 1,
Adam Cohenea889a22012-03-27 16:45:39 -07003169 null, mTargetCell, null, CellLayout.MODE_ON_DROP_EXTERNAL);
Michael Jurka9c6de3d2010-11-23 16:23:58 -08003170 } else {
3171 cellLayout.findCellForSpan(mTargetCell, 1, 1);
3172 }
Winson Chung3d503fb2011-07-13 17:25:49 -07003173 addInScreen(view, container, screen, mTargetCell[0], mTargetCell[1], info.spanX,
3174 info.spanY, insertAtFirst);
Adam Cohen716b51e2011-06-30 12:09:54 -07003175 cellLayout.onDropChild(view);
Patrick Dubroy6569f2c2010-07-12 14:25:18 -07003176 CellLayout.LayoutParams lp = (CellLayout.LayoutParams) view.getLayoutParams();
Michael Jurkaa52570f2012-03-20 03:18:20 -07003177 cellLayout.getShortcutsAndWidgets().measureChild(view);
Adam Cohend5e42732011-03-28 17:33:39 -07003178
Andrew Flynn0dca1ec2012-02-29 13:33:22 -08003179
Winson Chung3d503fb2011-07-13 17:25:49 -07003180 LauncherModel.addOrMoveItemInDatabase(mLauncher, info, container, screen,
Winson Chungaafa03c2010-06-11 17:34:16 -07003181 lp.cellX, lp.cellY);
Adam Cohen3e8f8112011-07-02 18:03:00 -07003182
3183 if (d.dragView != null) {
Adam Cohen4b285c52011-07-21 14:24:06 -07003184 // We wrap the animation call in the temporary set and reset of the current
3185 // cellLayout to its final transform -- this means we animate the drag view to
3186 // the correct final location.
3187 setFinalTransitionTransform(cellLayout);
Winson Chung557d6ed2011-07-08 15:34:52 -07003188 mLauncher.getDragLayer().animateViewIntoPosition(d.dragView, view,
Adam Cohen4b285c52011-07-21 14:24:06 -07003189 exitSpringLoadedRunnable);
3190 resetTransitionTransform(cellLayout);
Adam Cohen3e8f8112011-07-02 18:03:00 -07003191 }
Joe Onorato00acb122009-08-04 16:04:30 -04003192 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003193 }
Winson Chungaafa03c2010-06-11 17:34:16 -07003194
Adam Cohend41fbf52012-02-16 23:53:59 -08003195 public Bitmap createWidgetBitmap(ItemInfo widgetInfo, View layout) {
Adam Cohened66b2b2012-01-23 17:28:51 -08003196 int[] unScaledSize = mLauncher.getWorkspace().estimateItemSize(widgetInfo.spanX,
3197 widgetInfo.spanY, widgetInfo, false);
Adam Cohend41fbf52012-02-16 23:53:59 -08003198 int visibility = layout.getVisibility();
Adam Cohened66b2b2012-01-23 17:28:51 -08003199 layout.setVisibility(VISIBLE);
3200
3201 int width = MeasureSpec.makeMeasureSpec(unScaledSize[0], MeasureSpec.EXACTLY);
3202 int height = MeasureSpec.makeMeasureSpec(unScaledSize[1], MeasureSpec.EXACTLY);
3203 Bitmap b = Bitmap.createBitmap(unScaledSize[0], unScaledSize[1],
3204 Bitmap.Config.ARGB_8888);
3205 Canvas c = new Canvas(b);
3206
3207 layout.measure(width, height);
3208 layout.layout(0, 0, unScaledSize[0], unScaledSize[1]);
Adam Cohened66b2b2012-01-23 17:28:51 -08003209 layout.draw(c);
3210 c.setBitmap(null);
Adam Cohend41fbf52012-02-16 23:53:59 -08003211 layout.setVisibility(visibility);
Adam Cohened66b2b2012-01-23 17:28:51 -08003212 return b;
3213 }
3214
Adam Cohend41fbf52012-02-16 23:53:59 -08003215 private void getFinalPositionForDropAnimation(int[] loc, float[] scaleXY,
Adam Cohen9d5b7d82012-05-09 18:00:44 -07003216 DragView dragView, CellLayout layout, ItemInfo info, int[] targetCell,
Michael Jurkaa2fe7862012-05-29 05:58:17 -07003217 boolean external, boolean scale) {
Adam Cohened66b2b2012-01-23 17:28:51 -08003218 // Now we animate the dragView, (ie. the widget or shortcut preview) into its final
3219 // location and size on the home screen.
Adam Cohend41fbf52012-02-16 23:53:59 -08003220 int spanX = info.spanX;
3221 int spanY = info.spanY;
Adam Cohened66b2b2012-01-23 17:28:51 -08003222
Adam Cohend41fbf52012-02-16 23:53:59 -08003223 Rect r = estimateItemPosition(layout, info, targetCell[0], targetCell[1], spanX, spanY);
3224 loc[0] = r.left;
3225 loc[1] = r.top;
3226
3227 setFinalTransitionTransform(layout);
3228 float cellLayoutScale =
3229 mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(layout, loc);
3230 resetTransitionTransform(layout);
Michael Jurkaa2fe7862012-05-29 05:58:17 -07003231
3232 float dragViewScaleX;
3233 float dragViewScaleY;
3234 if (scale) {
3235 dragViewScaleX = (1.0f * r.width()) / dragView.getMeasuredWidth();
3236 dragViewScaleY = (1.0f * r.height()) / dragView.getMeasuredHeight();
3237 } else {
3238 dragViewScaleX = 1f;
3239 dragViewScaleY = 1f;
3240 }
Adam Cohend41fbf52012-02-16 23:53:59 -08003241
Adam Cohened66b2b2012-01-23 17:28:51 -08003242 // The animation will scale the dragView about its center, so we need to center about
3243 // the final location.
3244 loc[0] -= (dragView.getMeasuredWidth() - cellLayoutScale * r.width()) / 2;
3245 loc[1] -= (dragView.getMeasuredHeight() - cellLayoutScale * r.height()) / 2;
3246
Adam Cohend41fbf52012-02-16 23:53:59 -08003247 scaleXY[0] = dragViewScaleX * cellLayoutScale;
3248 scaleXY[1] = dragViewScaleY * cellLayoutScale;
3249 }
3250
3251 public void animateWidgetDrop(ItemInfo info, CellLayout cellLayout, DragView dragView,
3252 final Runnable onCompleteRunnable, int animationType, final View finalView,
3253 boolean external) {
3254 Rect from = new Rect();
3255 mLauncher.getDragLayer().getViewRectRelativeToSelf(dragView, from);
3256
3257 int[] finalPos = new int[2];
3258 float scaleXY[] = new float[2];
Michael Jurkaa2fe7862012-05-29 05:58:17 -07003259 boolean scalePreview = !(info instanceof PendingAddShortcutInfo);
Adam Cohend41fbf52012-02-16 23:53:59 -08003260 getFinalPositionForDropAnimation(finalPos, scaleXY, dragView, cellLayout, info, mTargetCell,
Michael Jurkaa2fe7862012-05-29 05:58:17 -07003261 external, scalePreview);
Adam Cohened66b2b2012-01-23 17:28:51 -08003262
3263 Resources res = mLauncher.getResources();
3264 int duration = res.getInteger(R.integer.config_dropAnimMaxDuration) - 200;
3265
Adam Cohend41fbf52012-02-16 23:53:59 -08003266 // In the case where we've prebound the widget, we remove it from the DragLayer
3267 if (finalView instanceof AppWidgetHostView && external) {
Adam Cohen68f681b2012-05-28 15:01:16 -07003268 Log.d(TAG, "6557954 Animate widget drop, final view is appWidgetHostView");
Adam Cohend41fbf52012-02-16 23:53:59 -08003269 mLauncher.getDragLayer().removeView(finalView);
3270 }
3271 if ((animationType == ANIMATE_INTO_POSITION_AND_RESIZE || external) && finalView != null) {
3272 Bitmap crossFadeBitmap = createWidgetBitmap(info, finalView);
Adam Cohened66b2b2012-01-23 17:28:51 -08003273 dragView.setCrossFadeBitmap(crossFadeBitmap);
3274 dragView.crossFade((int) (duration * 0.8f));
Adam Cohend41fbf52012-02-16 23:53:59 -08003275 } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET && external) {
3276 scaleXY[0] = scaleXY[1] = Math.min(scaleXY[0], scaleXY[1]);
Adam Cohened66b2b2012-01-23 17:28:51 -08003277 }
3278
Adam Cohend41fbf52012-02-16 23:53:59 -08003279 DragLayer dragLayer = mLauncher.getDragLayer();
Winson Chung7bd1bbb2012-02-13 18:29:29 -08003280 if (animationType == CANCEL_TWO_STAGE_WIDGET_DROP_ANIMATION) {
Adam Cohend41fbf52012-02-16 23:53:59 -08003281 mLauncher.getDragLayer().animateViewIntoPosition(dragView, finalPos, 0f, 0.1f, 0.1f,
Adam Cohened66b2b2012-01-23 17:28:51 -08003282 DragLayer.ANIMATION_END_DISAPPEAR, onCompleteRunnable, duration);
3283 } else {
Adam Cohend41fbf52012-02-16 23:53:59 -08003284 int endStyle;
3285 if (animationType == ANIMATE_INTO_POSITION_AND_REMAIN) {
3286 endStyle = DragLayer.ANIMATION_END_REMAIN_VISIBLE;
3287 } else {
3288 endStyle = DragLayer.ANIMATION_END_DISAPPEAR;;
3289 }
3290
3291 Runnable onComplete = new Runnable() {
3292 @Override
3293 public void run() {
3294 if (finalView != null) {
3295 finalView.setVisibility(VISIBLE);
3296 }
3297 if (onCompleteRunnable != null) {
3298 onCompleteRunnable.run();
3299 }
3300 }
3301 };
3302 dragLayer.animateViewIntoPosition(dragView, from.left, from.top, finalPos[0],
3303 finalPos[1], 1, 1, 1, scaleXY[0], scaleXY[1], onComplete, endStyle,
3304 duration, this);
Adam Cohened66b2b2012-01-23 17:28:51 -08003305 }
3306 }
3307
Adam Cohen4b285c52011-07-21 14:24:06 -07003308 public void setFinalTransitionTransform(CellLayout layout) {
3309 if (isSwitchingState()) {
3310 int index = indexOfChild(layout);
3311 mCurrentScaleX = layout.getScaleX();
3312 mCurrentScaleY = layout.getScaleY();
3313 mCurrentTranslationX = layout.getTranslationX();
3314 mCurrentTranslationY = layout.getTranslationY();
3315 mCurrentRotationY = layout.getRotationY();
3316 layout.setScaleX(mNewScaleXs[index]);
3317 layout.setScaleY(mNewScaleYs[index]);
3318 layout.setTranslationX(mNewTranslationXs[index]);
3319 layout.setTranslationY(mNewTranslationYs[index]);
3320 layout.setRotationY(mNewRotationYs[index]);
3321 }
3322 }
3323 public void resetTransitionTransform(CellLayout layout) {
3324 if (isSwitchingState()) {
Adam Cohen4b285c52011-07-21 14:24:06 -07003325 mCurrentScaleX = layout.getScaleX();
3326 mCurrentScaleY = layout.getScaleY();
3327 mCurrentTranslationX = layout.getTranslationX();
3328 mCurrentTranslationY = layout.getTranslationY();
3329 mCurrentRotationY = layout.getRotationY();
3330 layout.setScaleX(mCurrentScaleX);
3331 layout.setScaleY(mCurrentScaleY);
3332 layout.setTranslationX(mCurrentTranslationX);
3333 layout.setTranslationY(mCurrentTranslationY);
3334 layout.setRotationY(mCurrentRotationY);
3335 }
3336 }
3337
Jeff Sharkey70864282009-04-07 21:08:40 -07003338 /**
3339 * Return the current {@link CellLayout}, correctly picking the destination
3340 * screen while a scroll is in progress.
3341 */
Patrick Dubroy5f445422011-02-18 14:35:21 -08003342 public CellLayout getCurrentDropLayout() {
Winson Chung360e63f2012-04-27 13:48:05 -07003343 return (CellLayout) getChildAt(getNextPage());
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003344 }
3345
Jeff Sharkey70864282009-04-07 21:08:40 -07003346 /**
Michael Jurka0280c3b2010-09-17 15:00:07 -07003347 * Return the current CellInfo describing our current drag; this method exists
3348 * so that Launcher can sync this object with the correct info when the activity is created/
3349 * destroyed
3350 *
3351 */
3352 public CellLayout.CellInfo getDragInfo() {
3353 return mDragInfo;
3354 }
3355
3356 /**
Jeff Sharkey70864282009-04-07 21:08:40 -07003357 * Calculate the nearest cell where the given object would be dropped.
Adam Cohene3e27a82011-04-15 12:07:39 -07003358 *
3359 * pixelX and pixelY should be in the coordinate system of layout
Jeff Sharkey70864282009-04-07 21:08:40 -07003360 */
Adam Cohendf035382011-04-11 17:22:04 -07003361 private int[] findNearestArea(int pixelX, int pixelY,
Adam Cohene3e27a82011-04-15 12:07:39 -07003362 int spanX, int spanY, CellLayout layout, int[] recycle) {
Adam Cohendf035382011-04-11 17:22:04 -07003363 return layout.findNearestArea(
Adam Cohene3e27a82011-04-15 12:07:39 -07003364 pixelX, pixelY, spanX, spanY, recycle);
Adam Cohendf035382011-04-11 17:22:04 -07003365 }
3366
Adam Cohencff6af82011-09-13 14:51:53 -07003367 void setup(DragController dragController) {
Michael Jurkac2f7f472010-12-14 15:34:42 -08003368 mSpringLoadedDragController = new SpringLoadedDragController(mLauncher);
Joe Onorato00acb122009-08-04 16:04:30 -04003369 mDragController = dragController;
Michael Jurkad74c9842011-07-10 12:44:21 -07003370
Michael Jurkad74c9842011-07-10 12:44:21 -07003371 // hardware layers on children are enabled on startup, but should be disabled until
3372 // needed
Michael Jurka3a0469d2012-06-21 09:38:41 -07003373 updateChildrenLayersEnabled(false);
Michael Jurkad74c9842011-07-10 12:44:21 -07003374 setWallpaperDimension();
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003375 }
3376
Patrick Dubroye3887cc2011-01-20 10:43:40 -08003377 /**
3378 * Called at the end of a drag which originated on the workspace.
3379 */
Winson Chunga48487a2012-03-20 16:19:37 -07003380 public void onDropCompleted(View target, DragObject d, boolean isFlingToDelete,
3381 boolean success) {
Winson Chungaafa03c2010-06-11 17:34:16 -07003382 if (success) {
Michael Jurkad74c9842011-07-10 12:44:21 -07003383 if (target != this) {
3384 if (mDragInfo != null) {
Winson Chung3d503fb2011-07-13 17:25:49 -07003385 getParentCellLayoutForView(mDragInfo.cell).removeView(mDragInfo.cell);
Michael Jurkad74c9842011-07-10 12:44:21 -07003386 if (mDragInfo.cell instanceof DropTarget) {
3387 mDragController.removeDropTarget((DropTarget) mDragInfo.cell);
3388 }
Joe Onorato00acb122009-08-04 16:04:30 -04003389 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003390 }
Patrick Dubroyce34a972010-10-19 10:34:32 -07003391 } else if (mDragInfo != null) {
Winson Chung3d503fb2011-07-13 17:25:49 -07003392 CellLayout cellLayout;
3393 if (mLauncher.isHotseatLayout(target)) {
3394 cellLayout = mLauncher.getHotseat().getLayout();
3395 } else {
3396 cellLayout = (CellLayout) getChildAt(mDragInfo.screen);
3397 }
3398 cellLayout.onDropChild(mDragInfo.cell);
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003399 }
Adam Cohen36cc09b2011-09-29 17:33:15 -07003400 if (d.cancelled && mDragInfo.cell != null) {
3401 mDragInfo.cell.setVisibility(VISIBLE);
3402 }
Joe Onorato4be866d2010-10-10 11:26:02 -07003403 mDragOutline = null;
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003404 mDragInfo = null;
Winson Chung1afedc32012-01-23 16:14:56 -08003405
3406 // Hide the scrolling indicator after you pick up an item
3407 hideScrollingIndicator(false);
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003408 }
3409
Adam Cohenea889a22012-03-27 16:45:39 -07003410 void updateItemLocationsInDatabase(CellLayout cl) {
Michael Jurkaa52570f2012-03-20 03:18:20 -07003411 int count = cl.getShortcutsAndWidgets().getChildCount();
Adam Cohend3461712012-03-29 17:25:17 -07003412
Adam Cohen482ed822012-03-02 14:15:13 -08003413 int screen = indexOfChild(cl);
Adam Cohend3461712012-03-29 17:25:17 -07003414 int container = Favorites.CONTAINER_DESKTOP;
3415
3416 if (mLauncher.isHotseatLayout(cl)) {
3417 screen = -1;
3418 container = Favorites.CONTAINER_HOTSEAT;
3419 }
3420
Adam Cohen482ed822012-03-02 14:15:13 -08003421 for (int i = 0; i < count; i++) {
Michael Jurkaa52570f2012-03-20 03:18:20 -07003422 View v = cl.getShortcutsAndWidgets().getChildAt(i);
Adam Cohen482ed822012-03-02 14:15:13 -08003423 ItemInfo info = (ItemInfo) v.getTag();
Adam Cohen2acce882012-03-28 19:03:19 -07003424 // Null check required as the AllApps button doesn't have an item info
Adam Cohen487f7dd2012-06-28 18:12:10 -07003425 if (info != null && info.requiresDbUpdate) {
3426 info.requiresDbUpdate = false;
Adam Cohenbebf0422012-04-11 18:06:28 -07003427 LauncherModel.modifyItemInDatabase(mLauncher, info, container, screen, info.cellX,
3428 info.cellY, info.spanX, info.spanY);
Adam Cohen2acce882012-03-28 19:03:19 -07003429 }
Adam Cohen482ed822012-03-02 14:15:13 -08003430 }
3431 }
3432
Adam Cohena0b57492013-06-14 15:33:35 -07003433 ArrayList<ComponentName> stripDuplicateApps() {
Adam Cohene25af792013-06-06 23:08:25 -07003434 ArrayList<ComponentName> uniqueIntents = new ArrayList<ComponentName>();
Adam Cohena0b57492013-06-14 15:33:35 -07003435 stripDuplicateApps((CellLayout) mLauncher.getHotseat().getLayout(), uniqueIntents);
Adam Cohene25af792013-06-06 23:08:25 -07003436 int count = getChildCount();
3437 for (int i = 0; i < count; i++) {
3438 CellLayout cl = (CellLayout) getChildAt(i);
Adam Cohena0b57492013-06-14 15:33:35 -07003439 stripDuplicateApps(cl, uniqueIntents);
Adam Cohene25af792013-06-06 23:08:25 -07003440 }
3441 return uniqueIntents;
3442 }
3443
Adam Cohena0b57492013-06-14 15:33:35 -07003444 void stripDuplicateApps(CellLayout cl, ArrayList<ComponentName> uniqueIntents) {
Adam Cohene25af792013-06-06 23:08:25 -07003445 int count = cl.getShortcutsAndWidgets().getChildCount();
3446
3447 ArrayList<View> children = new ArrayList<View>();
3448 for (int i = 0; i < count; i++) {
3449 View v = cl.getShortcutsAndWidgets().getChildAt(i);
3450 children.add(v);
3451 }
3452
3453 for (int i = 0; i < count; i++) {
3454 View v = children.get(i);
3455 ItemInfo info = (ItemInfo) v.getTag();
3456 // Null check required as the AllApps button doesn't have an item info
3457 if (info instanceof ShortcutInfo) {
3458 ShortcutInfo si = (ShortcutInfo) info;
3459 ComponentName cn = si.intent.getComponent();
3460
Adam Cohena0b57492013-06-14 15:33:35 -07003461 if (si.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) {
Adam Cohen99894d92013-06-14 11:22:59 -07003462 continue;
3463 }
Adam Cohena0b57492013-06-14 15:33:35 -07003464
Adam Cohene25af792013-06-06 23:08:25 -07003465 if (!uniqueIntents.contains(cn)) {
3466 uniqueIntents.add(cn);
3467 } else {
3468 cl.removeViewInLayout(v);
3469 LauncherModel.deleteItemFromDatabase(mLauncher, si);
3470 }
3471 }
3472 if (v instanceof FolderIcon) {
3473 FolderIcon fi = (FolderIcon) v;
3474 ArrayList<View> items = fi.getFolder().getItemsInReadingOrder();
3475 for (int j = 0; j < items.size(); j++) {
3476 if (items.get(j).getTag() instanceof ShortcutInfo) {
3477 ShortcutInfo si = (ShortcutInfo) items.get(j).getTag();
3478 ComponentName cn = si.intent.getComponent();
3479
Adam Cohena0b57492013-06-14 15:33:35 -07003480 if (si.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) {
Adam Cohen99894d92013-06-14 11:22:59 -07003481 continue;
3482 }
Adam Cohene25af792013-06-06 23:08:25 -07003483 if (!uniqueIntents.contains(cn)) {
3484 uniqueIntents.add(cn);
3485 } else {
3486 fi.getFolderInfo().remove(si);
3487 LauncherModel.deleteItemFromDatabase(mLauncher, si);
3488 }
3489 }
3490 }
3491 }
3492 }
3493 }
3494
3495 void saveWorkspaceToDb() {
3496 saveWorkspaceScreenToDb((CellLayout) mLauncher.getHotseat().getLayout());
3497 int count = getChildCount();
3498 for (int i = 0; i < count; i++) {
3499 CellLayout cl = (CellLayout) getChildAt(i);
3500 saveWorkspaceScreenToDb(cl);
3501 }
3502 }
3503
3504 void saveWorkspaceScreenToDb(CellLayout cl) {
3505 int count = cl.getShortcutsAndWidgets().getChildCount();
3506
3507 int screen = indexOfChild(cl);
3508 int container = Favorites.CONTAINER_DESKTOP;
3509
3510 if (mLauncher.isHotseatLayout(cl)) {
3511 screen = -1;
3512 container = Favorites.CONTAINER_HOTSEAT;
3513 }
3514
3515 for (int i = 0; i < count; i++) {
3516 View v = cl.getShortcutsAndWidgets().getChildAt(i);
3517 ItemInfo info = (ItemInfo) v.getTag();
3518 // Null check required as the AllApps button doesn't have an item info
3519 if (info != null) {
3520 LauncherModel.addItemToDatabase(mLauncher, info, container, screen, info.cellX,
3521 info.cellY, false);
3522 }
3523 if (v instanceof FolderIcon) {
3524 FolderIcon fi = (FolderIcon) v;
3525 fi.getFolder().addItemLocationsInDatabase();
3526 }
3527 }
3528 }
3529
Winson Chunga48487a2012-03-20 16:19:37 -07003530 @Override
Winson Chung043f2af2012-03-01 16:09:54 -08003531 public boolean supportsFlingToDelete() {
3532 return true;
3533 }
3534
Winson Chunga48487a2012-03-20 16:19:37 -07003535 @Override
3536 public void onFlingToDelete(DragObject d, int x, int y, PointF vec) {
3537 // Do nothing
3538 }
3539
3540 @Override
3541 public void onFlingToDeleteCompleted() {
3542 // Do nothing
3543 }
3544
Michael Jurka0280c3b2010-09-17 15:00:07 -07003545 public boolean isDropEnabled() {
3546 return true;
3547 }
3548
Michael Jurka0142d492010-08-25 17:46:15 -07003549 @Override
3550 protected void onRestoreInstanceState(Parcelable state) {
3551 super.onRestoreInstanceState(state);
3552 Launcher.setScreen(mCurrentPage);
3553 }
3554
3555 @Override
Adam Cohen1462de32012-07-24 22:34:36 -07003556 protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
3557 // We don't dispatch restoreInstanceState to our children using this code path.
3558 // Some pages will be restored immediately as their items are bound immediately, and
3559 // others we will need to wait until after their items are bound.
3560 mSavedStates = container;
3561 }
3562
3563 public void restoreInstanceStateForChild(int child) {
3564 if (mSavedStates != null) {
3565 mRestoredPages.add(child);
3566 CellLayout cl = (CellLayout) getChildAt(child);
3567 cl.restoreInstanceState(mSavedStates);
3568 }
3569 }
3570
3571 public void restoreInstanceStateForRemainingPages() {
3572 int count = getChildCount();
3573 for (int i = 0; i < count; i++) {
3574 if (!mRestoredPages.contains(i)) {
3575 restoreInstanceStateForChild(i);
3576 }
3577 }
3578 mRestoredPages.clear();
3579 }
3580
3581 @Override
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003582 public void scrollLeft() {
Michael Jurkad74c9842011-07-10 12:44:21 -07003583 if (!isSmall() && !mIsSwitchingState) {
Michael Jurka0142d492010-08-25 17:46:15 -07003584 super.scrollLeft();
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003585 }
Adam Cohen95bb8002011-07-03 23:40:28 -07003586 Folder openFolder = getOpenFolder();
3587 if (openFolder != null) {
3588 openFolder.completeDragExit();
3589 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003590 }
3591
Michael Jurka0142d492010-08-25 17:46:15 -07003592 @Override
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003593 public void scrollRight() {
Michael Jurkad74c9842011-07-10 12:44:21 -07003594 if (!isSmall() && !mIsSwitchingState) {
Michael Jurka0142d492010-08-25 17:46:15 -07003595 super.scrollRight();
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003596 }
Adam Cohen95bb8002011-07-03 23:40:28 -07003597 Folder openFolder = getOpenFolder();
3598 if (openFolder != null) {
3599 openFolder.completeDragExit();
3600 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003601 }
3602
Patrick Dubroy1262e362010-10-06 15:49:50 -07003603 @Override
Winson Chung3e0839e2011-10-03 15:15:18 -07003604 public boolean onEnterScrollArea(int x, int y, int direction) {
Winson Chung1c4cf4a2011-07-29 14:49:10 -07003605 // Ignore the scroll area if we are dragging over the hot seat
Daniel Sandlercc8befa2013-06-11 14:45:48 -04003606 boolean isPortrait = !LauncherAppState.isScreenLandscape(getContext());
Winson Chung10bfc6e2012-03-28 15:41:26 -07003607 if (mLauncher.getHotseat() != null && isPortrait) {
Winson Chung1c4cf4a2011-07-29 14:49:10 -07003608 Rect r = new Rect();
3609 mLauncher.getHotseat().getHitRect(r);
3610 if (r.contains(x, y)) {
Winson Chung3e0839e2011-10-03 15:15:18 -07003611 return false;
Winson Chung1c4cf4a2011-07-29 14:49:10 -07003612 }
3613 }
3614
Winson Chung3e0839e2011-10-03 15:15:18 -07003615 boolean result = false;
Michael Jurkad74c9842011-07-10 12:44:21 -07003616 if (!isSmall() && !mIsSwitchingState) {
Michael Jurkad718d6a2010-10-14 15:35:17 -07003617 mInScrollArea = true;
Patrick Dubroy54fa3b92010-11-17 12:18:45 -08003618
Winson Chung360e63f2012-04-27 13:48:05 -07003619 final int page = getNextPage() +
Winson Chungaa15ffe2012-01-18 15:45:28 -08003620 (direction == DragController.SCROLL_LEFT ? -1 : 1);
Adam Cohenc6cc61d2012-04-04 12:47:08 -07003621
3622 // We always want to exit the current layout to ensure parity of enter / exit
3623 setCurrentDropLayout(null);
Patrick Dubroy54fa3b92010-11-17 12:18:45 -08003624
Winson Chungaa15ffe2012-01-18 15:45:28 -08003625 if (0 <= page && page < getChildCount()) {
3626 CellLayout layout = (CellLayout) getChildAt(page);
Adam Cohenc6cc61d2012-04-04 12:47:08 -07003627 setCurrentDragOverlappingLayout(layout);
Winson Chungc07918d2011-07-01 15:35:26 -07003628
3629 // Workspace is responsible for drawing the edge glow on adjacent pages,
3630 // so we need to redraw the workspace when this may have changed.
3631 invalidate();
Winson Chung3e0839e2011-10-03 15:15:18 -07003632 result = true;
Michael Jurkad718d6a2010-10-14 15:35:17 -07003633 }
Patrick Dubroy1262e362010-10-06 15:49:50 -07003634 }
Winson Chung3e0839e2011-10-03 15:15:18 -07003635 return result;
Patrick Dubroy1262e362010-10-06 15:49:50 -07003636 }
3637
3638 @Override
Winson Chung3e0839e2011-10-03 15:15:18 -07003639 public boolean onExitScrollArea() {
3640 boolean result = false;
Michael Jurkad718d6a2010-10-14 15:35:17 -07003641 if (mInScrollArea) {
Adam Cohenc6cc61d2012-04-04 12:47:08 -07003642 invalidate();
3643 CellLayout layout = getCurrentDropLayout();
3644 setCurrentDropLayout(layout);
3645 setCurrentDragOverlappingLayout(layout);
3646
Adam Cohen8a18afc2011-12-13 15:57:01 -08003647 result = true;
Winson Chungc07918d2011-07-01 15:35:26 -07003648 mInScrollArea = false;
Patrick Dubroy1262e362010-10-06 15:49:50 -07003649 }
Winson Chung3e0839e2011-10-03 15:15:18 -07003650 return result;
Patrick Dubroy1262e362010-10-06 15:49:50 -07003651 }
3652
Winson Chungc07918d2011-07-01 15:35:26 -07003653 private void onResetScrollArea() {
Adam Cohenc6cc61d2012-04-04 12:47:08 -07003654 setCurrentDragOverlappingLayout(null);
Winson Chungc07918d2011-07-01 15:35:26 -07003655 mInScrollArea = false;
3656 }
3657
Winson Chung3d503fb2011-07-13 17:25:49 -07003658 /**
3659 * Returns a specific CellLayout
3660 */
3661 CellLayout getParentCellLayoutForView(View v) {
3662 ArrayList<CellLayout> layouts = getWorkspaceAndHotseatCellLayouts();
3663 for (CellLayout layout : layouts) {
Michael Jurkaa52570f2012-03-20 03:18:20 -07003664 if (layout.getShortcutsAndWidgets().indexOfChild(v) > -1) {
Winson Chung3d503fb2011-07-13 17:25:49 -07003665 return layout;
3666 }
3667 }
3668 return null;
3669 }
3670
3671 /**
3672 * Returns a list of all the CellLayouts in the workspace.
3673 */
3674 ArrayList<CellLayout> getWorkspaceAndHotseatCellLayouts() {
3675 ArrayList<CellLayout> layouts = new ArrayList<CellLayout>();
3676 int screenCount = getChildCount();
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003677 for (int screen = 0; screen < screenCount; screen++) {
Winson Chung3d503fb2011-07-13 17:25:49 -07003678 layouts.add(((CellLayout) getChildAt(screen)));
3679 }
3680 if (mLauncher.getHotseat() != null) {
3681 layouts.add(mLauncher.getHotseat().getLayout());
3682 }
3683 return layouts;
3684 }
3685
3686 /**
3687 * We should only use this to search for specific children. Do not use this method to modify
Michael Jurkaa52570f2012-03-20 03:18:20 -07003688 * ShortcutsAndWidgetsContainer directly. Includes ShortcutAndWidgetContainers from
3689 * the hotseat and workspace pages
Winson Chung3d503fb2011-07-13 17:25:49 -07003690 */
Michael Jurkaa52570f2012-03-20 03:18:20 -07003691 ArrayList<ShortcutAndWidgetContainer> getAllShortcutAndWidgetContainers() {
3692 ArrayList<ShortcutAndWidgetContainer> childrenLayouts =
3693 new ArrayList<ShortcutAndWidgetContainer>();
Winson Chung3d503fb2011-07-13 17:25:49 -07003694 int screenCount = getChildCount();
3695 for (int screen = 0; screen < screenCount; screen++) {
Michael Jurkaa52570f2012-03-20 03:18:20 -07003696 childrenLayouts.add(((CellLayout) getChildAt(screen)).getShortcutsAndWidgets());
Winson Chung3d503fb2011-07-13 17:25:49 -07003697 }
3698 if (mLauncher.getHotseat() != null) {
Michael Jurkaa52570f2012-03-20 03:18:20 -07003699 childrenLayouts.add(mLauncher.getHotseat().getLayout().getShortcutsAndWidgets());
Winson Chung3d503fb2011-07-13 17:25:49 -07003700 }
3701 return childrenLayouts;
3702 }
3703
3704 public Folder getFolderForTag(Object tag) {
Michael Jurkaa52570f2012-03-20 03:18:20 -07003705 ArrayList<ShortcutAndWidgetContainer> childrenLayouts =
3706 getAllShortcutAndWidgetContainers();
3707 for (ShortcutAndWidgetContainer layout: childrenLayouts) {
Winson Chung3d503fb2011-07-13 17:25:49 -07003708 int count = layout.getChildCount();
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003709 for (int i = 0; i < count; i++) {
Winson Chung3d503fb2011-07-13 17:25:49 -07003710 View child = layout.getChildAt(i);
Winson Chung3d503fb2011-07-13 17:25:49 -07003711 if (child instanceof Folder) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003712 Folder f = (Folder) child;
Winson Chungaafa03c2010-06-11 17:34:16 -07003713 if (f.getInfo() == tag && f.getInfo().opened) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003714 return f;
3715 }
3716 }
3717 }
3718 }
3719 return null;
3720 }
3721
3722 public View getViewForTag(Object tag) {
Michael Jurkaa52570f2012-03-20 03:18:20 -07003723 ArrayList<ShortcutAndWidgetContainer> childrenLayouts =
3724 getAllShortcutAndWidgetContainers();
3725 for (ShortcutAndWidgetContainer layout: childrenLayouts) {
Winson Chung3d503fb2011-07-13 17:25:49 -07003726 int count = layout.getChildCount();
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003727 for (int i = 0; i < count; i++) {
Winson Chung3d503fb2011-07-13 17:25:49 -07003728 View child = layout.getChildAt(i);
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003729 if (child.getTag() == tag) {
3730 return child;
3731 }
3732 }
3733 }
3734 return null;
3735 }
3736
Adam Cohendf035382011-04-11 17:22:04 -07003737 void clearDropTargets() {
Michael Jurkaa52570f2012-03-20 03:18:20 -07003738 ArrayList<ShortcutAndWidgetContainer> childrenLayouts =
3739 getAllShortcutAndWidgetContainers();
3740 for (ShortcutAndWidgetContainer layout: childrenLayouts) {
Adam Cohendf035382011-04-11 17:22:04 -07003741 int childCount = layout.getChildCount();
3742 for (int j = 0; j < childCount; j++) {
3743 View v = layout.getChildAt(j);
3744 if (v instanceof DropTarget) {
3745 mDragController.removeDropTarget((DropTarget) v);
3746 }
3747 }
3748 }
3749 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003750
Winson Chung83892cc2013-05-01 16:53:33 -07003751 // Removes ALL items that match a given package name, this is usually called when a package
3752 // has been removed and we want to remove all components (widgets, shortcuts, apps) that
3753 // belong to that package.
3754 void removeItemsByPackageName(final ArrayList<String> packages) {
3755 HashSet<String> packageNames = new HashSet<String>();
Winson Chungcd810732012-06-18 16:45:43 -07003756 packageNames.addAll(packages);
Joe Onorato64e6be72010-03-05 15:05:52 -05003757
Winson Chung83892cc2013-05-01 16:53:33 -07003758 // Just create a hash table of all the specific components that this will affect
3759 HashSet<ComponentName> cns = new HashSet<ComponentName>();
3760 ArrayList<CellLayout> cellLayouts = getWorkspaceAndHotseatCellLayouts();
3761 for (CellLayout layoutParent : cellLayouts) {
3762 ViewGroup layout = layoutParent.getShortcutsAndWidgets();
3763 int childCount = layout.getChildCount();
3764 for (int i = 0; i < childCount; ++i) {
3765 View view = layout.getChildAt(i);
3766 Object tag = view.getTag();
3767
3768 if (tag instanceof ShortcutInfo) {
3769 ShortcutInfo info = (ShortcutInfo) tag;
3770 ComponentName cn = info.intent.getComponent();
Winson Chungcdbbab72013-05-13 13:09:58 -07003771 if ((cn != null) && packageNames.contains(cn.getPackageName())) {
Winson Chung83892cc2013-05-01 16:53:33 -07003772 cns.add(cn);
3773 }
3774 } else if (tag instanceof FolderInfo) {
3775 FolderInfo info = (FolderInfo) tag;
3776 for (ShortcutInfo s : info.contents) {
3777 ComponentName cn = s.intent.getComponent();
Winson Chungcdbbab72013-05-13 13:09:58 -07003778 if ((cn != null) && packageNames.contains(cn.getPackageName())) {
Winson Chung83892cc2013-05-01 16:53:33 -07003779 cns.add(cn);
3780 }
3781 }
3782 } else if (tag instanceof LauncherAppWidgetInfo) {
3783 LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) tag;
3784 ComponentName cn = info.providerName;
Winson Chungcdbbab72013-05-13 13:09:58 -07003785 if ((cn != null) && packageNames.contains(cn.getPackageName())) {
Winson Chung83892cc2013-05-01 16:53:33 -07003786 cns.add(cn);
3787 }
3788 }
3789 }
3790 }
3791
3792 // Remove all the things
3793 removeItemsByComponentName(cns);
3794 }
3795
3796 // Removes items that match the application info specified, when applications are removed
3797 // as a part of an update, this is called to ensure that other widgets and application
3798 // shortcuts are not removed.
3799 void removeItemsByApplicationInfo(final ArrayList<ApplicationInfo> appInfos) {
3800 // Just create a hash table of all the specific components that this will affect
3801 HashSet<ComponentName> cns = new HashSet<ComponentName>();
3802 for (ApplicationInfo info : appInfos) {
3803 cns.add(info.componentName);
3804 }
3805
3806 // Remove all the things
3807 removeItemsByComponentName(cns);
3808 }
3809
3810 void removeItemsByComponentName(final HashSet<ComponentName> componentNames) {
Winson Chung3d503fb2011-07-13 17:25:49 -07003811 ArrayList<CellLayout> cellLayouts = getWorkspaceAndHotseatCellLayouts();
3812 for (final CellLayout layoutParent: cellLayouts) {
Michael Jurkaa52570f2012-03-20 03:18:20 -07003813 final ViewGroup layout = layoutParent.getShortcutsAndWidgets();
Romain Guy574d20e2009-06-01 15:34:04 -07003814
Romain Guy629de3e2010-01-13 12:20:59 -08003815 // Avoid ANRs by treating each screen separately
3816 post(new Runnable() {
3817 public void run() {
3818 final ArrayList<View> childrenToRemove = new ArrayList<View>();
3819 childrenToRemove.clear();
Winson Chungaafa03c2010-06-11 17:34:16 -07003820
Romain Guy629de3e2010-01-13 12:20:59 -08003821 int childCount = layout.getChildCount();
3822 for (int j = 0; j < childCount; j++) {
3823 final View view = layout.getChildAt(j);
3824 Object tag = view.getTag();
Winson Chungaafa03c2010-06-11 17:34:16 -07003825
Joe Onorato0589f0f2010-02-08 13:44:00 -08003826 if (tag instanceof ShortcutInfo) {
3827 final ShortcutInfo info = (ShortcutInfo) tag;
Romain Guy629de3e2010-01-13 12:20:59 -08003828 final Intent intent = info.intent;
3829 final ComponentName name = intent.getComponent();
Winson Chungaafa03c2010-06-11 17:34:16 -07003830
Winson Chung11a49372012-04-27 15:12:38 -07003831 if (name != null) {
Winson Chung83892cc2013-05-01 16:53:33 -07003832 if (componentNames.contains(name)) {
Winson Chung2efec4e2012-05-03 12:31:48 -07003833 LauncherModel.deleteItemFromDatabase(mLauncher, info);
3834 childrenToRemove.add(view);
Joe Onorato64e6be72010-03-05 15:05:52 -05003835 }
Romain Guy629de3e2010-01-13 12:20:59 -08003836 }
Adam Cohendf2cc412011-04-27 16:56:57 -07003837 } else if (tag instanceof FolderInfo) {
3838 final FolderInfo info = (FolderInfo) tag;
Joe Onorato0589f0f2010-02-08 13:44:00 -08003839 final ArrayList<ShortcutInfo> contents = info.contents;
Romain Guy629de3e2010-01-13 12:20:59 -08003840 final int contentsCount = contents.size();
Adam Cohendf1e4e82011-06-24 15:57:39 -07003841 final ArrayList<ShortcutInfo> appsToRemoveFromFolder =
3842 new ArrayList<ShortcutInfo>();
Winson Chungaafa03c2010-06-11 17:34:16 -07003843
Romain Guy629de3e2010-01-13 12:20:59 -08003844 for (int k = 0; k < contentsCount; k++) {
Joe Onorato0589f0f2010-02-08 13:44:00 -08003845 final ShortcutInfo appInfo = contents.get(k);
Romain Guy629de3e2010-01-13 12:20:59 -08003846 final Intent intent = appInfo.intent;
3847 final ComponentName name = intent.getComponent();
Winson Chungaafa03c2010-06-11 17:34:16 -07003848
Winson Chung11a49372012-04-27 15:12:38 -07003849 if (name != null) {
Winson Chung83892cc2013-05-01 16:53:33 -07003850 if (componentNames.contains(name)) {
Winson Chung2efec4e2012-05-03 12:31:48 -07003851 appsToRemoveFromFolder.add(appInfo);
Joe Onorato64e6be72010-03-05 15:05:52 -05003852 }
Romain Guy629de3e2010-01-13 12:20:59 -08003853 }
3854 }
Adam Cohendf1e4e82011-06-24 15:57:39 -07003855 for (ShortcutInfo item: appsToRemoveFromFolder) {
3856 info.remove(item);
3857 LauncherModel.deleteItemFromDatabase(mLauncher, item);
Romain Guy629de3e2010-01-13 12:20:59 -08003858 }
Romain Guy629de3e2010-01-13 12:20:59 -08003859 } else if (tag instanceof LauncherAppWidgetInfo) {
3860 final LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) tag;
Winson Chung11a49372012-04-27 15:12:38 -07003861 final ComponentName provider = info.providerName;
Daniel Sandlere1cc6c32010-05-07 11:49:29 -04003862 if (provider != null) {
Winson Chung83892cc2013-05-01 16:53:33 -07003863 if (componentNames.contains(provider)) {
Winson Chung2efec4e2012-05-03 12:31:48 -07003864 LauncherModel.deleteItemFromDatabase(mLauncher, info);
3865 childrenToRemove.add(view);
Joe Onorato64e6be72010-03-05 15:05:52 -05003866 }
Romain Guy629de3e2010-01-13 12:20:59 -08003867 }
Romain Guy574d20e2009-06-01 15:34:04 -07003868 }
3869 }
Winson Chungaafa03c2010-06-11 17:34:16 -07003870
Romain Guy629de3e2010-01-13 12:20:59 -08003871 childCount = childrenToRemove.size();
3872 for (int j = 0; j < childCount; j++) {
3873 View child = childrenToRemove.get(j);
Winson Chung7a25a9e2011-01-30 13:33:56 -08003874 // Note: We can not remove the view directly from CellLayoutChildren as this
3875 // does not re-mark the spaces as unoccupied.
3876 layoutParent.removeViewInLayout(child);
Romain Guy629de3e2010-01-13 12:20:59 -08003877 if (child instanceof DropTarget) {
3878 mDragController.removeDropTarget((DropTarget)child);
3879 }
Romain Guy574d20e2009-06-01 15:34:04 -07003880 }
Winson Chungaafa03c2010-06-11 17:34:16 -07003881
Romain Guy629de3e2010-01-13 12:20:59 -08003882 if (childCount > 0) {
3883 layout.requestLayout();
3884 layout.invalidate();
Romain Guy5c16f3e2010-01-12 17:24:58 -08003885 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003886 }
Romain Guy629de3e2010-01-13 12:20:59 -08003887 });
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003888 }
Winson Chung2efec4e2012-05-03 12:31:48 -07003889
Winson Chung42490a52012-06-28 12:13:51 -07003890 // Clean up new-apps animation list
Winson Chung8a435102012-08-30 17:16:53 -07003891 final Context context = getContext();
Winson Chung2efec4e2012-05-03 12:31:48 -07003892 post(new Runnable() {
3893 @Override
3894 public void run() {
Daniel Sandlercc8befa2013-06-11 14:45:48 -04003895 String spKey = LauncherAppState.getSharedPreferencesKey();
Michael Jurka82422502012-09-17 18:06:20 -07003896 SharedPreferences sp = context.getSharedPreferences(spKey,
Winson Chung2efec4e2012-05-03 12:31:48 -07003897 Context.MODE_PRIVATE);
3898 Set<String> newApps = sp.getStringSet(InstallShortcutReceiver.NEW_APPS_LIST_KEY,
3899 null);
3900
Winson Chung42490a52012-06-28 12:13:51 -07003901 // Remove all queued items that match the same package
3902 if (newApps != null) {
3903 synchronized (newApps) {
3904 Iterator<String> iter = newApps.iterator();
3905 while (iter.hasNext()) {
3906 try {
3907 Intent intent = Intent.parseUri(iter.next(), 0);
Winson Chung83892cc2013-05-01 16:53:33 -07003908 if (componentNames.contains(intent.getComponent())) {
Winson Chung42490a52012-06-28 12:13:51 -07003909 iter.remove();
3910 }
Winson Chung8a435102012-08-30 17:16:53 -07003911
3912 // It is possible that we've queued an item to be loaded, yet it has
3913 // not been added to the workspace, so remove those items as well.
Michael Jurka82422502012-09-17 18:06:20 -07003914 ArrayList<ItemInfo> shortcuts;
3915 shortcuts = LauncherModel.getWorkspaceShortcutItemInfosWithIntent(
3916 intent);
Winson Chung8a435102012-08-30 17:16:53 -07003917 for (ItemInfo info : shortcuts) {
Michael Jurka82422502012-09-17 18:06:20 -07003918 LauncherModel.deleteItemFromDatabase(context, info);
Winson Chung8a435102012-08-30 17:16:53 -07003919 }
Winson Chung42490a52012-06-28 12:13:51 -07003920 } catch (URISyntaxException e) {}
Winson Chung2efec4e2012-05-03 12:31:48 -07003921 }
3922 }
3923 }
3924 }
3925 });
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003926 }
The Android Open Source Projectf96811c2009-03-18 17:39:48 -07003927
Joe Onorato64e6be72010-03-05 15:05:52 -05003928 void updateShortcuts(ArrayList<ApplicationInfo> apps) {
Michael Jurkaa52570f2012-03-20 03:18:20 -07003929 ArrayList<ShortcutAndWidgetContainer> childrenLayouts = getAllShortcutAndWidgetContainers();
3930 for (ShortcutAndWidgetContainer layout: childrenLayouts) {
The Android Open Source Projectf96811c2009-03-18 17:39:48 -07003931 int childCount = layout.getChildCount();
3932 for (int j = 0; j < childCount; j++) {
3933 final View view = layout.getChildAt(j);
3934 Object tag = view.getTag();
Joe Onorato0589f0f2010-02-08 13:44:00 -08003935 if (tag instanceof ShortcutInfo) {
Michael Jurkae384aff2012-03-09 15:59:25 -08003936 ShortcutInfo info = (ShortcutInfo) tag;
The Android Open Source Projectf96811c2009-03-18 17:39:48 -07003937 // We need to check for ACTION_MAIN otherwise getComponent() might
3938 // return null for some shortcuts (for instance, for shortcuts to
3939 // web pages.)
3940 final Intent intent = info.intent;
3941 final ComponentName name = intent.getComponent();
3942 if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION &&
Joe Onorato64e6be72010-03-05 15:05:52 -05003943 Intent.ACTION_MAIN.equals(intent.getAction()) && name != null) {
3944 final int appCount = apps.size();
Winson Chungaafa03c2010-06-11 17:34:16 -07003945 for (int k = 0; k < appCount; k++) {
Joe Onorato64e6be72010-03-05 15:05:52 -05003946 ApplicationInfo app = apps.get(k);
3947 if (app.componentName.equals(name)) {
Michael Jurkae384aff2012-03-09 15:59:25 -08003948 BubbleTextView shortcut = (BubbleTextView) view;
3949 info.updateIcon(mIconCache);
3950 info.title = app.title.toString();
3951 shortcut.applyFromShortcutInfo(info, mIconCache);
3952 }
Joe Onorato64e6be72010-03-05 15:05:52 -05003953 }
The Android Open Source Projectf96811c2009-03-18 17:39:48 -07003954 }
3955 }
3956 }
3957 }
3958 }
3959
Joe Onorato14f122b2009-11-19 14:06:36 -08003960 void moveToDefaultScreen(boolean animate) {
Winson Chungde1af762011-07-21 16:44:07 -07003961 if (!isSmall()) {
3962 if (animate) {
3963 snapToPage(mDefaultPage);
3964 } else {
3965 setCurrentPage(mDefaultPage);
3966 }
Joe Onoratoc45b1682010-01-11 18:48:40 -05003967 }
Michael Jurka0142d492010-08-25 17:46:15 -07003968 getChildAt(mDefaultPage).requestFocus();
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003969 }
3970
Michael Jurka0142d492010-08-25 17:46:15 -07003971 @Override
3972 public void syncPages() {
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003973 }
Michael Jurka0142d492010-08-25 17:46:15 -07003974
3975 @Override
Winson Chungf314b0e2011-08-16 11:54:27 -07003976 public void syncPageItems(int page, boolean immediate) {
Michael Jurka0142d492010-08-25 17:46:15 -07003977 }
Winson Chung6a0f57d2011-06-29 20:10:49 -07003978
3979 @Override
3980 protected String getCurrentPageDescription() {
3981 int page = (mNextPage != INVALID_PAGE) ? mNextPage : mCurrentPage;
Michael Jurka8b805b12012-04-18 14:23:14 -07003982 return String.format(getContext().getString(R.string.workspace_scroll_format),
Winson Chung6a0f57d2011-06-29 20:10:49 -07003983 page + 1, getChildCount());
3984 }
Adam Cohen8dfcba42011-07-07 16:38:18 -07003985
3986 public void getLocationInDragLayer(int[] loc) {
3987 mLauncher.getDragLayer().getLocationInDragLayer(this, loc);
3988 }
Winson Chung32174c82011-07-19 15:47:55 -07003989
Adam Cohen21b41102011-11-01 17:29:52 -07003990 void setFadeForOverScroll(float fade) {
3991 if (!isScrollingIndicatorEnabled()) return;
3992
3993 mOverscrollFade = fade;
3994 float reducedFade = 0.5f + 0.5f * (1 - fade);
3995 final ViewGroup parent = (ViewGroup) getParent();
Winson Chunge96e5cb2011-11-28 13:02:56 -08003996 final ImageView qsbDivider = (ImageView) (parent.findViewById(R.id.qsb_divider));
Adam Cohen21b41102011-11-01 17:29:52 -07003997 final ImageView dockDivider = (ImageView) (parent.findViewById(R.id.dock_divider));
Michael Jurkaafaa0502011-12-13 18:22:50 -08003998 final View scrollIndicator = getScrollingIndicator();
Adam Cohen21b41102011-11-01 17:29:52 -07003999
4000 cancelScrollingIndicatorAnimations();
Winson Chunge96e5cb2011-11-28 13:02:56 -08004001 if (qsbDivider != null) qsbDivider.setAlpha(reducedFade);
4002 if (dockDivider != null) dockDivider.setAlpha(reducedFade);
Adam Cohen21b41102011-11-01 17:29:52 -07004003 scrollIndicator.setAlpha(1 - fade);
4004 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -08004005}