blob: e3fad4e0054ccf0b97a8c18f1c58ad941122032f [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;
Adam Cohenf358a4b2013-07-23 16:47:31 -070020import android.animation.AnimatorListenerAdapter;
Chet Haaseb1254a62010-09-07 13:35:00 -070021import android.animation.AnimatorSet;
Adam Cohen22cba7f2013-07-19 16:14:00 -070022import android.animation.LayoutTransition;
Michael Jurka0280c3b2010-09-17 15:00:07 -070023import android.animation.ObjectAnimator;
Patrick Dubroycd68ff52010-10-28 17:57:05 -070024import android.animation.TimeInterpolator;
25import android.animation.ValueAnimator;
26import android.animation.ValueAnimator.AnimatorUpdateListener;
Dianne Hackborn8f573952009-08-10 23:21:09 -070027import android.app.WallpaperManager;
Michael Jurkabed61d22012-02-14 22:51:29 -080028import android.appwidget.AppWidgetHostView;
Romain Guy629de3e2010-01-13 12:20:59 -080029import android.appwidget.AppWidgetProviderInfo;
Adam Powell495f2892010-04-16 16:40:55 -070030import android.content.ComponentName;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080031import android.content.Context;
32import android.content.Intent;
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;
Joe Onorato956091b2010-02-19 12:47:40 -080043import android.os.IBinder;
Adam Powell495f2892010-04-16 16:40:55 -070044import android.os.Parcelable;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080045import android.util.AttributeSet;
Daniel Sandler291ad122010-05-24 16:03:53 -040046import android.util.Log;
Adam Cohen1462de32012-07-24 22:34:36 -070047import android.util.SparseArray;
Michael Jurkacc07e7a2013-08-26 20:56:35 +020048import android.view.Choreographer;
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;
Michael Jurkacc07e7a2013-08-26 20:56:35 +020054import android.view.animation.Interpolator;
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.FolderIcon.FolderRingAnimator;
Adam Cohenbffe7452013-07-22 18:21:45 -070058import com.android.launcher3.Launcher.CustomContentCallbacks;
Daniel Sandler325dc232013-06-05 22:57:57 -040059import com.android.launcher3.LauncherSettings.Favorites;
Romain Guyedcce092010-03-04 13:03:17 -080060
Adam Cohen716b51e2011-06-30 12:09:54 -070061import java.util.ArrayList;
Adam Cohendcd297f2013-06-18 13:13:40 -070062import java.util.HashMap;
Adam Cohen716b51e2011-06-30 12:09:54 -070063import java.util.HashSet;
Michael Jurka8bd65f52012-06-25 14:56:22 -070064import java.util.Iterator;
Adam Cohen716b51e2011-06-30 12:09:54 -070065
The Android Open Source Project31dd5032009-03-03 19:32:27 -080066/**
Michael Jurka0142d492010-08-25 17:46:15 -070067 * The workspace is a wide area with a wallpaper and a finite number of pages.
68 * Each page contains a number of icons, folders or widgets the user can
Winson Chungaafa03c2010-06-11 17:34:16 -070069 * interact with. A workspace is meant to be used with a fixed width only.
The Android Open Source Project31dd5032009-03-03 19:32:27 -080070 */
Michael Jurka0142d492010-08-25 17:46:15 -070071public class Workspace extends SmoothPagedView
Michael Jurkad74c9842011-07-10 12:44:21 -070072 implements DropTarget, DragSource, DragScroller, View.OnTouchListener,
Michael Jurka8b805b12012-04-18 14:23:14 -070073 DragController.DragListener, LauncherTransitionable, ViewGroup.OnHierarchyChangeListener {
Joe Onorato3a8820b2009-11-10 15:06:42 -080074 private static final String TAG = "Launcher.Workspace";
Michael Jurka0142d492010-08-25 17:46:15 -070075
Adam Cohenf34bab52010-09-30 14:11:56 -070076 // Y rotation to apply to the workspace screens
Adam Cohenb5ba0972011-09-07 18:02:31 -070077 private static final float WORKSPACE_OVERSCROLL_ROTATION = 24f;
Adam Cohena985e592010-09-09 11:23:48 -070078
Adam Cohen68d73932010-11-15 10:50:58 -080079 private static final int CHILDREN_OUTLINE_FADE_OUT_DELAY = 0;
80 private static final int CHILDREN_OUTLINE_FADE_OUT_DURATION = 375;
Winson Chung9171e6d2010-11-17 17:39:27 -080081 private static final int CHILDREN_OUTLINE_FADE_IN_DURATION = 100;
Adam Cohenf34bab52010-09-30 14:11:56 -070082
Winson Chungf135c6c2010-11-18 16:32:08 -080083 private static final int BACKGROUND_FADE_OUT_DURATION = 350;
Adam Cohened51cc92011-08-01 20:28:08 -070084 private static final int ADJACENT_SCREEN_DROP_DURATION = 300;
Adam Cohen265b9a62011-12-07 14:37:18 -080085 private static final int FLING_THRESHOLD_VELOCITY = 500;
Adam Cohened51cc92011-08-01 20:28:08 -070086
Adam Cohenf358a4b2013-07-23 16:47:31 -070087 private static final float ALPHA_CUTOFF_THRESHOLD = 0.01f;
88
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 Cohen3d1b2b42013-08-14 15:57:58 -0700101 private static final long CUSTOM_CONTENT_GESTURE_DELAY = 200;
102 private long mTouchDownTime = -1;
103 private long mCustomContentShowTime = -1;
104
Adam Cohen22cba7f2013-07-19 16:14:00 -0700105 private LayoutTransition mLayoutTransition;
Dianne Hackborn8f573952009-08-10 23:21:09 -0700106 private final WallpaperManager mWallpaperManager;
Michael Jurka9c6fbed2011-03-02 17:41:34 -0800107 private IBinder mWindowToken;
Winson Chungaafa03c2010-06-11 17:34:16 -0700108
Winson Chung9e6a0a22013-08-27 11:58:12 -0700109 private int mOriginalDefaultPage;
Michael Jurka0142d492010-08-25 17:46:15 -0700110 private int mDefaultPage;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800111
Adam Cohendcd297f2013-06-18 13:13:40 -0700112 // The screen id used for the empty screen always present to the right.
113 private final static long EXTRA_EMPTY_SCREEN_ID = -201;
114 private final static long CUSTOM_CONTENT_SCREEN_ID = -301;
115
116 private HashMap<Long, CellLayout> mWorkspaceScreens = new HashMap<Long, CellLayout>();
117 private ArrayList<Long> mScreenOrder = new ArrayList<Long>();
118
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800119 /**
120 * CellInfo for the cell that is currently being dragged
121 */
122 private CellLayout.CellInfo mDragInfo;
Winson Chungaafa03c2010-06-11 17:34:16 -0700123
Jeff Sharkey70864282009-04-07 21:08:40 -0700124 /**
125 * Target drop area calculated during last acceptDrop call.
126 */
Adam Cohenc0dcf592011-06-01 15:30:43 -0700127 private int[] mTargetCell = new int[2];
Adam Cohenc6cc61d2012-04-04 12:47:08 -0700128 private int mDragOverX = -1;
129 private int mDragOverY = -1;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800130
Adam Cohena897f392012-04-27 18:12:05 -0700131 static Rect mLandscapeCellLayoutMetrics = null;
132 static Rect mPortraitCellLayoutMetrics = null;
133
Adam Cohenbffe7452013-07-22 18:21:45 -0700134 CustomContentCallbacks mCustomContentCallbacks;
135 boolean mCustomContentShowing;
136
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700137 /**
138 * The CellLayout that is currently being dragged over
139 */
140 private CellLayout mDragTargetLayout = null;
Adam Cohenc6cc61d2012-04-04 12:47:08 -0700141 /**
142 * The CellLayout that we will show as glowing
143 */
144 private CellLayout mDragOverlappingLayout = null;
145
146 /**
147 * The CellLayout which will be dropped to
148 */
149 private CellLayout mDropToLayout = null;
150
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800151 private Launcher mLauncher;
Joe Onorato0589f0f2010-02-08 13:44:00 -0800152 private IconCache mIconCache;
Joe Onorato00acb122009-08-04 16:04:30 -0400153 private DragController mDragController;
Winson Chungaafa03c2010-06-11 17:34:16 -0700154
Michael Jurka4516c112010-10-07 15:13:47 -0700155 // These are temporary variables to prevent having to allocate a new object just to
156 // 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 -0800157 private int[] mTempCell = new int[2];
Adam Cohen7d30a372013-07-01 17:03:59 -0700158 private int[] mTempPt = new int[2];
Jeff Sharkey70864282009-04-07 21:08:40 -0700159 private int[] mTempEstimate = new int[2];
Adam Cohene3e27a82011-04-15 12:07:39 -0700160 private float[] mDragViewVisualCenter = new float[2];
Michael Jurka4516c112010-10-07 15:13:47 -0700161 private float[] mTempCellLayoutCenterCoordinates = new float[2];
Michael Jurka0280c3b2010-09-17 15:00:07 -0700162 private Matrix mTempInverseMatrix = new Matrix();
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800163
Michael Jurkac2f7f472010-12-14 15:34:42 -0800164 private SpringLoadedDragController mSpringLoadedDragController;
Winson Chungb26f3d62011-06-02 10:49:29 -0700165 private float mSpringLoadedShrinkFactor;
Adam Cohenf358a4b2013-07-23 16:47:31 -0700166 private float mOverviewModeShrinkFactor;
Michael Jurkad3ef3062010-11-23 16:23:58 -0800167
Patrick Dubroy1262e362010-10-06 15:49:50 -0700168 // State variable that indicates whether the pages are small (ie when you're
Michael Jurkadee05892010-07-27 10:01:56 -0700169 // in all apps or customize mode)
Michael Jurkad74c9842011-07-10 12:44:21 -0700170
Adam Cohenf358a4b2013-07-23 16:47:31 -0700171 enum State { NORMAL, SPRING_LOADED, SMALL, OVERVIEW};
Adam Cohen7777d962011-08-18 18:58:38 -0700172 private State mState = State.NORMAL;
Michael Jurkad74c9842011-07-10 12:44:21 -0700173 private boolean mIsSwitchingState = false;
Michael Jurkad74c9842011-07-10 12:44:21 -0700174
Michael Jurkad74c9842011-07-10 12:44:21 -0700175 boolean mAnimatingViewIntoPlace = false;
176 boolean mIsDragOccuring = false;
177 boolean mChildrenLayersEnabled = true;
Michael Jurkadee05892010-07-27 10:01:56 -0700178
Adam Cohenaccfd562013-07-12 14:40:40 -0700179 private boolean mStripScreensOnPageStopMoving = false;
180
Patrick Dubroy54fa3b92010-11-17 12:18:45 -0800181 /** Is the user is dragging an item near the edge of a page? */
Patrick Dubroy1262e362010-10-06 15:49:50 -0700182 private boolean mInScrollArea = false;
183
Daniel Sandlere4f98912013-06-25 15:13:26 -0400184 private HolographicOutlineHelper mOutlineHelper;
Joe Onorato4be866d2010-10-10 11:26:02 -0700185 private Bitmap mDragOutline = null;
Patrick Dubroy8e58e912010-10-14 13:21:48 -0700186 private final Rect mTempRect = new Rect();
187 private final int[] mTempXY = new int[2];
Michael Jurkad51f33a2012-06-28 15:35:26 -0700188 private int[] mTempVisiblePagesRange = new int[2];
Michael Jurkab06d95f2012-04-02 06:26:53 -0700189 private boolean mOverscrollTransformsSet;
Michael Jurkaf8304f02012-04-26 13:33:26 -0700190 public static final int DRAG_BITMAP_PADDING = 2;
Michael Jurka869390b2012-05-06 15:55:19 -0700191 private boolean mWorkspaceFadeInAdjacentScreens;
Joe Onorato4be866d2010-10-10 11:26:02 -0700192
Michael Jurkaab1983f2011-01-18 15:50:17 -0800193 WallpaperOffsetInterpolator mWallpaperOffset;
Adam Cohen26976d92011-03-22 15:33:33 -0700194 private Runnable mDelayedResizeRunnable;
Winson Chungf0c6ae02012-03-21 16:10:31 -0700195 private Runnable mDelayedSnapToPageRunnable;
Michael Jurka84f2ce72012-04-13 15:08:01 -0700196 private Point mDisplaySize = new Point();
Adam Cohen94309882012-06-08 16:24:56 -0700197 private int mCameraDistance;
Michael Jurkac5b262c2011-01-12 20:24:50 -0800198
Adam Cohen19072da2011-05-31 14:30:45 -0700199 // Variables relating to the creation of user folders by hovering shortcuts over shortcuts
Adam Cohen482ed822012-03-02 14:15:13 -0800200 private static final int FOLDER_CREATION_TIMEOUT = 0;
201 private static final int REORDER_TIMEOUT = 250;
Adam Cohen19072da2011-05-31 14:30:45 -0700202 private final Alarm mFolderCreationAlarm = new Alarm();
Adam Cohen482ed822012-03-02 14:15:13 -0800203 private final Alarm mReorderAlarm = new Alarm();
Adam Cohen19072da2011-05-31 14:30:45 -0700204 private FolderRingAnimator mDragFolderRingAnimator = null;
Adam Cohenc6cc61d2012-04-04 12:47:08 -0700205 private FolderIcon mDragOverFolderIcon = null;
Adam Cohen19072da2011-05-31 14:30:45 -0700206 private boolean mCreateUserFolderOnDrop = false;
Adam Cohenc6cc61d2012-04-04 12:47:08 -0700207 private boolean mAddToExistingFolderOnDrop = false;
208 private DropTarget.DragEnforcer mDragEnforcer;
Adam Cohen3aff81c2012-05-16 21:01:01 -0700209 private float mMaxDistanceForFolderCreation;
Adam Cohen073a46f2011-05-17 16:28:09 -0700210
Adam Cohenf8d28232011-02-01 21:47:00 -0800211 // Variables relating to touch disambiguation (scrolling workspace vs. scrolling a widget)
212 private float mXDown;
213 private float mYDown;
214 final static float START_DAMPING_TOUCH_SLOP_ANGLE = (float) Math.PI / 6;
215 final static float MAX_SWIPE_ANGLE = (float) Math.PI / 3;
216 final static float TOUCH_SLOP_DAMPING_FACTOR = 4;
217
Adam Cohened66b2b2012-01-23 17:28:51 -0800218 // Relating to the animation of items being dropped externally
Adam Cohend41fbf52012-02-16 23:53:59 -0800219 public static final int ANIMATE_INTO_POSITION_AND_DISAPPEAR = 0;
220 public static final int ANIMATE_INTO_POSITION_AND_REMAIN = 1;
221 public static final int ANIMATE_INTO_POSITION_AND_RESIZE = 2;
222 public static final int COMPLETE_TWO_STAGE_WIDGET_DROP_ANIMATION = 3;
223 public static final int CANCEL_TWO_STAGE_WIDGET_DROP_ANIMATION = 4;
Adam Cohened66b2b2012-01-23 17:28:51 -0800224
Adam Cohen482ed822012-03-02 14:15:13 -0800225 // Related to dragging, folder creation and reordering
226 private static final int DRAG_MODE_NONE = 0;
227 private static final int DRAG_MODE_CREATE_FOLDER = 1;
228 private static final int DRAG_MODE_ADD_TO_FOLDER = 2;
229 private static final int DRAG_MODE_REORDER = 3;
230 private int mDragMode = DRAG_MODE_NONE;
231 private int mLastReorderX = -1;
232 private int mLastReorderY = -1;
233
Adam Cohen1462de32012-07-24 22:34:36 -0700234 private SparseArray<Parcelable> mSavedStates;
235 private final ArrayList<Integer> mRestoredPages = new ArrayList<Integer>();
236
Adam Cohen4b285c52011-07-21 14:24:06 -0700237 // These variables are used for storing the initial and final values during workspace animations
Adam Cohened51cc92011-08-01 20:28:08 -0700238 private int mSavedScrollX;
239 private float mSavedRotationY;
240 private float mSavedTranslationX;
Adam Cohen7d30a372013-07-01 17:03:59 -0700241
242 private float mCurrentScale;
243 private float mNewScale;
Adam Cohen4b285c52011-07-21 14:24:06 -0700244 private float[] mOldBackgroundAlphas;
Adam Cohen4b285c52011-07-21 14:24:06 -0700245 private float[] mOldAlphas;
Adam Cohen4b285c52011-07-21 14:24:06 -0700246 private float[] mNewBackgroundAlphas;
Adam Cohen4b285c52011-07-21 14:24:06 -0700247 private float[] mNewAlphas;
Adam Cohendcd297f2013-06-18 13:13:40 -0700248 private int mLastChildCount = -1;
Winson Chung70442722012-02-10 15:43:22 -0800249 private float mTransitionProgress;
Adam Cohen4b285c52011-07-21 14:24:06 -0700250
Michael Jurka1e2f4652013-07-08 18:03:46 -0700251 private Runnable mDeferredAction;
252 private boolean mDeferDropAfterUninstall;
253 private boolean mUninstallSuccessful;
254
Romain Guyeeacd562012-10-10 18:47:33 -0700255 private final Runnable mBindPages = new Runnable() {
256 @Override
257 public void run() {
258 mLauncher.getModel().bindRemainingSynchronousPages();
259 }
260 };
261
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800262 /**
263 * Used to inflate the Workspace from XML.
264 *
265 * @param context The application's context.
Michael Jurka0142d492010-08-25 17:46:15 -0700266 * @param attrs The attributes set containing the Workspace's customization values.
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800267 */
268 public Workspace(Context context, AttributeSet attrs) {
269 this(context, attrs, 0);
270 }
271
272 /**
273 * Used to inflate the Workspace from XML.
274 *
275 * @param context The application's context.
Michael Jurka0142d492010-08-25 17:46:15 -0700276 * @param attrs The attributes set containing the Workspace's customization values.
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800277 * @param defStyle Unused.
278 */
279 public Workspace(Context context, AttributeSet attrs, int defStyle) {
280 super(context, attrs, defStyle);
Michael Jurka0142d492010-08-25 17:46:15 -0700281 mContentIsRefreshable = false;
Michael Jurka5f1c5092010-09-03 14:15:02 -0700282
Daniel Sandlere4f98912013-06-25 15:13:26 -0400283 mOutlineHelper = HolographicOutlineHelper.obtain(context);
284
Adam Cohenc6cc61d2012-04-04 12:47:08 -0700285 mDragEnforcer = new DropTarget.DragEnforcer(context);
Winson Chungf0ea4d32011-06-06 14:27:16 -0700286 // With workspace, data is available straight from the get-go
287 setDataIsReady();
288
Michael Jurka8bc66c72012-06-21 08:36:45 -0700289 mLauncher = (Launcher) context;
Winson Chung867ca622012-02-21 15:48:35 -0800290 final Resources res = getResources();
Michael Jurka869390b2012-05-06 15:55:19 -0700291 mWorkspaceFadeInAdjacentScreens = res.getBoolean(R.bool.config_workspaceFadeAdjacentScreens);
292 mFadeInAdjacentScreens = false;
Dianne Hackborn8f573952009-08-10 23:21:09 -0700293 mWallpaperManager = WallpaperManager.getInstance(context);
Winson Chungaafa03c2010-06-11 17:34:16 -0700294
295 TypedArray a = context.obtainStyledAttributes(attrs,
296 R.styleable.Workspace, defStyle, 0);
Winson Chungb26f3d62011-06-02 10:49:29 -0700297 mSpringLoadedShrinkFactor =
298 res.getInteger(R.integer.config_workspaceSpringLoadShrinkPercentage) / 100.0f;
Adam Cohenf358a4b2013-07-23 16:47:31 -0700299 mOverviewModeShrinkFactor =
300 res.getInteger(R.integer.config_workspaceOverviewShrinkPercentage) / 100.0f;
Adam Cohen94309882012-06-08 16:24:56 -0700301 mCameraDistance = res.getInteger(R.integer.config_cameraDistance);
Winson Chung9e6a0a22013-08-27 11:58:12 -0700302 mOriginalDefaultPage = mDefaultPage = a.getInt(R.styleable.Workspace_defaultScreen, 1);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800303 a.recycle();
304
Michael Jurka8b805b12012-04-18 14:23:14 -0700305 setOnHierarchyChangeListener(this);
Joe Onorato0d44e942009-11-16 18:20:51 -0800306 setHapticFeedbackEnabled(false);
Michael Jurka0142d492010-08-25 17:46:15 -0700307
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800308 initWorkspace();
Winson Chungc35afb22011-02-23 13:01:49 -0800309
310 // Disable multitouch across the workspace/all apps/customize tray
311 setMotionEventSplittingEnabled(true);
Svetoslav Ganov08055f62012-05-15 11:06:36 -0700312
313 // Unless otherwise specified this view is important for accessibility.
314 if (getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
315 setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
316 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800317 }
318
Michael Jurka038f9d82011-11-03 13:50:45 -0700319 // estimate the size of a widget with spans hSpan, vSpan. return MAX_VALUE for each
320 // dimension if unsuccessful
321 public int[] estimateItemSize(int hSpan, int vSpan,
Adam Cohend41fbf52012-02-16 23:53:59 -0800322 ItemInfo itemInfo, boolean springLoaded) {
Michael Jurka038f9d82011-11-03 13:50:45 -0700323 int[] size = new int[2];
324 if (getChildCount() > 0) {
325 CellLayout cl = (CellLayout) mLauncher.getWorkspace().getChildAt(0);
Adam Cohend41fbf52012-02-16 23:53:59 -0800326 Rect r = estimateItemPosition(cl, itemInfo, 0, 0, hSpan, vSpan);
327 size[0] = r.width();
328 size[1] = r.height();
Michael Jurka038f9d82011-11-03 13:50:45 -0700329 if (springLoaded) {
330 size[0] *= mSpringLoadedShrinkFactor;
331 size[1] *= mSpringLoadedShrinkFactor;
332 }
333 return size;
334 } else {
335 size[0] = Integer.MAX_VALUE;
336 size[1] = Integer.MAX_VALUE;
337 return size;
338 }
339 }
Adam Cohendcd297f2013-06-18 13:13:40 -0700340
Adam Cohend41fbf52012-02-16 23:53:59 -0800341 public Rect estimateItemPosition(CellLayout cl, ItemInfo pendingInfo,
Michael Jurka038f9d82011-11-03 13:50:45 -0700342 int hCell, int vCell, int hSpan, int vSpan) {
Adam Cohend41fbf52012-02-16 23:53:59 -0800343 Rect r = new Rect();
Michael Jurka038f9d82011-11-03 13:50:45 -0700344 cl.cellToRect(hCell, vCell, hSpan, vSpan, r);
Michael Jurka038f9d82011-11-03 13:50:45 -0700345 return r;
346 }
347
Michael Jurkad74c9842011-07-10 12:44:21 -0700348 public void onDragStart(DragSource source, Object info, int dragAction) {
349 mIsDragOccuring = true;
Michael Jurka3a0469d2012-06-21 09:38:41 -0700350 updateChildrenLayersEnabled(false);
Winson Chung641d71d2012-04-26 15:58:01 -0700351 mLauncher.lockScreenOrientation();
Michael Jurkaa3d30ad2012-05-08 13:43:43 -0700352 setChildrenBackgroundAlphaMultipliers(1f);
Winson Chungf561bdf2012-05-03 11:20:19 -0700353 // Prevent any Un/InstallShortcutReceivers from updating the db while we are dragging
354 InstallShortcutReceiver.enableInstallQueue();
355 UninstallShortcutReceiver.enableUninstallQueue();
Michael Jurkad74c9842011-07-10 12:44:21 -0700356 }
357
358 public void onDragEnd() {
359 mIsDragOccuring = false;
Michael Jurka3a0469d2012-06-21 09:38:41 -0700360 updateChildrenLayersEnabled(false);
Winson Chung4b919f82012-05-01 10:44:08 -0700361 mLauncher.unlockScreenOrientation(false);
Winson Chungf561bdf2012-05-03 11:20:19 -0700362
363 // Re-enable any Un/InstallShortcutReceiver and now process any queued items
364 InstallShortcutReceiver.disableAndFlushInstallQueue(getContext());
365 UninstallShortcutReceiver.disableAndFlushUninstallQueue(getContext());
Michael Jurkad74c9842011-07-10 12:44:21 -0700366 }
367
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800368 /**
369 * Initializes various states for this workspace.
370 */
Michael Jurka0142d492010-08-25 17:46:15 -0700371 protected void initWorkspace() {
Joe Onorato0589f0f2010-02-08 13:44:00 -0800372 Context context = getContext();
Michael Jurka0142d492010-08-25 17:46:15 -0700373 mCurrentPage = mDefaultPage;
374 Launcher.setScreen(mCurrentPage);
Daniel Sandlercc8befa2013-06-11 14:45:48 -0400375 LauncherAppState app = LauncherAppState.getInstance();
Winson Chung5f8afe62013-08-12 16:19:28 -0700376 DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
Joe Onorato0589f0f2010-02-08 13:44:00 -0800377 mIconCache = app.getIconCache();
Patrick Dubroycd68ff52010-10-28 17:57:05 -0700378 setWillNotDraw(false);
Romain Guyce3cbd12013-02-25 15:00:36 -0800379 setClipChildren(false);
380 setClipToPadding(false);
Adam Cohen7777d962011-08-18 18:58:38 -0700381 setChildrenDrawnWithCacheEnabled(true);
Adam Cohen7d30a372013-07-01 17:03:59 -0700382 setMinScale(0.5f);
Adam Cohen22cba7f2013-07-19 16:14:00 -0700383 setupLayoutTransition();
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800384
Adam Cohen482ed822012-03-02 14:15:13 -0800385 final Resources res = getResources();
Winson Chungb4b7fa72010-11-18 14:38:53 -0800386 try {
Winson Chungfd3385f2011-06-15 19:51:24 -0700387 mBackground = res.getDrawable(R.drawable.apps_customize_bg);
Winson Chungb4b7fa72010-11-18 14:38:53 -0800388 } catch (Resources.NotFoundException e) {
389 // In this case, we will skip drawing background protection
390 }
Winson Chung9171e6d2010-11-17 17:39:27 -0800391
Michael Jurkaab1983f2011-01-18 15:50:17 -0800392 mWallpaperOffset = new WallpaperOffsetInterpolator();
Adam Cohencff6af82011-09-13 14:51:53 -0700393 Display display = mLauncher.getWindowManager().getDefaultDisplay();
Michael Jurka84f2ce72012-04-13 15:08:01 -0700394 display.getSize(mDisplaySize);
Adam Cohen265b9a62011-12-07 14:37:18 -0800395
Winson Chung5f8afe62013-08-12 16:19:28 -0700396 mMaxDistanceForFolderCreation = (0.55f * grid.iconSizePx);
Adam Cohen265b9a62011-12-07 14:37:18 -0800397 mFlingThresholdVelocity = (int) (FLING_THRESHOLD_VELOCITY * mDensity);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800398 }
399
Adam Cohen22cba7f2013-07-19 16:14:00 -0700400 private void setupLayoutTransition() {
401 // We want to show layout transitions when pages are deleted, to close the gap.
402 mLayoutTransition = new LayoutTransition();
403 mLayoutTransition.enableTransitionType(LayoutTransition.DISAPPEARING);
404 mLayoutTransition.enableTransitionType(LayoutTransition.CHANGE_DISAPPEARING);
405 mLayoutTransition.disableTransitionType(LayoutTransition.APPEARING);
406 mLayoutTransition.disableTransitionType(LayoutTransition.CHANGE_APPEARING);
407 setLayoutTransition(mLayoutTransition);
408 }
409
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800410 @Override
Adam Cohenf34bab52010-09-30 14:11:56 -0700411 protected int getScrollMode() {
Winson Chungb26f3d62011-06-02 10:49:29 -0700412 return SmoothPagedView.X_LARGE_MODE;
Adam Cohenf34bab52010-09-30 14:11:56 -0700413 }
414
Michael Jurka08ee7702011-08-11 16:53:35 -0700415 @Override
Michael Jurka8b805b12012-04-18 14:23:14 -0700416 public void onChildViewAdded(View parent, View child) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800417 if (!(child instanceof CellLayout)) {
418 throw new IllegalArgumentException("A Workspace can only have CellLayout children.");
419 }
Adam Cohen2801caf2011-05-13 20:57:39 -0700420 CellLayout cl = ((CellLayout) child);
421 cl.setOnInterceptTouchListener(this);
Adam Cohen2801caf2011-05-13 20:57:39 -0700422 cl.setClickable(true);
alanv51944f12012-05-07 17:31:32 -0700423 cl.setContentDescription(getContext().getString(
424 R.string.workspace_description_format, getChildCount()));
Adam Cohen2801caf2011-05-13 20:57:39 -0700425
Winson Chungf70696d2013-06-25 16:19:53 -0700426 super.onChildViewAdded(parent, child);
Michael Jurka8b805b12012-04-18 14:23:14 -0700427 }
428
Michael Jurka920d7f42012-05-14 16:29:55 -0700429 protected boolean shouldDrawChild(View child) {
430 final CellLayout cl = (CellLayout) child;
431 return super.shouldDrawChild(child) &&
432 (cl.getShortcutsAndWidgets().getAlpha() > 0 ||
433 cl.getBackgroundAlpha() > 0);
434 }
435
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800436 /**
437 * @return The open folder on the current screen, or null if there is none
438 */
439 Folder getOpenFolder() {
Adam Cohen716b51e2011-06-30 12:09:54 -0700440 DragLayer dragLayer = mLauncher.getDragLayer();
Adam Cohen8e776a62011-06-28 18:10:06 -0700441 int count = dragLayer.getChildCount();
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800442 for (int i = 0; i < count; i++) {
Adam Cohen8e776a62011-06-28 18:10:06 -0700443 View child = dragLayer.getChildAt(i);
Winson Chungaafa03c2010-06-11 17:34:16 -0700444 if (child instanceof Folder) {
445 Folder folder = (Folder) child;
446 if (folder.getInfo().opened)
447 return folder;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800448 }
449 }
450 return null;
451 }
452
Patrick Dubroya0aa0122011-02-24 11:42:23 -0800453 boolean isTouchActive() {
454 return mTouchState != TOUCH_STATE_REST;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800455 }
456
Winson Chung9e6a0a22013-08-27 11:58:12 -0700457 public void removeAllWorkspaceScreens() {
458 Log.w(TAG, "10249126 - removeAllWorkspaceScreens()");
459 // Remove the pages and clear the screen models
460 removeAllViews();
461 mScreenOrder.clear();
462 mWorkspaceScreens.clear();
463 }
464
Adam Cohen89bddfa2013-08-20 11:57:13 -0700465 public long insertNewWorkspaceScreenBeforeEmptyScreen(long screenId) {
Winson Chung64359a52013-07-08 17:17:08 -0700466 // Find the index to insert this view into. If the empty screen exists, then
467 // insert it before that.
468 int insertIndex = mScreenOrder.indexOf(EXTRA_EMPTY_SCREEN_ID);
Winson Chung9e6a0a22013-08-27 11:58:12 -0700469 Log.w(TAG, "10249126 - insertNewWorkspaceScreenBeforeEmptyScreen(" + insertIndex + ")");
Winson Chung64359a52013-07-08 17:17:08 -0700470 if (insertIndex < 0) {
471 insertIndex = mScreenOrder.size();
472 }
Adam Cohen89bddfa2013-08-20 11:57:13 -0700473 return insertNewWorkspaceScreen(screenId, insertIndex);
Adam Cohendcd297f2013-06-18 13:13:40 -0700474 }
475
Adam Cohen89bddfa2013-08-20 11:57:13 -0700476 public long insertNewWorkspaceScreen(long screenId) {
477 return insertNewWorkspaceScreen(screenId, getChildCount());
Winson Chung64359a52013-07-08 17:17:08 -0700478 }
479
Adam Cohen89bddfa2013-08-20 11:57:13 -0700480 public long insertNewWorkspaceScreen(long screenId, int insertIndex) {
481 Log.w(TAG, "10249126 - insertNewWorkspaceScreen(" + screenId + ", " + insertIndex + ")");
Adam Cohendcd297f2013-06-18 13:13:40 -0700482 CellLayout newScreen = (CellLayout)
483 mLauncher.getLayoutInflater().inflate(R.layout.workspace_screen, null);
484
Adam Cohen7d30a372013-07-01 17:03:59 -0700485 newScreen.setOnLongClickListener(mLongClickListener);
Adam Cohenf358a4b2013-07-23 16:47:31 -0700486 newScreen.setOnClickListener(mLauncher);
Adam Cohendcd297f2013-06-18 13:13:40 -0700487 mWorkspaceScreens.put(screenId, newScreen);
Winson Chung64359a52013-07-08 17:17:08 -0700488 mScreenOrder.add(insertIndex, screenId);
489 addView(newScreen, insertIndex);
Adam Cohendcd297f2013-06-18 13:13:40 -0700490 return screenId;
491 }
492
Winson Chung98ca0f72013-07-29 12:58:51 -0700493 public void createCustomContentPage() {
Winson Chung76828c82013-08-19 15:43:29 -0700494 Log.w(TAG, "10249126 - createCustomContentPage()");
Adam Cohendcd297f2013-06-18 13:13:40 -0700495 CellLayout customScreen = (CellLayout)
Adam Cohen41eb4702013-06-27 15:08:59 -0700496 mLauncher.getLayoutInflater().inflate(R.layout.workspace_screen, null);
Adam Cohendcd297f2013-06-18 13:13:40 -0700497
Adam Cohendcd297f2013-06-18 13:13:40 -0700498 mWorkspaceScreens.put(CUSTOM_CONTENT_SCREEN_ID, customScreen);
499 mScreenOrder.add(0, CUSTOM_CONTENT_SCREEN_ID);
Adam Cohenedb40762013-07-18 16:45:45 -0700500
Adam Cohen2702ea02013-08-15 16:17:42 -0700501 // We want no padding on the custom content
502 customScreen.setPadding(0, 0, 0, 0);
503
Adam Cohenedb40762013-07-18 16:45:45 -0700504 addFullScreenPage(customScreen);
Michael Jurkaee0ce2b2013-07-02 17:24:35 -0700505
Adam Cohendcd297f2013-06-18 13:13:40 -0700506 // Ensure that the current page and default page are maintained.
Winson Chung9e6a0a22013-08-27 11:58:12 -0700507 mDefaultPage = mOriginalDefaultPage + 1;
Adam Cohendcd297f2013-06-18 13:13:40 -0700508 setCurrentPage(getCurrentPage() + 1);
509 }
510
Winson Chung98ca0f72013-07-29 12:58:51 -0700511 public void addToCustomContentPage(View customContent, CustomContentCallbacks callbacks) {
512 if (getPageIndexForScreenId(CUSTOM_CONTENT_SCREEN_ID) < 0) {
513 throw new RuntimeException("Expected custom content screen to exist");
514 }
515
516 // Add the custom content to the full screen custom page
517 CellLayout customScreen = getScreenWithId(CUSTOM_CONTENT_SCREEN_ID);
518 int spanX = customScreen.getCountX();
519 int spanY = customScreen.getCountY();
520 CellLayout.LayoutParams lp = new CellLayout.LayoutParams(0, 0, spanX, spanY);
521 lp.canReorder = false;
522 lp.isFullscreen = true;
523 customScreen.addViewToCellLayout(customContent, 0, 0, lp, true);
524
525 mCustomContentCallbacks = callbacks;
526 }
527
Adam Cohendcd297f2013-06-18 13:13:40 -0700528 public long commitExtraEmptyScreen() {
Winson Chung76828c82013-08-19 15:43:29 -0700529 Log.w(TAG, "10249126 - commitExtraEmptyScreen()");
Adam Cohendcd297f2013-06-18 13:13:40 -0700530 CellLayout cl = mWorkspaceScreens.get(EXTRA_EMPTY_SCREEN_ID);
Winson Chungc9168342013-06-26 14:54:55 -0700531 mWorkspaceScreens.remove(EXTRA_EMPTY_SCREEN_ID);
Adam Cohendcd297f2013-06-18 13:13:40 -0700532 mScreenOrder.remove(EXTRA_EMPTY_SCREEN_ID);
533
Michael Jurka104c4562013-07-08 18:03:46 -0700534 long newId = LauncherAppState.getLauncherProvider().generateNewScreenId();
Adam Cohendcd297f2013-06-18 13:13:40 -0700535 mWorkspaceScreens.put(newId, cl);
536 mScreenOrder.add(newId);
537
538 addExtraEmptyScreen();
Winson Chung64359a52013-07-08 17:17:08 -0700539
540 // Update the model for the new screen
541 mLauncher.getModel().updateWorkspaceScreenOrder(mLauncher, mScreenOrder);
542
Adam Cohendcd297f2013-06-18 13:13:40 -0700543 return newId;
544 }
545
546 public void addExtraEmptyScreen() {
Adam Cohen89bddfa2013-08-20 11:57:13 -0700547 insertNewWorkspaceScreen(EXTRA_EMPTY_SCREEN_ID);
Adam Cohendcd297f2013-06-18 13:13:40 -0700548 }
549
550 public CellLayout getScreenWithId(long screenId) {
Winson Chung76828c82013-08-19 15:43:29 -0700551 Log.w(TAG, "10249126 - getScreenWithId(" + screenId + ")");
Adam Cohendcd297f2013-06-18 13:13:40 -0700552 CellLayout layout = mWorkspaceScreens.get(screenId);
553 return layout;
554 }
555
556 public long getIdForScreen(CellLayout layout) {
Winson Chung76828c82013-08-19 15:43:29 -0700557 Log.w(TAG, "10249126 - getIdForScreen()");
Adam Cohendcd297f2013-06-18 13:13:40 -0700558 Iterator<Long> iter = mWorkspaceScreens.keySet().iterator();
559 while (iter.hasNext()) {
560 long id = iter.next();
561 if (mWorkspaceScreens.get(id) == layout) {
562 return id;
563 }
564 }
565 return -1;
566 }
567
568 public int getPageIndexForScreenId(long screenId) {
Winson Chung76828c82013-08-19 15:43:29 -0700569 Log.w(TAG, "10249126 - getPageIndexForScreenId(" + screenId + ")");
Adam Cohendcd297f2013-06-18 13:13:40 -0700570 return indexOfChild(mWorkspaceScreens.get(screenId));
571 }
572
573 public long getScreenIdForPageIndex(int index) {
Winson Chung5f8afe62013-08-12 16:19:28 -0700574 if (0 <= index && index < mScreenOrder.size()) {
575 return mScreenOrder.get(index);
576 }
577 return -1;
Adam Cohendcd297f2013-06-18 13:13:40 -0700578 }
579
Winson Chung0e6a7132013-08-23 12:55:10 -0700580 public boolean hasNonCustomEmptyScreens() {
581 Log.w(TAG, "10249126 - hasNonCustomEmptyScreens()");
582 Iterator<Long> iter = mWorkspaceScreens.keySet().iterator();
583 while (iter.hasNext()) {
584 long id = iter.next();
585 if (id >= 0) {
586 return true;
587 }
588 }
589 return false;
590 }
591
Winson Chungc9168342013-06-26 14:54:55 -0700592 ArrayList<Long> getScreenOrder() {
593 return mScreenOrder;
594 }
595
Adam Cohendcd297f2013-06-18 13:13:40 -0700596 public void stripEmptyScreens() {
Adam Cohenaccfd562013-07-12 14:40:40 -0700597 if (isPageMoving()) {
598 mStripScreensOnPageStopMoving = true;
599 return;
600 }
601
Winson Chung76828c82013-08-19 15:43:29 -0700602 Log.w(TAG, "10249126 - stripEmptyScreens()");
Winson Chung8481e322013-08-09 16:06:38 -0700603
Adam Cohenaccfd562013-07-12 14:40:40 -0700604 int currentPage = getNextPage();
Adam Cohendcd297f2013-06-18 13:13:40 -0700605 ArrayList<Long> removeScreens = new ArrayList<Long>();
606 for (Long id: mWorkspaceScreens.keySet()) {
607 CellLayout cl = mWorkspaceScreens.get(id);
Winson Chungc9168342013-06-26 14:54:55 -0700608 if (id >= 0 && cl.getShortcutsAndWidgets().getChildCount() == 0) {
Adam Cohendcd297f2013-06-18 13:13:40 -0700609 removeScreens.add(id);
610 }
611 }
612
613 int pageShift = 0;
614 for (Long id: removeScreens) {
Winson Chung76828c82013-08-19 15:43:29 -0700615 Log.w(TAG, "10249126 - \tremove(" + id + ")");
Adam Cohendcd297f2013-06-18 13:13:40 -0700616 CellLayout cl = mWorkspaceScreens.get(id);
617 mWorkspaceScreens.remove(id);
618 mScreenOrder.remove(id);
Adam Cohenaccfd562013-07-12 14:40:40 -0700619 if (indexOfChild(cl) < currentPage) {
Adam Cohendcd297f2013-06-18 13:13:40 -0700620 pageShift++;
621 }
622 removeView(cl);
623 }
Winson Chung64359a52013-07-08 17:17:08 -0700624
625 if (!removeScreens.isEmpty()) {
626 // Update the model if we have changed any screens
627 mLauncher.getModel().updateWorkspaceScreenOrder(mLauncher, mScreenOrder);
628 }
Adam Cohenaccfd562013-07-12 14:40:40 -0700629
630 if (pageShift >= 0) {
631 setCurrentPage(currentPage - pageShift);
632 }
Adam Cohendcd297f2013-06-18 13:13:40 -0700633 }
634
635 // See implementation for parameter definition.
636 void addInScreen(View child, long container, long screenId,
637 int x, int y, int spanX, int spanY) {
638 addInScreen(child, container, screenId, x, y, spanX, spanY, false, false);
639 }
640
641 // At bind time, we use the rank (screenId) to compute x and y for hotseat items.
642 // See implementation for parameter definition.
643 void addInScreenFromBind(View child, long container, long screenId, int x, int y,
644 int spanX, int spanY) {
645 addInScreen(child, container, screenId, x, y, spanX, spanY, false, true);
646 }
647
648 // See implementation for parameter definition.
649 void addInScreen(View child, long container, long screenId, int x, int y, int spanX, int spanY,
650 boolean insert) {
651 addInScreen(child, container, screenId, x, y, spanX, spanY, insert, false);
Winson Chungaafa03c2010-06-11 17:34:16 -0700652 }
653
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800654 /**
655 * Adds the specified child in the specified screen. The position and dimension of
656 * the child are defined by x, y, spanX and spanY.
657 *
658 * @param child The child to add in one of the workspace's screens.
Adam Cohendcd297f2013-06-18 13:13:40 -0700659 * @param screenId The screen in which to add the child.
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800660 * @param x The X position of the child in the screen's grid.
661 * @param y The Y position of the child in the screen's grid.
662 * @param spanX The number of cells spanned horizontally by the child.
663 * @param spanY The number of cells spanned vertically by the child.
664 * @param insert When true, the child is inserted at the beginning of the children list.
Adam Cohendcd297f2013-06-18 13:13:40 -0700665 * @param computeXYFromRank When true, we use the rank (stored in screenId) to compute
666 * the x and y position in which to place hotseat items. Otherwise
667 * we use the x and y position to compute the rank.
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800668 */
Adam Cohendcd297f2013-06-18 13:13:40 -0700669 void addInScreen(View child, long container, long screenId, int x, int y, int spanX, int spanY,
670 boolean insert, boolean computeXYFromRank) {
Winson Chung3d503fb2011-07-13 17:25:49 -0700671 if (container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
Adam Cohendcd297f2013-06-18 13:13:40 -0700672 if (getScreenWithId(screenId) == null) {
673 Log.e(TAG, "Skipping child, screenId " + screenId + " not found");
Winson Chung8481e322013-08-09 16:06:38 -0700674 // DEBUGGING - Print out the stack trace to see where we are adding from
675 new Throwable().printStackTrace();
Winson Chung3d503fb2011-07-13 17:25:49 -0700676 return;
677 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800678 }
Adam Cohendcd297f2013-06-18 13:13:40 -0700679 if (screenId == EXTRA_EMPTY_SCREEN_ID) {
Adam Cohendedbd962013-07-11 14:21:49 -0700680 // This should never happen
681 throw new RuntimeException("Screen id should not be EXTRA_EMPTY_SCREEN_ID");
Adam Cohendcd297f2013-06-18 13:13:40 -0700682 }
683
Winson Chung3d503fb2011-07-13 17:25:49 -0700684 final CellLayout layout;
685 if (container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
686 layout = mLauncher.getHotseat().getLayout();
Winson Chung4d279d92011-07-21 11:46:32 -0700687 child.setOnKeyListener(null);
Winson Chung3d503fb2011-07-13 17:25:49 -0700688
Adam Cohen099f60d2011-08-23 21:07:26 -0700689 // Hide folder title in the hotseat
690 if (child instanceof FolderIcon) {
691 ((FolderIcon) child).setTextVisible(false);
692 }
693
Adam Cohendcd297f2013-06-18 13:13:40 -0700694 if (computeXYFromRank) {
695 x = mLauncher.getHotseat().getCellXFromOrder((int) screenId);
696 y = mLauncher.getHotseat().getCellYFromOrder((int) screenId);
Winson Chung3d503fb2011-07-13 17:25:49 -0700697 } else {
Adam Cohendcd297f2013-06-18 13:13:40 -0700698 screenId = mLauncher.getHotseat().getOrderInHotseat(x, y);
Winson Chung3d503fb2011-07-13 17:25:49 -0700699 }
700 } else {
Adam Cohen099f60d2011-08-23 21:07:26 -0700701 // Show folder title if not in the hotseat
702 if (child instanceof FolderIcon) {
703 ((FolderIcon) child).setTextVisible(true);
704 }
Adam Cohendcd297f2013-06-18 13:13:40 -0700705 layout = getScreenWithId(screenId);
Adam Cohenac56cff2011-09-28 20:45:37 -0700706 child.setOnKeyListener(new IconKeyEventListener());
Winson Chung3d503fb2011-07-13 17:25:49 -0700707 }
708
Adam Cohen96d30a12013-07-16 18:13:21 -0700709 ViewGroup.LayoutParams genericLp = child.getLayoutParams();
Adam Cohened66b2b2012-01-23 17:28:51 -0800710 CellLayout.LayoutParams lp;
711 if (genericLp == null || !(genericLp instanceof CellLayout.LayoutParams)) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800712 lp = new CellLayout.LayoutParams(x, y, spanX, spanY);
713 } else {
Adam Cohened66b2b2012-01-23 17:28:51 -0800714 lp = (CellLayout.LayoutParams) genericLp;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800715 lp.cellX = x;
716 lp.cellY = y;
717 lp.cellHSpan = spanX;
718 lp.cellVSpan = spanY;
719 }
Winson Chungaafa03c2010-06-11 17:34:16 -0700720
Adam Cohen7f4eabe2011-04-21 16:19:16 -0700721 if (spanX < 0 && spanY < 0) {
722 lp.isLockedToGrid = false;
723 }
724
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700725 // Get the canonical child id to uniquely represent this view in this screen
Adam Cohendcd297f2013-06-18 13:13:40 -0700726 int childId = LauncherModel.getCellLayoutChildId(container, screenId, x, y, spanX, spanY);
Michael Jurkaf3ca3ab2010-10-20 17:08:24 -0700727 boolean markCellsAsOccupied = !(child instanceof Folder);
Winson Chung3d503fb2011-07-13 17:25:49 -0700728 if (!layout.addViewToCellLayout(child, insert ? 0 : -1, childId, lp, markCellsAsOccupied)) {
Winson Chungaafa03c2010-06-11 17:34:16 -0700729 // TODO: This branch occurs when the workspace is adding views
730 // outside of the defined grid
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700731 // maybe we should be deleting these items from the LauncherModel?
Winson Chungaafa03c2010-06-11 17:34:16 -0700732 Log.w(TAG, "Failed to add to item at (" + lp.cellX + "," + lp.cellY + ") to CellLayout");
733 }
734
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800735 if (!(child instanceof Folder)) {
Joe Onorato0d44e942009-11-16 18:20:51 -0800736 child.setHapticFeedbackEnabled(false);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800737 child.setOnLongClickListener(mLongClickListener);
738 }
Joe Onorato00acb122009-08-04 16:04:30 -0400739 if (child instanceof DropTarget) {
Winson Chungaafa03c2010-06-11 17:34:16 -0700740 mDragController.addDropTarget((DropTarget) child);
Joe Onorato00acb122009-08-04 16:04:30 -0400741 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800742 }
743
Patrick Dubroyd0ce1ec2011-01-19 18:47:27 -0800744 /**
Patrick Dubroye708c522011-03-01 16:03:43 -0800745 * Called directly from a CellLayout (not by the framework), after we've been added as a
746 * listener via setOnInterceptTouchEventListener(). This allows us to tell the CellLayout
747 * that it should intercept touch events, which is not something that is normally supported.
748 */
749 @Override
Michael Jurkadee05892010-07-27 10:01:56 -0700750 public boolean onTouch(View v, MotionEvent event) {
Adam Cohenf358a4b2013-07-23 16:47:31 -0700751 return (isSmall() || !isFinishedSwitchingState())
752 || (!isSmall() && indexOfChild(v) != mCurrentPage);
Patrick Dubroye708c522011-03-01 16:03:43 -0800753 }
754
Adam Cohenfc53cd22011-07-20 15:45:11 -0700755 public boolean isSwitchingState() {
756 return mIsSwitchingState;
757 }
758
Winson Chung70442722012-02-10 15:43:22 -0800759 /** This differs from isSwitchingState in that we take into account how far the transition
760 * has completed. */
Winson Chung9b0b2fe2012-02-24 13:03:34 -0800761 public boolean isFinishedSwitchingState() {
Winson Chung70442722012-02-10 15:43:22 -0800762 return !mIsSwitchingState || (mTransitionProgress > 0.5f);
763 }
764
Adam Cohended9f8d2010-11-03 13:25:16 -0700765 protected void onWindowVisibilityChanged (int visibility) {
766 mLauncher.onWindowVisibilityChanged(visibility);
Derek Prothroce9249e2013-07-30 15:32:39 -0400767 if (mCustomContentShowing && mCustomContentCallbacks != null) {
768 if (visibility == View.VISIBLE) {
769 mCustomContentCallbacks.onShow();
770 } else if (visibility == View.GONE) {
771 mCustomContentCallbacks.onHide();
772 }
773 }
Adam Cohended9f8d2010-11-03 13:25:16 -0700774 }
775
Michael Jurka5f1c5092010-09-03 14:15:02 -0700776 @Override
777 public boolean dispatchUnhandledMove(View focused, int direction) {
Winson Chung70442722012-02-10 15:43:22 -0800778 if (isSmall() || !isFinishedSwitchingState()) {
Michael Jurka5f1c5092010-09-03 14:15:02 -0700779 // when the home screens are shrunken, shouldn't allow side-scrolling
780 return false;
781 }
782 return super.dispatchUnhandledMove(focused, direction);
783 }
784
785 @Override
786 public boolean onInterceptTouchEvent(MotionEvent ev) {
Michael Jurkad771c962011-08-09 15:00:48 -0700787 switch (ev.getAction() & MotionEvent.ACTION_MASK) {
788 case MotionEvent.ACTION_DOWN:
Adam Cohenf8d28232011-02-01 21:47:00 -0800789 mXDown = ev.getX();
790 mYDown = ev.getY();
Adam Cohen3d1b2b42013-08-14 15:57:58 -0700791 mTouchDownTime = System.currentTimeMillis();
Michael Jurkad771c962011-08-09 15:00:48 -0700792 break;
793 case MotionEvent.ACTION_POINTER_UP:
794 case MotionEvent.ACTION_UP:
795 if (mTouchState == TOUCH_STATE_REST) {
796 final CellLayout currentPage = (CellLayout) getChildAt(mCurrentPage);
797 if (!currentPage.lastDownOnOccupiedCell()) {
798 onWallpaperTap(ev);
799 }
800 }
Adam Cohenf8d28232011-02-01 21:47:00 -0800801 }
Michael Jurka5f1c5092010-09-03 14:15:02 -0700802 return super.onInterceptTouchEvent(ev);
803 }
804
Adam Cohen3d509322012-06-06 14:10:04 -0700805 protected void reinflateWidgetsIfNecessary() {
806 final int clCount = getChildCount();
807 for (int i = 0; i < clCount; i++) {
808 CellLayout cl = (CellLayout) getChildAt(i);
809 ShortcutAndWidgetContainer swc = cl.getShortcutsAndWidgets();
810 final int itemCount = swc.getChildCount();
811 for (int j = 0; j < itemCount; j++) {
812 View v = swc.getChildAt(j);
813
814 if (v.getTag() instanceof LauncherAppWidgetInfo) {
815 LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) v.getTag();
816 LauncherAppWidgetHostView lahv = (LauncherAppWidgetHostView) info.hostView;
817 if (lahv != null && lahv.orientationChangedSincedInflation()) {
818 mLauncher.removeAppWidget(info);
819 // Remove the current widget which is inflated with the wrong orientation
820 cl.removeView(lahv);
821 mLauncher.bindAppWidget(info);
822 }
823 }
824 }
825 }
826 }
827
Michael Jurka1adf5392010-10-18 18:10:22 -0700828 @Override
829 protected void determineScrollingStart(MotionEvent ev) {
Winson Chung70442722012-02-10 15:43:22 -0800830 if (!isFinishedSwitchingState()) return;
Adam Cohenf8d28232011-02-01 21:47:00 -0800831
Adam Cohen3d1b2b42013-08-14 15:57:58 -0700832 float deltaX = ev.getX() - mXDown;
833 float absDeltaX = Math.abs(deltaX);
834 float absDeltaY = Math.abs(ev.getY() - mYDown);
Adam Cohenf8d28232011-02-01 21:47:00 -0800835
Adam Cohen3d1b2b42013-08-14 15:57:58 -0700836 if (Float.compare(absDeltaX, 0f) == 0) return;
Adam Cohenf8d28232011-02-01 21:47:00 -0800837
Adam Cohen3d1b2b42013-08-14 15:57:58 -0700838 float slope = absDeltaY / absDeltaX;
Winson Chung70442722012-02-10 15:43:22 -0800839 float theta = (float) Math.atan(slope);
Adam Cohenf8d28232011-02-01 21:47:00 -0800840
Adam Cohen3d1b2b42013-08-14 15:57:58 -0700841 if (absDeltaX > mTouchSlop || absDeltaY > mTouchSlop) {
Winson Chung70442722012-02-10 15:43:22 -0800842 cancelCurrentPageLongPress();
843 }
844
Adam Cohen3d1b2b42013-08-14 15:57:58 -0700845 boolean passRightSwipesToCustomContent =
846 (mTouchDownTime - mCustomContentShowTime) > CUSTOM_CONTENT_GESTURE_DELAY;
847
848 if (deltaX > 0 && getScreenIdForPageIndex(getCurrentPage()) == CUSTOM_CONTENT_SCREEN_ID
849 && passRightSwipesToCustomContent) {
850 // Pass swipes to the right to the custom content page.
851 return;
852 }
853
Winson Chung70442722012-02-10 15:43:22 -0800854 if (theta > MAX_SWIPE_ANGLE) {
855 // Above MAX_SWIPE_ANGLE, we don't want to ever start scrolling the workspace
856 return;
857 } else if (theta > START_DAMPING_TOUCH_SLOP_ANGLE) {
858 // Above START_DAMPING_TOUCH_SLOP_ANGLE and below MAX_SWIPE_ANGLE, we want to
859 // increase the touch slop to make it harder to begin scrolling the workspace. This
860 // results in vertically scrolling widgets to more easily. The higher the angle, the
861 // more we increase touch slop.
862 theta -= START_DAMPING_TOUCH_SLOP_ANGLE;
863 float extraRatio = (float)
864 Math.sqrt((theta / (MAX_SWIPE_ANGLE - START_DAMPING_TOUCH_SLOP_ANGLE)));
865 super.determineScrollingStart(ev, 1 + TOUCH_SLOP_DAMPING_FACTOR * extraRatio);
866 } else {
867 // Below START_DAMPING_TOUCH_SLOP_ANGLE, we don't do anything special
868 super.determineScrollingStart(ev);
Adam Cohenf8d28232011-02-01 21:47:00 -0800869 }
Michael Jurka1adf5392010-10-18 18:10:22 -0700870 }
871
Patrick Dubroy1262e362010-10-06 15:49:50 -0700872 protected void onPageBeginMoving() {
Winson Chung007c6982011-06-14 13:27:53 -0700873 super.onPageBeginMoving();
874
Michael Jurkad74c9842011-07-10 12:44:21 -0700875 if (isHardwareAccelerated()) {
Michael Jurka3a0469d2012-06-21 09:38:41 -0700876 updateChildrenLayersEnabled(false);
Michael Jurka0142d492010-08-25 17:46:15 -0700877 } else {
Michael Jurkad74c9842011-07-10 12:44:21 -0700878 if (mNextPage != INVALID_PAGE) {
879 // we're snapping to a particular screen
880 enableChildrenCache(mCurrentPage, mNextPage);
881 } else {
882 // this is when user is actively dragging a particular screen, they might
883 // swipe it either left or right (but we won't advance by more than one screen)
884 enableChildrenCache(mCurrentPage - 1, mCurrentPage + 1);
885 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800886 }
Winson Chung007c6982011-06-14 13:27:53 -0700887
888 // Only show page outlines as we pan if we are on large screen
Daniel Sandlere4f98912013-06-25 15:13:26 -0400889 if (LauncherAppState.getInstance().isScreenLarge()) {
Winson Chung007c6982011-06-14 13:27:53 -0700890 showOutlines();
891 }
Winson Chung1afedc32012-01-23 16:14:56 -0800892
Winson Chung70442722012-02-10 15:43:22 -0800893 // If we are not fading in adjacent screens, we still need to restore the alpha in case the
894 // user scrolls while we are transitioning (should not affect dispatchDraw optimizations)
Michael Jurka869390b2012-05-06 15:55:19 -0700895 if (!mWorkspaceFadeInAdjacentScreens) {
Winson Chung70442722012-02-10 15:43:22 -0800896 for (int i = 0; i < getChildCount(); ++i) {
Michael Jurkaa52570f2012-03-20 03:18:20 -0700897 ((CellLayout) getPageAt(i)).setShortcutAndWidgetAlpha(1f);
Winson Chung70442722012-02-10 15:43:22 -0800898 }
899 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800900 }
901
Patrick Dubroy1262e362010-10-06 15:49:50 -0700902 protected void onPageEndMoving() {
Winson Chung007c6982011-06-14 13:27:53 -0700903 super.onPageEndMoving();
904
Michael Jurkad74c9842011-07-10 12:44:21 -0700905 if (isHardwareAccelerated()) {
Michael Jurka3a0469d2012-06-21 09:38:41 -0700906 updateChildrenLayersEnabled(false);
Michael Jurkad74c9842011-07-10 12:44:21 -0700907 } else {
908 clearChildrenCache();
909 }
910
Winson Chung3bc21c32012-01-20 13:59:18 -0800911
912 if (mDragController.isDragging()) {
913 if (isSmall()) {
914 // If we are in springloaded mode, then force an event to check if the current touch
915 // is under a new page (to scroll to)
Winson Chung25460a12013-04-01 18:21:28 -0700916 mDragController.forceTouchMove();
Winson Chung3bc21c32012-01-20 13:59:18 -0800917 }
918 } else {
919 // If we are not mid-dragging, hide the page outlines if we are on a large screen
Daniel Sandlere4f98912013-06-25 15:13:26 -0400920 if (LauncherAppState.getInstance().isScreenLarge()) {
Winson Chung007c6982011-06-14 13:27:53 -0700921 hideOutlines();
922 }
Patrick Dubroy1262e362010-10-06 15:49:50 -0700923 }
Adam Cohen26976d92011-03-22 15:33:33 -0700924
925 if (mDelayedResizeRunnable != null) {
926 mDelayedResizeRunnable.run();
927 mDelayedResizeRunnable = null;
928 }
Winson Chungf0c6ae02012-03-21 16:10:31 -0700929
930 if (mDelayedSnapToPageRunnable != null) {
931 mDelayedSnapToPageRunnable.run();
932 mDelayedSnapToPageRunnable = null;
933 }
Adam Cohenaccfd562013-07-12 14:40:40 -0700934 if (mStripScreensOnPageStopMoving) {
935 stripEmptyScreens();
936 mStripScreensOnPageStopMoving = false;
937 }
Michael Jurka0142d492010-08-25 17:46:15 -0700938
Adam Cohen6ad0e7d2013-07-24 13:55:41 -0700939 if (hasCustomContent() && getNextPage() == 0 && !mCustomContentShowing) {
Adam Cohenbffe7452013-07-22 18:21:45 -0700940 mCustomContentShowing = true;
941 if (mCustomContentCallbacks != null) {
942 mCustomContentCallbacks.onShow();
Adam Cohen3d1b2b42013-08-14 15:57:58 -0700943 mCustomContentShowTime = System.currentTimeMillis();
Adam Cohenbffe7452013-07-22 18:21:45 -0700944 }
Adam Cohen6ad0e7d2013-07-24 13:55:41 -0700945 } else if (hasCustomContent() && getNextPage() != 0 && mCustomContentShowing) {
Adam Cohenbffe7452013-07-22 18:21:45 -0700946 mCustomContentShowing = false;
947 if (mCustomContentCallbacks != null) {
948 mCustomContentCallbacks.onHide();
949 mLauncher.resetQSBScroll();
950 }
951 }
Adam Cohen6ad0e7d2013-07-24 13:55:41 -0700952 }
953
954 @Override
955 protected void notifyPageSwitchListener() {
956 super.notifyPageSwitchListener();
957 Launcher.setScreen(mCurrentPage);
Michael Jurka0142d492010-08-25 17:46:15 -0700958 };
959
Michael Jurkac5b262c2011-01-12 20:24:50 -0800960 protected void setWallpaperDimension() {
Michael Jurka104c4562013-07-08 18:03:46 -0700961 WallpaperPickerActivity.suggestWallpaperDimension(mLauncher.getResources(),
962 mLauncher.getSharedPrefs(), mLauncher.getWindowManager(), mWallpaperManager);
Michael Jurkac5b262c2011-01-12 20:24:50 -0800963 }
964
Michael Jurkac5b262c2011-01-12 20:24:50 -0800965
Michael Jurkacc07e7a2013-08-26 20:56:35 +0200966 private float wallpaperOffsetForCurrentScroll() {
967 // Set wallpaper offset steps (1 / (number of screens - 1))
968 mWallpaperManager.setWallpaperOffsetSteps(1.0f / (getChildCount() - 1), 1.0f);
969 if (mMaxScrollX == 0) {
970 return 0;
971 }
Michael Jurkac5b262c2011-01-12 20:24:50 -0800972
Michael Jurkacc07e7a2013-08-26 20:56:35 +0200973 // do different behavior if it's alive wallpaper?
974 return getScrollX() / (float) mMaxScrollX;
Michael Jurkaab1983f2011-01-18 15:50:17 -0800975 }
976
Winson Chungf0c6ae02012-03-21 16:10:31 -0700977 protected void snapToPage(int whichPage, Runnable r) {
978 if (mDelayedSnapToPageRunnable != null) {
979 mDelayedSnapToPageRunnable.run();
980 }
981 mDelayedSnapToPageRunnable = r;
982 snapToPage(whichPage, SLOW_PAGE_SNAP_ANIMATION_DURATION);
983 }
984
Adam Cohendcd297f2013-06-18 13:13:40 -0700985 protected void snapToScreenId(long screenId, Runnable r) {
986 snapToPage(getPageIndexForScreenId(screenId), r);
987 }
988
Michael Jurkacc07e7a2013-08-26 20:56:35 +0200989 class WallpaperOffsetInterpolator implements Choreographer.FrameCallback {
990 float mFinalOffset = 0.0f;
991 float mCurrentOffset = 0.0f;
992 //long mLastWallpaperOffsetUpdateTime;
993 boolean mWaitingForCallback;
994 Choreographer mChoreographer;
995 Interpolator mInterpolator;
996 boolean mAnimating;
997 long mAnimationStartTime;
998 float mAnimationStartOffset;
999 final int ANIMATION_DURATION = 250;
1000 int mNumScreens;
Michael Jurkaab1983f2011-01-18 15:50:17 -08001001
1002 public WallpaperOffsetInterpolator() {
Michael Jurkacc07e7a2013-08-26 20:56:35 +02001003 mChoreographer = Choreographer.getInstance();
1004 mInterpolator = new DecelerateInterpolator(1.5f);
Michael Jurkaab1983f2011-01-18 15:50:17 -08001005 }
1006
Michael Jurkacc07e7a2013-08-26 20:56:35 +02001007 @Override
1008 public void doFrame(long frameTimeNanos) {
1009 mWaitingForCallback = false;
1010 if (computeScrollOffset()) {
1011 mWallpaperManager.setWallpaperOffsets(mWindowToken,
1012 mWallpaperOffset.getCurrX(), 0f);
1013 }
Michael Jurkaca5b8362011-01-27 13:23:26 -08001014 }
1015
Michael Jurkaab1983f2011-01-18 15:50:17 -08001016 public boolean computeScrollOffset() {
Michael Jurkacc07e7a2013-08-26 20:56:35 +02001017 final float oldOffset = mCurrentOffset;
1018 if (mAnimating) {
1019 long durationSinceAnimation = System.currentTimeMillis() - mAnimationStartTime;
1020 float t0 = durationSinceAnimation / (float) ANIMATION_DURATION;
1021 float t1 = mInterpolator.getInterpolation(t0);
1022 mCurrentOffset = mAnimationStartOffset +
1023 (mFinalOffset - mAnimationStartOffset) * t1;
1024 mAnimating = durationSinceAnimation < ANIMATION_DURATION;
Michael Jurkaca5b8362011-01-27 13:23:26 -08001025 } else {
Michael Jurkacc07e7a2013-08-26 20:56:35 +02001026 mCurrentOffset = mFinalOffset;
Michael Jurkaab1983f2011-01-18 15:50:17 -08001027 }
Michael Jurkaca5b8362011-01-27 13:23:26 -08001028
Michael Jurkacc07e7a2013-08-26 20:56:35 +02001029 if (Math.abs(oldOffset - mCurrentOffset) > 0.0000001f) {
1030 scheduleCallback();
1031 return true;
1032 }
1033 return false;
Michael Jurkaab1983f2011-01-18 15:50:17 -08001034 }
1035
1036 public float getCurrX() {
Michael Jurkacc07e7a2013-08-26 20:56:35 +02001037 return mCurrentOffset;
Michael Jurkaab1983f2011-01-18 15:50:17 -08001038 }
1039
1040 public float getFinalX() {
Michael Jurkacc07e7a2013-08-26 20:56:35 +02001041 return mFinalOffset;
Michael Jurkaab1983f2011-01-18 15:50:17 -08001042 }
1043
Michael Jurkacc07e7a2013-08-26 20:56:35 +02001044 private void animateToFinal() {
1045 mAnimating = true;
1046 mAnimationStartOffset = mCurrentOffset;
1047 mAnimationStartTime = System.currentTimeMillis();
Michael Jurkaab1983f2011-01-18 15:50:17 -08001048 }
1049
1050 public void setFinalX(float x) {
Michael Jurkacc07e7a2013-08-26 20:56:35 +02001051 scheduleCallback();
1052 mFinalOffset = Math.max(0f, Math.min(x, 1.0f));
1053 if (getChildCount() != mNumScreens) {
1054 if (mNumScreens > 0) {
1055 // Don't animate if we're going from 0 screens
1056 animateToFinal();
1057 }
1058 mNumScreens = getChildCount();
1059 }
Michael Jurkaab1983f2011-01-18 15:50:17 -08001060 }
1061
Michael Jurkacc07e7a2013-08-26 20:56:35 +02001062 private void scheduleCallback() {
1063 if (!mWaitingForCallback) {
1064 mChoreographer.postFrameCallback(this);
1065 mWaitingForCallback = true;
1066 }
Michael Jurkaab1983f2011-01-18 15:50:17 -08001067 }
1068
1069 public void jumpToFinal() {
Michael Jurkacc07e7a2013-08-26 20:56:35 +02001070 mCurrentOffset = mFinalOffset;
Michael Jurkaab1983f2011-01-18 15:50:17 -08001071 }
Dianne Hackborn8f573952009-08-10 23:21:09 -07001072 }
Winson Chungaafa03c2010-06-11 17:34:16 -07001073
Michael Jurka340c5f32010-10-21 16:49:19 -07001074 @Override
1075 public void computeScroll() {
1076 super.computeScroll();
Adam Cohenbeff8c62011-08-31 17:46:01 -07001077 syncWallpaperOffsetWithScroll();
Michael Jurka340c5f32010-10-21 16:49:19 -07001078 }
1079
Michael Jurkacc07e7a2013-08-26 20:56:35 +02001080 private void syncWallpaperOffsetWithScroll() {
1081 mWallpaperOffset.setFinalX(wallpaperOffsetForCurrentScroll());
1082 }
1083
Patrick Dubroy94f78a52011-02-28 17:39:16 -08001084 void showOutlines() {
Michael Jurkad74c9842011-07-10 12:44:21 -07001085 if (!isSmall() && !mIsSwitchingState) {
Winson Chung9171e6d2010-11-17 17:39:27 -08001086 if (mChildrenOutlineFadeOutAnimation != null) mChildrenOutlineFadeOutAnimation.cancel();
1087 if (mChildrenOutlineFadeInAnimation != null) mChildrenOutlineFadeInAnimation.cancel();
Michael Jurka2ecf9952012-06-18 12:52:28 -07001088 mChildrenOutlineFadeInAnimation = LauncherAnimUtils.ofFloat(this, "childrenOutlineAlpha", 1.0f);
Winson Chung9171e6d2010-11-17 17:39:27 -08001089 mChildrenOutlineFadeInAnimation.setDuration(CHILDREN_OUTLINE_FADE_IN_DURATION);
1090 mChildrenOutlineFadeInAnimation.start();
Michael Jurka3e7c7632010-10-02 16:01:03 -07001091 }
Adam Cohenf34bab52010-09-30 14:11:56 -07001092 }
1093
Patrick Dubroy94f78a52011-02-28 17:39:16 -08001094 void hideOutlines() {
Michael Jurkad74c9842011-07-10 12:44:21 -07001095 if (!isSmall() && !mIsSwitchingState) {
Winson Chung9171e6d2010-11-17 17:39:27 -08001096 if (mChildrenOutlineFadeInAnimation != null) mChildrenOutlineFadeInAnimation.cancel();
1097 if (mChildrenOutlineFadeOutAnimation != null) mChildrenOutlineFadeOutAnimation.cancel();
Michael Jurka2ecf9952012-06-18 12:52:28 -07001098 mChildrenOutlineFadeOutAnimation = LauncherAnimUtils.ofFloat(this, "childrenOutlineAlpha", 0.0f);
Winson Chung9171e6d2010-11-17 17:39:27 -08001099 mChildrenOutlineFadeOutAnimation.setDuration(CHILDREN_OUTLINE_FADE_OUT_DURATION);
1100 mChildrenOutlineFadeOutAnimation.setStartDelay(CHILDREN_OUTLINE_FADE_OUT_DELAY);
1101 mChildrenOutlineFadeOutAnimation.start();
Michael Jurka3e7c7632010-10-02 16:01:03 -07001102 }
Adam Cohenf34bab52010-09-30 14:11:56 -07001103 }
1104
Patrick Dubroy94f78a52011-02-28 17:39:16 -08001105 public void showOutlinesTemporarily() {
1106 if (!mIsPageMoving && !isTouchActive()) {
1107 snapToPage(mCurrentPage);
1108 }
1109 }
1110
Winson Chung9171e6d2010-11-17 17:39:27 -08001111 public void setChildrenOutlineAlpha(float alpha) {
1112 mChildrenOutlineAlpha = alpha;
Adam Cohenf34bab52010-09-30 14:11:56 -07001113 for (int i = 0; i < getChildCount(); i++) {
1114 CellLayout cl = (CellLayout) getChildAt(i);
1115 cl.setBackgroundAlpha(alpha);
1116 }
1117 }
1118
Winson Chung9171e6d2010-11-17 17:39:27 -08001119 public float getChildrenOutlineAlpha() {
1120 return mChildrenOutlineAlpha;
1121 }
1122
Michael Jurka9c6fbed2011-03-02 17:41:34 -08001123 void disableBackground() {
1124 mDrawBackground = false;
1125 }
1126 void enableBackground() {
1127 mDrawBackground = true;
1128 }
1129
Michael Jurka7bdb25a2011-08-03 15:16:44 -07001130 private void animateBackgroundGradient(float finalAlpha, boolean animated) {
Winson Chungb4b7fa72010-11-18 14:38:53 -08001131 if (mBackground == null) return;
Michael Jurkab9e14972011-07-25 17:57:40 -07001132 if (mBackgroundFadeInAnimation != null) {
1133 mBackgroundFadeInAnimation.cancel();
1134 mBackgroundFadeInAnimation = null;
1135 }
1136 if (mBackgroundFadeOutAnimation != null) {
1137 mBackgroundFadeOutAnimation.cancel();
1138 mBackgroundFadeOutAnimation = null;
1139 }
Michael Jurka7bdb25a2011-08-03 15:16:44 -07001140 float startAlpha = getBackgroundAlpha();
1141 if (finalAlpha != startAlpha) {
1142 if (animated) {
Michael Jurkaf1ad6082013-03-13 12:55:46 +01001143 mBackgroundFadeOutAnimation =
1144 LauncherAnimUtils.ofFloat(this, startAlpha, finalAlpha);
Michael Jurka7bdb25a2011-08-03 15:16:44 -07001145 mBackgroundFadeOutAnimation.addUpdateListener(new AnimatorUpdateListener() {
1146 public void onAnimationUpdate(ValueAnimator animation) {
1147 setBackgroundAlpha(((Float) animation.getAnimatedValue()).floatValue());
1148 }
1149 });
1150 mBackgroundFadeOutAnimation.setInterpolator(new DecelerateInterpolator(1.5f));
1151 mBackgroundFadeOutAnimation.setDuration(BACKGROUND_FADE_OUT_DURATION);
1152 mBackgroundFadeOutAnimation.start();
1153 } else {
1154 setBackgroundAlpha(finalAlpha);
1155 }
Michael Jurkab9e14972011-07-25 17:57:40 -07001156 }
Winson Chung9171e6d2010-11-17 17:39:27 -08001157 }
1158
1159 public void setBackgroundAlpha(float alpha) {
Michael Jurka9c6fbed2011-03-02 17:41:34 -08001160 if (alpha != mBackgroundAlpha) {
1161 mBackgroundAlpha = alpha;
1162 invalidate();
1163 }
Winson Chung9171e6d2010-11-17 17:39:27 -08001164 }
1165
Adam Cohenf34bab52010-09-30 14:11:56 -07001166 public float getBackgroundAlpha() {
1167 return mBackgroundAlpha;
1168 }
1169
Adam Cohen68d73932010-11-15 10:50:58 -08001170 float backgroundAlphaInterpolator(float r) {
1171 float pivotA = 0.1f;
1172 float pivotB = 0.4f;
1173 if (r < pivotA) {
1174 return 0;
1175 } else if (r > pivotB) {
1176 return 1.0f;
1177 } else {
1178 return (r - pivotA)/(pivotB - pivotA);
1179 }
1180 }
1181
Michael Jurkaa3d30ad2012-05-08 13:43:43 -07001182 private void updatePageAlphaValues(int screenCenter) {
Michael Jurka869390b2012-05-06 15:55:19 -07001183 boolean isInOverscroll = mOverScrollX < 0 || mOverScrollX > mMaxScrollX;
1184 if (mWorkspaceFadeInAdjacentScreens &&
1185 mState == State.NORMAL &&
1186 !mIsSwitchingState &&
1187 !isInOverscroll) {
1188 for (int i = 0; i < getChildCount(); i++) {
1189 CellLayout child = (CellLayout) getChildAt(i);
1190 if (child != null) {
1191 float scrollProgress = getScrollProgress(screenCenter, child, i);
Adam Cohen73894962011-10-31 13:17:17 -07001192 float alpha = 1 - Math.abs(scrollProgress);
Michael Jurka869390b2012-05-06 15:55:19 -07001193 child.getShortcutsAndWidgets().setAlpha(alpha);
Michael Jurkaa3d30ad2012-05-08 13:43:43 -07001194 if (!mIsDragOccuring) {
1195 child.setBackgroundAlphaMultiplier(
1196 backgroundAlphaInterpolator(Math.abs(scrollProgress)));
1197 } else {
1198 child.setBackgroundAlphaMultiplier(1f);
1199 }
Adam Cohen73894962011-10-31 13:17:17 -07001200 }
Adam Cohenf34bab52010-09-30 14:11:56 -07001201 }
1202 }
Michael Jurkaa3d30ad2012-05-08 13:43:43 -07001203 }
1204
1205 private void setChildrenBackgroundAlphaMultipliers(float a) {
1206 for (int i = 0; i < getChildCount(); i++) {
1207 CellLayout child = (CellLayout) getChildAt(i);
1208 child.setBackgroundAlphaMultiplier(a);
1209 }
1210 }
1211
Winson Chung98ca0f72013-07-29 12:58:51 -07001212 public boolean hasCustomContent() {
Adam Cohenedb40762013-07-18 16:45:45 -07001213 return (mScreenOrder.size() > 0 && mScreenOrder.get(0) == CUSTOM_CONTENT_SCREEN_ID);
1214 }
1215
Adam Cohenbffe7452013-07-22 18:21:45 -07001216 public boolean isOnOrMovingToCustomContent() {
1217 return hasCustomContent() && getNextPage() == 0;
1218 }
1219
Adam Cohenedb40762013-07-18 16:45:45 -07001220 private void updateStateForCustomContent(int screenCenter) {
Adam Cohenf358a4b2013-07-23 16:47:31 -07001221 if (hasCustomContent() && !isSmall() && !isSwitchingState()) {
Adam Cohenedb40762013-07-18 16:45:45 -07001222 int index = mScreenOrder.indexOf(CUSTOM_CONTENT_SCREEN_ID);
Adam Cohenedb40762013-07-18 16:45:45 -07001223 int scrollDelta = getScrollForPage(index + 1) - getScrollX();
Adam Cohenedb40762013-07-18 16:45:45 -07001224 float progress = (1.0f * scrollDelta) /
1225 (getScrollForPage(index + 1) - getScrollForPage(index));
Adam Cohen955806d2013-07-19 16:36:43 -07001226 progress = Math.max(0, progress);
Adam Cohenedb40762013-07-18 16:45:45 -07001227
1228 setBackgroundAlpha(progress * 0.8f);
Winson Chungc763c4e2013-07-19 13:49:06 -07001229 float height = getViewportHeight();
1230 if (getPageIndicator() != null) {
1231 height -= getPageIndicator().getTop();
1232 } else if (mLauncher.getHotseat() != null) {
1233 height -= mLauncher.getHotseat().getTop();
1234 }
1235 float transY = progress * height;
Adam Cohen22cba7f2013-07-19 16:14:00 -07001236
1237 if (mLauncher.getHotseat() != null) {
Adam Cohen955806d2013-07-19 16:36:43 -07001238 mLauncher.getHotseat().setTranslationY(transY);
Adam Cohen6ad0e7d2013-07-24 13:55:41 -07001239 mLauncher.getHotseat().setAlpha(1 - progress);
Adam Cohen22cba7f2013-07-19 16:14:00 -07001240 }
1241 if (getPageIndicator() != null) {
Adam Cohenf358a4b2013-07-23 16:47:31 -07001242 final float alpha = 1 - progress;
1243 final View pi = getPageIndicator();
1244 getPageIndicator().setAlpha(alpha);
1245 if (alpha < ALPHA_CUTOFF_THRESHOLD && pi.getVisibility() != INVISIBLE) {
1246 pi.setVisibility(INVISIBLE);
1247 } else if (alpha > ALPHA_CUTOFF_THRESHOLD && pi.getVisibility() != VISIBLE) {
1248 pi.setVisibility(VISIBLE);
1249 }
Adam Cohen22cba7f2013-07-19 16:14:00 -07001250 }
Adam Cohenedb40762013-07-18 16:45:45 -07001251 }
1252 }
1253
Michael Jurkaa3d30ad2012-05-08 13:43:43 -07001254 @Override
1255 protected void screenScrolled(int screenCenter) {
Winson Chung52aee602013-01-30 12:01:02 -08001256 final boolean isRtl = isLayoutRtl();
Michael Jurkaa3d30ad2012-05-08 13:43:43 -07001257 super.screenScrolled(screenCenter);
1258
1259 updatePageAlphaValues(screenCenter);
Adam Cohenedb40762013-07-18 16:45:45 -07001260 updateStateForCustomContent(screenCenter);
Michael Jurkad51f33a2012-06-28 15:35:26 -07001261 enableHwLayersOnVisiblePages();
Adam Cohenf34bab52010-09-30 14:11:56 -07001262
Adam Cohenedb40762013-07-18 16:45:45 -07001263 if ((mOverScrollX < 0 && !hasCustomContent()) || mOverScrollX > mMaxScrollX) {
Winson Chung52aee602013-01-30 12:01:02 -08001264 int index = 0;
1265 float pivotX = 0f;
1266 final float leftBiasedPivot = 0.25f;
1267 final float rightBiasedPivot = 0.75f;
1268 final int lowerIndex = 0;
1269 final int upperIndex = getChildCount() - 1;
1270 if (isRtl) {
1271 index = mOverScrollX < 0 ? upperIndex : lowerIndex;
1272 pivotX = (index == 0 ? leftBiasedPivot : rightBiasedPivot);
1273 } else {
1274 index = mOverScrollX < 0 ? lowerIndex : upperIndex;
1275 pivotX = (index == 0 ? rightBiasedPivot : leftBiasedPivot);
1276 }
1277
Adam Cohenb5ba0972011-09-07 18:02:31 -07001278 CellLayout cl = (CellLayout) getChildAt(index);
1279 float scrollProgress = getScrollProgress(screenCenter, cl, index);
Winson Chung52aee602013-01-30 12:01:02 -08001280 final boolean isLeftPage = (isRtl ? index > 0 : index == 0);
1281 cl.setOverScrollAmount(Math.abs(scrollProgress), isLeftPage);
1282 float rotation = -WORKSPACE_OVERSCROLL_ROTATION * scrollProgress;
Adam Cohenb5ba0972011-09-07 18:02:31 -07001283 cl.setRotationY(rotation);
Michael Jurkab06d95f2012-04-02 06:26:53 -07001284 if (!mOverscrollTransformsSet) {
1285 mOverscrollTransformsSet = true;
Adam Cohen94309882012-06-08 16:24:56 -07001286 cl.setCameraDistance(mDensity * mCameraDistance);
Winson Chung52aee602013-01-30 12:01:02 -08001287 cl.setPivotX(cl.getMeasuredWidth() * pivotX);
Michael Jurkab06d95f2012-04-02 06:26:53 -07001288 cl.setPivotY(cl.getMeasuredHeight() * 0.5f);
1289 cl.setOverscrollTransformsDirty(true);
1290 }
Adam Cohenb5ba0972011-09-07 18:02:31 -07001291 } else {
Michael Jurkab06d95f2012-04-02 06:26:53 -07001292 if (mOverscrollTransformsSet) {
1293 mOverscrollTransformsSet = false;
Adam Cohenebea84d2011-11-09 17:20:41 -08001294 ((CellLayout) getChildAt(0)).resetOverscrollTransforms();
1295 ((CellLayout) getChildAt(getChildCount() - 1)).resetOverscrollTransforms();
Adam Cohen7842d7f2011-09-12 15:28:15 -07001296 }
Adam Cohenb5ba0972011-09-07 18:02:31 -07001297 }
1298 }
1299
1300 @Override
Adam Cohenb5ba0972011-09-07 18:02:31 -07001301 protected void overScroll(float amount) {
Michael Jurka869390b2012-05-06 15:55:19 -07001302 acceleratedOverScroll(amount);
Adam Cohenb5ba0972011-09-07 18:02:31 -07001303 }
1304
Joe Onorato00acb122009-08-04 16:04:30 -04001305 protected void onAttachedToWindow() {
1306 super.onAttachedToWindow();
Michael Jurka9c6fbed2011-03-02 17:41:34 -08001307 mWindowToken = getWindowToken();
Joe Onorato956091b2010-02-19 12:47:40 -08001308 computeScroll();
Michael Jurka9c6fbed2011-03-02 17:41:34 -08001309 mDragController.setWindowToken(mWindowToken);
1310 }
1311
1312 protected void onDetachedFromWindow() {
Romain Guye6661952013-08-08 19:13:22 -07001313 super.onDetachedFromWindow();
Michael Jurka9c6fbed2011-03-02 17:41:34 -08001314 mWindowToken = null;
Joe Onorato00acb122009-08-04 16:04:30 -04001315 }
1316
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001317 @Override
Michael Jurka28750fb2010-09-24 17:43:49 -07001318 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
Michael Jurkac5b262c2011-01-12 20:24:50 -08001319 if (mFirstLayout && mCurrentPage >= 0 && mCurrentPage < getChildCount()) {
Michael Jurkacc07e7a2013-08-26 20:56:35 +02001320 syncWallpaperOffsetWithScroll();
1321 mWallpaperOffset.jumpToFinal();
Michael Jurkac5b262c2011-01-12 20:24:50 -08001322 }
Michael Jurka0142d492010-08-25 17:46:15 -07001323 super.onLayout(changed, left, top, right, bottom);
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001324 }
1325
1326 @Override
Winson Chung9171e6d2010-11-17 17:39:27 -08001327 protected void onDraw(Canvas canvas) {
1328 // Draw the background gradient if necessary
Michael Jurka9c6fbed2011-03-02 17:41:34 -08001329 if (mBackground != null && mBackgroundAlpha > 0.0f && mDrawBackground) {
Winson Chung8d006d52010-11-29 15:55:29 -08001330 int alpha = (int) (mBackgroundAlpha * 255);
Winson Chungf0ea4d32011-06-06 14:27:16 -07001331 mBackground.setAlpha(alpha);
Michael Jurka8b805b12012-04-18 14:23:14 -07001332 mBackground.setBounds(getScrollX(), 0, getScrollX() + getMeasuredWidth(),
Winson Chungf0ea4d32011-06-06 14:27:16 -07001333 getMeasuredHeight());
1334 mBackground.draw(canvas);
Winson Chung9171e6d2010-11-17 17:39:27 -08001335 }
Adam Cohen073a46f2011-05-17 16:28:09 -07001336
Winson Chung9171e6d2010-11-17 17:39:27 -08001337 super.onDraw(canvas);
Winson Chungb8b2a5a2012-07-12 17:55:31 -07001338
1339 // Call back to LauncherModel to finish binding after the first draw
Romain Guyeeacd562012-10-10 18:47:33 -07001340 post(mBindPages);
Winson Chung9171e6d2010-11-17 17:39:27 -08001341 }
1342
Adam Cohen21b41102011-11-01 17:29:52 -07001343 boolean isDrawingBackgroundGradient() {
1344 return (mBackground != null && mBackgroundAlpha > 0.0f && mDrawBackground);
1345 }
1346
Michael Jurkadfab7f02011-11-18 13:01:04 -08001347 @Override
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001348 protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
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();
1351 if (openFolder != null) {
1352 return openFolder.requestFocus(direction, previouslyFocusedRect);
1353 } else {
Michael Jurka0142d492010-08-25 17:46:15 -07001354 return super.onRequestFocusInDescendants(direction, previouslyFocusedRect);
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001355 }
1356 }
1357 return false;
1358 }
1359
1360 @Override
Winson Chung97d85d22011-04-13 11:27:36 -07001361 public int getDescendantFocusability() {
Michael Jurkad74c9842011-07-10 12:44:21 -07001362 if (isSmall()) {
Winson Chung97d85d22011-04-13 11:27:36 -07001363 return ViewGroup.FOCUS_BLOCK_DESCENDANTS;
1364 }
1365 return super.getDescendantFocusability();
1366 }
1367
1368 @Override
Romain Guyc2e24c02009-06-01 16:11:41 -07001369 public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
Joe Onorato67886212009-09-14 19:05:05 -04001370 if (!mLauncher.isAllAppsVisible()) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001371 final Folder openFolder = getOpenFolder();
Michael Jurka0142d492010-08-25 17:46:15 -07001372 if (openFolder != null) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001373 openFolder.addFocusables(views, direction);
Michael Jurka0142d492010-08-25 17:46:15 -07001374 } else {
1375 super.addFocusables(views, direction, focusableMode);
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001376 }
1377 }
1378 }
1379
Michael Jurkad74c9842011-07-10 12:44:21 -07001380 public boolean isSmall() {
Adam Cohenf358a4b2013-07-23 16:47:31 -07001381 return mState == State.SMALL || mState == State.SPRING_LOADED || mState == State.OVERVIEW;
Michael Jurkad74c9842011-07-10 12:44:21 -07001382 }
1383
Michael Jurka0142d492010-08-25 17:46:15 -07001384 void enableChildrenCache(int fromPage, int toPage) {
1385 if (fromPage > toPage) {
1386 final int temp = fromPage;
1387 fromPage = toPage;
1388 toPage = temp;
Mike Cleron3a2b3f22009-11-05 17:17:42 -08001389 }
Winson Chungaafa03c2010-06-11 17:34:16 -07001390
Michael Jurkadee05892010-07-27 10:01:56 -07001391 final int screenCount = getChildCount();
Adam Powellfea5d022010-04-29 11:42:45 -07001392
Michael Jurka0142d492010-08-25 17:46:15 -07001393 fromPage = Math.max(fromPage, 0);
1394 toPage = Math.min(toPage, screenCount - 1);
Adam Powellfea5d022010-04-29 11:42:45 -07001395
Michael Jurka0142d492010-08-25 17:46:15 -07001396 for (int i = fromPage; i <= toPage; i++) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001397 final CellLayout layout = (CellLayout) getChildAt(i);
1398 layout.setChildrenDrawnWithCacheEnabled(true);
1399 layout.setChildrenDrawingCacheEnabled(true);
1400 }
1401 }
1402
1403 void clearChildrenCache() {
Michael Jurkadee05892010-07-27 10:01:56 -07001404 final int screenCount = getChildCount();
1405 for (int i = 0; i < screenCount; i++) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001406 final CellLayout layout = (CellLayout) getChildAt(i);
1407 layout.setChildrenDrawnWithCacheEnabled(false);
Adam Cohen8182e5b2011-08-01 15:43:31 -07001408 // In software mode, we don't want the items to continue to be drawn into bitmaps
1409 if (!isHardwareAccelerated()) {
1410 layout.setChildrenDrawingCacheEnabled(false);
1411 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001412 }
1413 }
1414
Michael Jurka3a0469d2012-06-21 09:38:41 -07001415 private void updateChildrenLayersEnabled(boolean force) {
Adam Cohenf358a4b2013-07-23 16:47:31 -07001416 boolean small = mState == State.SMALL || mState == State.OVERVIEW || mIsSwitchingState;
Michael Jurka3a0469d2012-06-21 09:38:41 -07001417 boolean enableChildrenLayers = force || small || mAnimatingViewIntoPlace || isPageMoving();
Michael Jurkad74c9842011-07-10 12:44:21 -07001418
1419 if (enableChildrenLayers != mChildrenLayersEnabled) {
1420 mChildrenLayersEnabled = enableChildrenLayers;
Michael Jurkad51f33a2012-06-28 15:35:26 -07001421 if (mChildrenLayersEnabled) {
1422 enableHwLayersOnVisiblePages();
1423 } else {
1424 for (int i = 0; i < getPageCount(); i++) {
1425 final CellLayout cl = (CellLayout) getChildAt(i);
1426 cl.disableHardwareLayers();
1427 }
1428 }
1429 }
1430 }
1431
1432 private void enableHwLayersOnVisiblePages() {
1433 if (mChildrenLayersEnabled) {
1434 final int screenCount = getChildCount();
1435 getVisiblePages(mTempVisiblePagesRange);
1436 int leftScreen = mTempVisiblePagesRange[0];
1437 int rightScreen = mTempVisiblePagesRange[1];
1438 if (leftScreen == rightScreen) {
1439 // make sure we're caching at least two pages always
1440 if (rightScreen < screenCount - 1) {
1441 rightScreen++;
1442 } else if (leftScreen > 0) {
1443 leftScreen--;
1444 }
1445 }
1446 for (int i = 0; i < screenCount; i++) {
Michael Jurka47639b92013-01-14 12:42:27 +01001447 final CellLayout layout = (CellLayout) getPageAt(i);
Michael Jurkad51f33a2012-06-28 15:35:26 -07001448 if (!(leftScreen <= i && i <= rightScreen && shouldDrawChild(layout))) {
1449 layout.disableHardwareLayers();
1450 }
1451 }
1452 for (int i = 0; i < screenCount; i++) {
Michael Jurka47639b92013-01-14 12:42:27 +01001453 final CellLayout layout = (CellLayout) getPageAt(i);
Michael Jurkad51f33a2012-06-28 15:35:26 -07001454 if (leftScreen <= i && i <= rightScreen && shouldDrawChild(layout)) {
1455 layout.enableHardwareLayers();
1456 }
Michael Jurkad74c9842011-07-10 12:44:21 -07001457 }
Michael Jurkace7e05f2011-02-01 22:02:35 -08001458 }
Michael Jurkace7e05f2011-02-01 22:02:35 -08001459 }
1460
Michael Jurka3a0469d2012-06-21 09:38:41 -07001461 public void buildPageHardwareLayers() {
1462 // force layers to be enabled just for the call to buildLayer
1463 updateChildrenLayersEnabled(true);
1464 if (getWindowToken() != null) {
1465 final int childCount = getChildCount();
1466 for (int i = 0; i < childCount; i++) {
1467 CellLayout cl = (CellLayout) getChildAt(i);
Michael Jurkad51f33a2012-06-28 15:35:26 -07001468 cl.buildHardwareLayer();
Michael Jurka3a0469d2012-06-21 09:38:41 -07001469 }
1470 }
1471 updateChildrenLayersEnabled(false);
1472 }
1473
Jeff Brown1d0867c2010-12-02 18:27:39 -08001474 protected void onWallpaperTap(MotionEvent ev) {
1475 final int[] position = mTempCell;
1476 getLocationOnScreen(position);
1477
1478 int pointerIndex = ev.getActionIndex();
1479 position[0] += (int) ev.getX(pointerIndex);
1480 position[1] += (int) ev.getY(pointerIndex);
1481
1482 mWallpaperManager.sendWallpaperCommand(getWindowToken(),
1483 ev.getAction() == MotionEvent.ACTION_UP
1484 ? WallpaperManager.COMMAND_TAP : WallpaperManager.COMMAND_SECONDARY_TAP,
1485 position[0], position[1], 0, null);
1486 }
1487
Adam Cohen61033d32010-11-15 18:29:44 -08001488 /*
1489 * This interpolator emulates the rate at which the perceived scale of an object changes
1490 * as its distance from a camera increases. When this interpolator is applied to a scale
1491 * animation on a view, it evokes the sense that the object is shrinking due to moving away
Andrew Flynn0dca1ec2012-02-29 13:33:22 -08001492 * from the camera.
Adam Cohen61033d32010-11-15 18:29:44 -08001493 */
1494 static class ZInterpolator implements TimeInterpolator {
1495 private float focalLength;
1496
1497 public ZInterpolator(float foc) {
1498 focalLength = foc;
1499 }
1500
Adam Coheneed565d2010-11-15 11:30:05 -08001501 public float getInterpolation(float input) {
1502 return (1.0f - focalLength / (focalLength + input)) /
Adam Cohen61033d32010-11-15 18:29:44 -08001503 (1.0f - focalLength / (focalLength + 1.0f));
Adam Cohencbbaf982010-11-12 14:50:33 -08001504 }
1505 }
1506
Adam Cohen61033d32010-11-15 18:29:44 -08001507 /*
1508 * The exact reverse of ZInterpolator.
1509 */
1510 static class InverseZInterpolator implements TimeInterpolator {
1511 private ZInterpolator zInterpolator;
1512 public InverseZInterpolator(float foc) {
1513 zInterpolator = new ZInterpolator(foc);
1514 }
Adam Cohencbbaf982010-11-12 14:50:33 -08001515 public float getInterpolation(float input) {
Adam Cohen61033d32010-11-15 18:29:44 -08001516 return 1 - zInterpolator.getInterpolation(1 - input);
Adam Cohencbbaf982010-11-12 14:50:33 -08001517 }
1518 }
1519
Adam Cohen61033d32010-11-15 18:29:44 -08001520 /*
1521 * ZInterpolator compounded with an ease-out.
1522 */
1523 static class ZoomOutInterpolator implements TimeInterpolator {
Adam Cohenb64d36e2011-10-17 21:48:02 -07001524 private final DecelerateInterpolator decelerate = new DecelerateInterpolator(0.75f);
1525 private final ZInterpolator zInterpolator = new ZInterpolator(0.13f);
Adam Cohen61033d32010-11-15 18:29:44 -08001526
1527 public float getInterpolation(float input) {
1528 return decelerate.getInterpolation(zInterpolator.getInterpolation(input));
1529 }
1530 }
1531
1532 /*
1533 * InvereZInterpolator compounded with an ease-out.
1534 */
1535 static class ZoomInInterpolator implements TimeInterpolator {
1536 private final InverseZInterpolator inverseZInterpolator = new InverseZInterpolator(0.35f);
1537 private final DecelerateInterpolator decelerate = new DecelerateInterpolator(3.0f);
1538
1539 public float getInterpolation(float input) {
1540 return decelerate.getInterpolation(inverseZInterpolator.getInterpolation(input));
1541 }
1542 }
1543
Adam Cohen61033d32010-11-15 18:29:44 -08001544 private final ZoomInInterpolator mZoomInInterpolator = new ZoomInInterpolator();
Michael Jurka3e7c7632010-10-02 16:01:03 -07001545
Michael Jurka3e7c7632010-10-02 16:01:03 -07001546 /*
Adam Cohen66396872011-04-15 17:50:36 -07001547 *
1548 * We call these methods (onDragStartedWithItemSpans/onDragStartedWithSize) whenever we
1549 * start a drag in Launcher, regardless of whether the drag has ever entered the Workspace
1550 *
1551 * These methods mark the appropriate pages as accepting drops (which alters their visual
1552 * appearance).
1553 *
1554 */
1555 public void onDragStartedWithItem(View v) {
Adam Cohen66396872011-04-15 17:50:36 -07001556 final Canvas canvas = new Canvas();
1557
Adam Cohen66396872011-04-15 17:50:36 -07001558 // The outline is used to visualize where the item will land if dropped
Adam Cohend41fbf52012-02-16 23:53:59 -08001559 mDragOutline = createDragOutline(v, canvas, DRAG_BITMAP_PADDING);
Adam Cohen66396872011-04-15 17:50:36 -07001560 }
1561
Michael Jurka8c3339b2012-06-14 16:18:21 -07001562 public void onDragStartedWithItem(PendingAddItemInfo info, Bitmap b, boolean clipAlpha) {
Michael Jurkad3ef3062010-11-23 16:23:58 -08001563 final Canvas canvas = new Canvas();
1564
Michael Jurka038f9d82011-11-03 13:50:45 -07001565 int[] size = estimateItemSize(info.spanX, info.spanY, info, false);
Adam Cohen66396872011-04-15 17:50:36 -07001566
Michael Jurkad3ef3062010-11-23 16:23:58 -08001567 // The outline is used to visualize where the item will land if dropped
Adam Cohend41fbf52012-02-16 23:53:59 -08001568 mDragOutline = createDragOutline(b, canvas, DRAG_BITMAP_PADDING, size[0],
Michael Jurka8c3339b2012-06-14 16:18:21 -07001569 size[1], clipAlpha);
Michael Jurka3e7c7632010-10-02 16:01:03 -07001570 }
1571
Patrick Dubroy758a9232011-03-03 19:54:56 -08001572 public void exitWidgetResizeMode() {
Adam Cohen716b51e2011-06-30 12:09:54 -07001573 DragLayer dragLayer = mLauncher.getDragLayer();
Adam Cohen67882692011-03-11 15:29:03 -08001574 dragLayer.clearAllResizeFrames();
Patrick Dubroy758a9232011-03-03 19:54:56 -08001575 }
1576
Adam Cohen4b285c52011-07-21 14:24:06 -07001577 private void initAnimationArrays() {
1578 final int childCount = getChildCount();
Adam Cohendcd297f2013-06-18 13:13:40 -07001579 if (mLastChildCount == childCount) return;
Adam Cohen7d30a372013-07-01 17:03:59 -07001580
Adam Cohen4b285c52011-07-21 14:24:06 -07001581 mOldBackgroundAlphas = new float[childCount];
Adam Cohen4b285c52011-07-21 14:24:06 -07001582 mOldAlphas = new float[childCount];
Adam Cohen4b285c52011-07-21 14:24:06 -07001583 mNewBackgroundAlphas = new float[childCount];
Adam Cohen4b285c52011-07-21 14:24:06 -07001584 mNewAlphas = new float[childCount];
Adam Cohen4b285c52011-07-21 14:24:06 -07001585 }
1586
Michael Jurka2a4b1a82011-12-07 14:00:02 -08001587 Animator getChangeStateAnimation(final State state, boolean animated) {
Adam Cohenf358a4b2013-07-23 16:47:31 -07001588 return getChangeStateAnimation(state, animated, 0, -1);
Adam Cohen7777d962011-08-18 18:58:38 -07001589 }
1590
Adam Cohenf358a4b2013-07-23 16:47:31 -07001591 @Override
1592 protected void getOverviewModePages(int[] range) {
Adam Cohendedbd962013-07-11 14:21:49 -07001593 int count = mScreenOrder.size();
1594
1595 int start = -1;
1596 int end = -1;
1597 //
1598 for (int i = 0; i < count; i++) {
1599 if (start < 0 && mScreenOrder.get(i) >= 0) {
1600 start = i;
1601 }
1602 if (start >=0 && mScreenOrder.get(i) >= 0) {
1603 end = i;
1604 }
1605 }
1606 range[0] = start;
1607 range[1] = end;
1608 }
1609
1610 protected void onStartReordering() {
1611 super.onStartReordering();
1612 int count = getChildCount();
1613 for (int i = 0; i < count; i++) {
1614 ((CellLayout) getChildAt(i)).setUseActiveGlowBackground(true);
1615 }
1616 showOutlines();
Adam Cohen22cba7f2013-07-19 16:14:00 -07001617
1618 // Reordering handles its own animations, disable the automatic ones.
1619 setLayoutTransition(null);
Adam Cohendedbd962013-07-11 14:21:49 -07001620 }
1621
1622 protected void onEndReordering() {
1623 super.onEndReordering();
1624 int count = getChildCount();
1625 for (int i = 0; i < count; i++) {
1626 ((CellLayout) getChildAt(i)).setUseActiveGlowBackground(false);
1627 }
1628 hideOutlines();
1629
1630 mScreenOrder.clear();
1631 for (int i = 0; i < count; i++) {
1632 CellLayout cl = ((CellLayout) getChildAt(i));
1633 mScreenOrder.add(getIdForScreen(cl));
1634 }
Winson Chungd64d1762013-08-20 14:37:16 -07001635
1636 Log.w(TAG, "10249126 - onEndReordering()");
Adam Cohendedbd962013-07-11 14:21:49 -07001637 mLauncher.getModel().updateWorkspaceScreenOrder(mLauncher, mScreenOrder);
Adam Cohen22cba7f2013-07-19 16:14:00 -07001638
1639 // Re-enable auto layout transitions for page deletion.
1640 setLayoutTransition(mLayoutTransition);
Adam Cohendedbd962013-07-11 14:21:49 -07001641 }
1642
Adam Cohenf358a4b2013-07-23 16:47:31 -07001643 public boolean isInOverviewMode() {
1644 return mState == State.OVERVIEW;
1645 }
1646
1647 public void enterOverviewMode() {
1648 enableOverviewMode(true, -1);
1649 }
1650
1651 public void exitOverviewMode() {
1652 exitOverviewMode(-1);
1653 }
1654
1655 public void exitOverviewMode(int snapPage) {
1656 enableOverviewMode(false, snapPage);
1657 }
1658
1659 private void enableOverviewMode(boolean enable, int snapPage) {
1660 State finalState = Workspace.State.OVERVIEW;
1661 if (!enable) {
1662 finalState = Workspace.State.NORMAL;
1663 }
1664
1665 Animator workspaceAnim = getChangeStateAnimation(finalState, true, 0, snapPage);
1666 workspaceAnim.addListener(new AnimatorListenerAdapter() {
1667 @Override
1668 public void onAnimationEnd(Animator arg0) {
1669 mIsSwitchingState = false;
1670 }
1671 @Override
1672 public void onAnimationStart(Animator arg0) {
1673 mIsSwitchingState = true;
1674 }
1675 });
1676 workspaceAnim.start();
1677 }
1678
1679 Animator getChangeStateAnimation(final State state, boolean animated, int delay, int snapPage) {
Michael Jurkabdf78552011-10-31 14:34:25 -07001680 if (mState == state) {
Michael Jurka2a4b1a82011-12-07 14:00:02 -08001681 return null;
Michael Jurka99633da2011-07-27 22:40:17 -07001682 }
1683
Winson Chung1b7c1d32011-10-25 12:09:38 -07001684 // Initialize animation arrays for the first time if necessary
1685 initAnimationArrays();
1686
Michael Jurka2ecf9952012-06-18 12:52:28 -07001687 AnimatorSet anim = animated ? LauncherAnimUtils.createAnimatorSet() : null;
Adam Lesinski6b879f02010-11-04 16:15:23 -07001688
Winson Chung1b7c1d32011-10-25 12:09:38 -07001689 final State oldState = mState;
1690 final boolean oldStateIsNormal = (oldState == State.NORMAL);
Michael Jurka4ff7d792012-04-02 03:46:50 -07001691 final boolean oldStateIsSpringLoaded = (oldState == State.SPRING_LOADED);
Winson Chung1b7c1d32011-10-25 12:09:38 -07001692 final boolean oldStateIsSmall = (oldState == State.SMALL);
Adam Cohenf358a4b2013-07-23 16:47:31 -07001693 final boolean oldStateIsOverview = (oldState == State.OVERVIEW);
Adam Cohen7777d962011-08-18 18:58:38 -07001694 mState = state;
Winson Chung1b7c1d32011-10-25 12:09:38 -07001695 final boolean stateIsNormal = (state == State.NORMAL);
1696 final boolean stateIsSpringLoaded = (state == State.SPRING_LOADED);
1697 final boolean stateIsSmall = (state == State.SMALL);
Adam Cohenf358a4b2013-07-23 16:47:31 -07001698 final boolean stateIsOverview = (state == State.OVERVIEW);
Winson Chung1b7c1d32011-10-25 12:09:38 -07001699 float finalBackgroundAlpha = stateIsSpringLoaded ? 1.0f : 0f;
Adam Cohenf358a4b2013-07-23 16:47:31 -07001700 float finalHotseatAndPageIndicatorAlpha = (stateIsOverview || stateIsSmall) ? 0f : 1f;
1701 float finalOverviewPanelAlpha = stateIsOverview ? 1f : 0f;
1702
Adam Cohen7777d962011-08-18 18:58:38 -07001703 boolean zoomIn = true;
Adam Cohen7d30a372013-07-01 17:03:59 -07001704 mNewScale = 1.0f;
Adam Cohenbeff8c62011-08-31 17:46:01 -07001705
Adam Cohenf358a4b2013-07-23 16:47:31 -07001706 if (oldStateIsOverview) {
1707 disableFreeScroll(snapPage);
1708 } else if (stateIsOverview) {
1709 enableFreeScroll();
1710 }
1711
Adam Cohen7777d962011-08-18 18:58:38 -07001712 if (state != State.NORMAL) {
Adam Cohenf358a4b2013-07-23 16:47:31 -07001713 if (stateIsSpringLoaded) {
1714 mNewScale = mSpringLoadedShrinkFactor;
1715 } else if (stateIsOverview) {
1716 mNewScale = mOverviewModeShrinkFactor;
1717 } else if (stateIsSmall){
1718 mNewScale = mOverviewModeShrinkFactor - 0.1f;
1719 }
Winson Chung1b7c1d32011-10-25 12:09:38 -07001720 if (oldStateIsNormal && stateIsSmall) {
Adam Cohen7777d962011-08-18 18:58:38 -07001721 zoomIn = false;
Michael Jurka3a0469d2012-06-21 09:38:41 -07001722 updateChildrenLayersEnabled(false);
Michael Jurkaca5b8362011-01-27 13:23:26 -08001723 } else {
Adam Cohencff6af82011-09-13 14:51:53 -07001724 finalBackgroundAlpha = 1.0f;
Adam Cohen7777d962011-08-18 18:58:38 -07001725 }
Adam Cohen7777d962011-08-18 18:58:38 -07001726 }
Andrew Flynn0dca1ec2012-02-29 13:33:22 -08001727 final int duration = zoomIn ?
Adam Cohen7777d962011-08-18 18:58:38 -07001728 getResources().getInteger(R.integer.config_workspaceUnshrinkTime) :
1729 getResources().getInteger(R.integer.config_appsCustomizeWorkspaceShrinkTime);
Winson Chung1b7c1d32011-10-25 12:09:38 -07001730 for (int i = 0; i < getChildCount(); i++) {
1731 final CellLayout cl = (CellLayout) getChildAt(i);
Michael Jurka869390b2012-05-06 15:55:19 -07001732 float finalAlpha = (!mWorkspaceFadeInAdjacentScreens || stateIsSpringLoaded ||
Winson Chung1b7c1d32011-10-25 12:09:38 -07001733 (i == mCurrentPage)) ? 1f : 0f;
Michael Jurka869390b2012-05-06 15:55:19 -07001734 float currentAlpha = cl.getShortcutsAndWidgets().getAlpha();
1735 float initialAlpha = currentAlpha;
Adam Cohen7777d962011-08-18 18:58:38 -07001736
Winson Chung1b7c1d32011-10-25 12:09:38 -07001737 // Determine the pages alpha during the state transition
1738 if ((oldStateIsSmall && stateIsNormal) ||
1739 (oldStateIsNormal && stateIsSmall)) {
1740 // To/from workspace - only show the current page unless the transition is not
Michael Jurka4ff7d792012-04-02 03:46:50 -07001741 // animated and the animation end callback below doesn't run;
1742 // or, if we're in spring-loaded mode
1743 if (i == mCurrentPage || !animated || oldStateIsSpringLoaded) {
Winson Chung1b7c1d32011-10-25 12:09:38 -07001744 finalAlpha = 1f;
Winson Chung1b7c1d32011-10-25 12:09:38 -07001745 } else {
1746 initialAlpha = 0f;
1747 finalAlpha = 0f;
1748 }
Adam Cohen7777d962011-08-18 18:58:38 -07001749 }
1750
Winson Chung1b7c1d32011-10-25 12:09:38 -07001751 mOldAlphas[i] = initialAlpha;
1752 mNewAlphas[i] = finalAlpha;
Adam Cohen7777d962011-08-18 18:58:38 -07001753 if (animated) {
Adam Cohen7777d962011-08-18 18:58:38 -07001754 mOldBackgroundAlphas[i] = cl.getBackgroundAlpha();
Adam Cohen7777d962011-08-18 18:58:38 -07001755 mNewBackgroundAlphas[i] = finalBackgroundAlpha;
Adam Cohen7777d962011-08-18 18:58:38 -07001756 } else {
Adam Cohen7d30a372013-07-01 17:03:59 -07001757 setScaleX(mNewScale);
1758 setScaleY(mNewScale);
Winson Chung1b7c1d32011-10-25 12:09:38 -07001759 cl.setBackgroundAlpha(finalBackgroundAlpha);
Michael Jurkaa52570f2012-03-20 03:18:20 -07001760 cl.setShortcutAndWidgetAlpha(finalAlpha);
Adam Cohen7777d962011-08-18 18:58:38 -07001761 }
Michael Jurkadee05892010-07-27 10:01:56 -07001762 }
Winson Chung8d006d52010-11-29 15:55:29 -08001763
Adam Cohen7777d962011-08-18 18:58:38 -07001764 if (animated) {
Adam Cohen7d30a372013-07-01 17:03:59 -07001765 LauncherViewPropertyAnimator scale = new LauncherViewPropertyAnimator(this);
1766 scale.scaleX(mNewScale)
1767 .scaleY(mNewScale)
1768 .setInterpolator(mZoomInInterpolator);
1769 anim.play(scale);
Michael Jurka7407d2a2011-12-12 21:48:38 -08001770 for (int index = 0; index < getChildCount(); index++) {
1771 final int i = index;
1772 final CellLayout cl = (CellLayout) getChildAt(i);
Michael Jurka869390b2012-05-06 15:55:19 -07001773 float currentAlpha = cl.getShortcutsAndWidgets().getAlpha();
Michael Jurka2a4b1a82011-12-07 14:00:02 -08001774 if (mOldAlphas[i] == 0 && mNewAlphas[i] == 0) {
Michael Jurka7372c592012-01-16 04:21:35 -08001775 cl.setBackgroundAlpha(mNewBackgroundAlphas[i]);
Michael Jurkaa52570f2012-03-20 03:18:20 -07001776 cl.setShortcutAndWidgetAlpha(mNewAlphas[i]);
Michael Jurka7407d2a2011-12-12 21:48:38 -08001777 } else {
Michael Jurkaa52570f2012-03-20 03:18:20 -07001778
Michael Jurka869390b2012-05-06 15:55:19 -07001779 if (mOldAlphas[i] != mNewAlphas[i] || currentAlpha != mNewAlphas[i]) {
Michael Jurka6c8a5792012-03-22 05:24:37 -07001780 LauncherViewPropertyAnimator alphaAnim =
1781 new LauncherViewPropertyAnimator(cl.getShortcutsAndWidgets());
Michael Jurkaa52570f2012-03-20 03:18:20 -07001782 alphaAnim.alpha(mNewAlphas[i])
1783 .setDuration(duration)
1784 .setInterpolator(mZoomInInterpolator);
1785 anim.play(alphaAnim);
1786 }
Michael Jurka7407d2a2011-12-12 21:48:38 -08001787 if (mOldBackgroundAlphas[i] != 0 ||
Michael Jurka869390b2012-05-06 15:55:19 -07001788 mNewBackgroundAlphas[i] != 0) {
Michael Jurkaf1ad6082013-03-13 12:55:46 +01001789 ValueAnimator bgAnim =
1790 LauncherAnimUtils.ofFloat(cl, 0f, 1f).setDuration(duration);
Michael Jurka7407d2a2011-12-12 21:48:38 -08001791 bgAnim.setInterpolator(mZoomInInterpolator);
1792 bgAnim.addUpdateListener(new LauncherAnimatorUpdateListener() {
1793 public void onAnimationUpdate(float a, float b) {
Michael Jurka7372c592012-01-16 04:21:35 -08001794 cl.setBackgroundAlpha(
Michael Jurka7407d2a2011-12-12 21:48:38 -08001795 a * mOldBackgroundAlphas[i] +
1796 b * mNewBackgroundAlphas[i]);
Michael Jurka7407d2a2011-12-12 21:48:38 -08001797 }
1798 });
1799 anim.play(bgAnim);
1800 }
Michael Jurka2a4b1a82011-12-07 14:00:02 -08001801 }
1802 }
Winson Chung66700732013-08-20 16:56:15 -07001803 ObjectAnimator pageIndicatorAlpha = null;
1804 if (getPageIndicator() != null) {
1805 pageIndicatorAlpha = ObjectAnimator.ofFloat(getPageIndicator(), "alpha",
1806 finalHotseatAndPageIndicatorAlpha);
1807 }
Adam Cohenf358a4b2013-07-23 16:47:31 -07001808 ObjectAnimator hotseatAlpha = ObjectAnimator.ofFloat(mLauncher.getHotseat(), "alpha",
1809 finalHotseatAndPageIndicatorAlpha);
Adam Cohenf358a4b2013-07-23 16:47:31 -07001810 ObjectAnimator overviewPanelAlpha = ObjectAnimator.ofFloat(mLauncher.getOverviewPanel(),
1811 "alpha", finalOverviewPanelAlpha);
1812 overviewPanelAlpha.addUpdateListener(new AlphaUpdateListener(
1813 mLauncher.getOverviewPanel()));
1814 hotseatAlpha.addUpdateListener(new AlphaUpdateListener(mLauncher.getHotseat()));
Winson Chung66700732013-08-20 16:56:15 -07001815 if (getPageIndicator() != null) {
1816 pageIndicatorAlpha.addUpdateListener(new AlphaUpdateListener(getPageIndicator()));
1817 }
Adam Cohenf358a4b2013-07-23 16:47:31 -07001818 anim.play(overviewPanelAlpha);
1819 anim.play(hotseatAlpha);
1820 anim.play(pageIndicatorAlpha);
Michael Jurka2a4b1a82011-12-07 14:00:02 -08001821 anim.setStartDelay(delay);
Adam Cohenf358a4b2013-07-23 16:47:31 -07001822 } else {
1823 mLauncher.getOverviewPanel().setAlpha(finalOverviewPanelAlpha);
1824 mLauncher.getHotseat().setAlpha(finalHotseatAndPageIndicatorAlpha);
Winson Chung66700732013-08-20 16:56:15 -07001825 if (getPageIndicator() != null) {
1826 getPageIndicator().setAlpha(finalHotseatAndPageIndicatorAlpha);
1827 }
Adam Cohen7777d962011-08-18 18:58:38 -07001828 }
1829
Winson Chung1b7c1d32011-10-25 12:09:38 -07001830 if (stateIsSpringLoaded) {
Michael Jurka7bdb25a2011-08-03 15:16:44 -07001831 // Right now we're covered by Apps Customize
1832 // Show the background gradient immediately, so the gradient will
1833 // be showing once AppsCustomize disappears
1834 animateBackgroundGradient(getResources().getInteger(
1835 R.integer.config_appsCustomizeSpringLoadedBgAlpha) / 100f, false);
1836 } else {
1837 // Fade the background gradient away
1838 animateBackgroundGradient(0f, true);
1839 }
Michael Jurka2a4b1a82011-12-07 14:00:02 -08001840 return anim;
Michael Jurkadee05892010-07-27 10:01:56 -07001841 }
1842
Adam Cohenf358a4b2013-07-23 16:47:31 -07001843 class AlphaUpdateListener implements AnimatorUpdateListener {
1844 View view;
1845 public AlphaUpdateListener(View v) {
1846 view = v;
1847 }
1848
1849 @Override
1850 public void onAnimationUpdate(ValueAnimator arg0) {
1851 if (view.getAlpha() < ALPHA_CUTOFF_THRESHOLD && view.getVisibility() != INVISIBLE) {
1852 view.setVisibility(INVISIBLE);
1853 } else if (view.getAlpha() > ALPHA_CUTOFF_THRESHOLD
1854 && view.getVisibility() != VISIBLE) {
1855 view.setVisibility(VISIBLE);
1856 }
1857 }
1858
1859 }
1860
Michael Jurkabed61d22012-02-14 22:51:29 -08001861 @Override
Michael Jurkaa35e35a2012-04-26 15:04:28 -07001862 public void onLauncherTransitionPrepare(Launcher l, boolean animated, boolean toWorkspace) {
Michael Jurkabed61d22012-02-14 22:51:29 -08001863 mIsSwitchingState = true;
Michael Jurka315d38e2013-03-07 13:15:10 +01001864 updateChildrenLayersEnabled(false);
Michael Jurkabed61d22012-02-14 22:51:29 -08001865 }
1866
1867 @Override
Michael Jurkaa35e35a2012-04-26 15:04:28 -07001868 public void onLauncherTransitionStart(Launcher l, boolean animated, boolean toWorkspace) {
1869 }
1870
1871 @Override
Winson Chung70442722012-02-10 15:43:22 -08001872 public void onLauncherTransitionStep(Launcher l, float t) {
1873 mTransitionProgress = t;
1874 }
1875
1876 @Override
Michael Jurkabed61d22012-02-14 22:51:29 -08001877 public void onLauncherTransitionEnd(Launcher l, boolean animated, boolean toWorkspace) {
1878 mIsSwitchingState = false;
Michael Jurka3a0469d2012-06-21 09:38:41 -07001879 updateChildrenLayersEnabled(false);
Michael Jurkabed61d22012-02-14 22:51:29 -08001880 // The code in getChangeStateAnimation to determine initialAlpha and finalAlpha will ensure
1881 // ensure that only the current page is visible during (and subsequently, after) the
1882 // transition animation. If fade adjacent pages is disabled, then re-enable the page
1883 // visibility after the transition animation.
Michael Jurka869390b2012-05-06 15:55:19 -07001884 if (!mWorkspaceFadeInAdjacentScreens) {
Michael Jurkabed61d22012-02-14 22:51:29 -08001885 for (int i = 0; i < getChildCount(); i++) {
1886 final CellLayout cl = (CellLayout) getChildAt(i);
Michael Jurkaa52570f2012-03-20 03:18:20 -07001887 cl.setShortcutAndWidgetAlpha(1f);
Michael Jurkabed61d22012-02-14 22:51:29 -08001888 }
1889 }
1890 }
1891
1892 @Override
1893 public View getContent() {
1894 return this;
1895 }
1896
Joe Onorato4be866d2010-10-10 11:26:02 -07001897 /**
1898 * Draw the View v into the given Canvas.
1899 *
1900 * @param v the view to draw
1901 * @param destCanvas the canvas to draw on
1902 * @param padding the horizontal and vertical padding to use when drawing
1903 */
Adam Cohenac8c8762011-07-13 11:15:27 -07001904 private void drawDragView(View v, Canvas destCanvas, int padding, boolean pruneToDrawable) {
Joe Onorato4be866d2010-10-10 11:26:02 -07001905 final Rect clipRect = mTempRect;
1906 v.getDrawingRect(clipRect);
1907
Adam Cohen099f60d2011-08-23 21:07:26 -07001908 boolean textVisible = false;
1909
Adam Cohenac8c8762011-07-13 11:15:27 -07001910 destCanvas.save();
1911 if (v instanceof TextView && pruneToDrawable) {
1912 Drawable d = ((TextView) v).getCompoundDrawables()[1];
1913 clipRect.set(0, 0, d.getIntrinsicWidth() + padding, d.getIntrinsicHeight() + padding);
1914 destCanvas.translate(padding / 2, padding / 2);
1915 d.draw(destCanvas);
1916 } else {
1917 if (v instanceof FolderIcon) {
Adam Cohen099f60d2011-08-23 21:07:26 -07001918 // For FolderIcons the text can bleed into the icon area, and so we need to
1919 // hide the text completely (which can't be achieved by clipping).
1920 if (((FolderIcon) v).getTextVisible()) {
1921 ((FolderIcon) v).setTextVisible(false);
1922 textVisible = true;
1923 }
Adam Cohenac8c8762011-07-13 11:15:27 -07001924 } else if (v instanceof BubbleTextView) {
1925 final BubbleTextView tv = (BubbleTextView) v;
1926 clipRect.bottom = tv.getExtendedPaddingTop() - (int) BubbleTextView.PADDING_V +
1927 tv.getLayout().getLineTop(0);
1928 } else if (v instanceof TextView) {
1929 final TextView tv = (TextView) v;
1930 clipRect.bottom = tv.getExtendedPaddingTop() - tv.getCompoundDrawablePadding() +
1931 tv.getLayout().getLineTop(0);
1932 }
1933 destCanvas.translate(-v.getScrollX() + padding / 2, -v.getScrollY() + padding / 2);
1934 destCanvas.clipRect(clipRect, Op.REPLACE);
1935 v.draw(destCanvas);
Adam Cohen099f60d2011-08-23 21:07:26 -07001936
1937 // Restore text visibility of FolderIcon if necessary
1938 if (textVisible) {
1939 ((FolderIcon) v).setTextVisible(true);
1940 }
Adam Cohenac8c8762011-07-13 11:15:27 -07001941 }
1942 destCanvas.restore();
1943 }
1944
1945 /**
1946 * Returns a new bitmap to show when the given View is being dragged around.
1947 * Responsibility for the bitmap is transferred to the caller.
1948 */
1949 public Bitmap createDragBitmap(View v, Canvas canvas, int padding) {
Adam Cohenac8c8762011-07-13 11:15:27 -07001950 Bitmap b;
1951
1952 if (v instanceof TextView) {
1953 Drawable d = ((TextView) v).getCompoundDrawables()[1];
1954 b = Bitmap.createBitmap(d.getIntrinsicWidth() + padding,
1955 d.getIntrinsicHeight() + padding, Bitmap.Config.ARGB_8888);
1956 } else {
1957 b = Bitmap.createBitmap(
1958 v.getWidth() + padding, v.getHeight() + padding, Bitmap.Config.ARGB_8888);
Joe Onorato4be866d2010-10-10 11:26:02 -07001959 }
1960
Adam Cohenac8c8762011-07-13 11:15:27 -07001961 canvas.setBitmap(b);
1962 drawDragView(v, canvas, padding, true);
Adam Cohenaaf473c2011-08-03 12:02:47 -07001963 canvas.setBitmap(null);
Joe Onorato4be866d2010-10-10 11:26:02 -07001964
Adam Cohenac8c8762011-07-13 11:15:27 -07001965 return b;
Joe Onorato4be866d2010-10-10 11:26:02 -07001966 }
1967
1968 /**
1969 * Returns a new bitmap to be used as the object outline, e.g. to visualize the drop location.
1970 * Responsibility for the bitmap is transferred to the caller.
1971 */
1972 private Bitmap createDragOutline(View v, Canvas canvas, int padding) {
Winson Chungea359c62011-08-03 17:06:35 -07001973 final int outlineColor = getResources().getColor(android.R.color.holo_blue_light);
Joe Onorato4be866d2010-10-10 11:26:02 -07001974 final Bitmap b = Bitmap.createBitmap(
1975 v.getWidth() + padding, v.getHeight() + padding, Bitmap.Config.ARGB_8888);
1976
1977 canvas.setBitmap(b);
Winson Chungb8c69f32011-10-19 21:36:08 -07001978 drawDragView(v, canvas, padding, true);
Adam Cohen5bb50bd2010-12-03 11:39:55 -08001979 mOutlineHelper.applyMediumExpensiveOutlineWithBlur(b, canvas, outlineColor, outlineColor);
Adam Cohenaaf473c2011-08-03 12:02:47 -07001980 canvas.setBitmap(null);
Joe Onorato4be866d2010-10-10 11:26:02 -07001981 return b;
1982 }
1983
1984 /**
Michael Jurkad3ef3062010-11-23 16:23:58 -08001985 * Returns a new bitmap to be used as the object outline, e.g. to visualize the drop location.
1986 * Responsibility for the bitmap is transferred to the caller.
1987 */
Peter Ng8db70002011-10-25 15:40:08 -07001988 private Bitmap createDragOutline(Bitmap orig, Canvas canvas, int padding, int w, int h,
Michael Jurka8c3339b2012-06-14 16:18:21 -07001989 boolean clipAlpha) {
Winson Chungea359c62011-08-03 17:06:35 -07001990 final int outlineColor = getResources().getColor(android.R.color.holo_blue_light);
Michael Jurkaf12c75c2011-01-25 22:41:40 -08001991 final Bitmap b = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
Michael Jurkad3ef3062010-11-23 16:23:58 -08001992 canvas.setBitmap(b);
Michael Jurkaf12c75c2011-01-25 22:41:40 -08001993
1994 Rect src = new Rect(0, 0, orig.getWidth(), orig.getHeight());
1995 float scaleFactor = Math.min((w - padding) / (float) orig.getWidth(),
1996 (h - padding) / (float) orig.getHeight());
1997 int scaledWidth = (int) (scaleFactor * orig.getWidth());
1998 int scaledHeight = (int) (scaleFactor * orig.getHeight());
1999 Rect dst = new Rect(0, 0, scaledWidth, scaledHeight);
2000
2001 // center the image
2002 dst.offset((w - scaledWidth) / 2, (h - scaledHeight) / 2);
2003
Winson Chung1120e032011-11-22 16:11:31 -08002004 canvas.drawBitmap(orig, src, dst, null);
Peter Ng8db70002011-10-25 15:40:08 -07002005 mOutlineHelper.applyMediumExpensiveOutlineWithBlur(b, canvas, outlineColor, outlineColor,
Michael Jurka8c3339b2012-06-14 16:18:21 -07002006 clipAlpha);
Adam Cohenaaf473c2011-08-03 12:02:47 -07002007 canvas.setBitmap(null);
Michael Jurkad3ef3062010-11-23 16:23:58 -08002008
2009 return b;
2010 }
2011
The Android Open Source Project31dd5032009-03-03 19:32:27 -08002012 void startDrag(CellLayout.CellInfo cellInfo) {
2013 View child = cellInfo.cell;
Winson Chungaafa03c2010-06-11 17:34:16 -07002014
The Android Open Source Project31dd5032009-03-03 19:32:27 -08002015 // Make sure the drag was started by a long press as opposed to a long click.
Bjorn Bringert7984c942009-12-09 15:38:25 +00002016 if (!child.isInTouchMode()) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -08002017 return;
2018 }
Winson Chungaafa03c2010-06-11 17:34:16 -07002019
The Android Open Source Project31dd5032009-03-03 19:32:27 -08002020 mDragInfo = cellInfo;
Adam Cohend41fbf52012-02-16 23:53:59 -08002021 child.setVisibility(INVISIBLE);
Adam Cohen482ed822012-03-02 14:15:13 -08002022 CellLayout layout = (CellLayout) child.getParent().getParent();
2023 layout.prepareChildForDrag(child);
Joe Onorato4be866d2010-10-10 11:26:02 -07002024
2025 child.clearFocus();
2026 child.setPressed(false);
2027
2028 final Canvas canvas = new Canvas();
2029
2030 // The outline is used to visualize where the item will land if dropped
Adam Cohend41fbf52012-02-16 23:53:59 -08002031 mDragOutline = createDragOutline(child, canvas, DRAG_BITMAP_PADDING);
Adam Cohenac8c8762011-07-13 11:15:27 -07002032 beginDragShared(child, this);
2033 }
2034
2035 public void beginDragShared(View child, DragSource source) {
Joe Onorato4be866d2010-10-10 11:26:02 -07002036 // The drag bitmap follows the touch point around on the screen
Adam Cohend41fbf52012-02-16 23:53:59 -08002037 final Bitmap b = createDragBitmap(child, new Canvas(), DRAG_BITMAP_PADDING);
Joe Onorato4be866d2010-10-10 11:26:02 -07002038
2039 final int bmpWidth = b.getWidth();
Winson Chungeecf02d2012-03-02 17:14:58 -08002040 final int bmpHeight = b.getHeight();
Adam Cohene3e27a82011-04-15 12:07:39 -07002041
Adam Cohen307fe232012-08-16 17:55:58 -07002042 float scale = mLauncher.getDragLayer().getLocationInDragLayer(child, mTempXY);
Winson Chungeecf02d2012-03-02 17:14:58 -08002043 int dragLayerX =
Adam Cohen307fe232012-08-16 17:55:58 -07002044 Math.round(mTempXY[0] - (bmpWidth - scale * child.getWidth()) / 2);
Winson Chungeecf02d2012-03-02 17:14:58 -08002045 int dragLayerY =
Adam Cohen307fe232012-08-16 17:55:58 -07002046 Math.round(mTempXY[1] - (bmpHeight - scale * bmpHeight) / 2
Winson Chungeecf02d2012-03-02 17:14:58 -08002047 - DRAG_BITMAP_PADDING / 2);
Adam Cohene3e27a82011-04-15 12:07:39 -07002048
Winson Chung5f8afe62013-08-12 16:19:28 -07002049 LauncherAppState app = LauncherAppState.getInstance();
2050 DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
Winson Chungb8c69f32011-10-19 21:36:08 -07002051 Point dragVisualizeOffset = null;
Adam Cohene3e27a82011-04-15 12:07:39 -07002052 Rect dragRect = null;
Winson Chungb8c69f32011-10-19 21:36:08 -07002053 if (child instanceof BubbleTextView || child instanceof PagedViewIcon) {
Winson Chung5f8afe62013-08-12 16:19:28 -07002054 int iconSize = grid.iconSizePx;
Adam Cohene3e27a82011-04-15 12:07:39 -07002055 int top = child.getPaddingTop();
2056 int left = (bmpWidth - iconSize) / 2;
2057 int right = left + iconSize;
2058 int bottom = top + iconSize;
Adam Cohenfc53cd22011-07-20 15:45:11 -07002059 dragLayerY += top;
Winson Chungb8c69f32011-10-19 21:36:08 -07002060 // Note: The drag region is used to calculate drag layer offsets, but the
2061 // dragVisualizeOffset in addition to the dragRect (the size) to position the outline.
Winson Chung5f8afe62013-08-12 16:19:28 -07002062 dragVisualizeOffset = new Point(-DRAG_BITMAP_PADDING / 2, DRAG_BITMAP_PADDING / 2);
Adam Cohene3e27a82011-04-15 12:07:39 -07002063 dragRect = new Rect(left, top, right, bottom);
Adam Cohen0e4857c2011-06-30 17:05:14 -07002064 } else if (child instanceof FolderIcon) {
Winson Chung5f8afe62013-08-12 16:19:28 -07002065 int previewSize = grid.folderIconSizePx;
2066 dragRect = new Rect(0, child.getPaddingTop(), child.getWidth(), previewSize);
Adam Cohene3e27a82011-04-15 12:07:39 -07002067 }
2068
Winson Chung1e9cbfe2011-09-30 16:52:26 -07002069 // Clear the pressed state if necessary
2070 if (child instanceof BubbleTextView) {
2071 BubbleTextView icon = (BubbleTextView) child;
2072 icon.clearPressedOrFocusedBackground();
2073 }
2074
Adam Cohenac8c8762011-07-13 11:15:27 -07002075 mDragController.startDrag(b, dragLayerX, dragLayerY, source, child.getTag(),
Adam Cohen307fe232012-08-16 17:55:58 -07002076 DragController.DRAG_ACTION_MOVE, dragVisualizeOffset, dragRect, scale);
Joe Onorato4be866d2010-10-10 11:26:02 -07002077 b.recycle();
The Android Open Source Project31dd5032009-03-03 19:32:27 -08002078 }
2079
Adam Cohendcd297f2013-06-18 13:13:40 -07002080 void addApplicationShortcut(ShortcutInfo info, CellLayout target, long container, long screenId,
Winson Chung3d503fb2011-07-13 17:25:49 -07002081 int cellX, int cellY, boolean insertAtFirst, int intersectX, int intersectY) {
2082 View view = mLauncher.createShortcut(R.layout.application, target, (ShortcutInfo) info);
Michael Jurka0280c3b2010-09-17 15:00:07 -07002083
2084 final int[] cellXY = new int[2];
Winson Chung3d503fb2011-07-13 17:25:49 -07002085 target.findCellForSpanThatIntersects(cellXY, 1, 1, intersectX, intersectY);
Adam Cohendcd297f2013-06-18 13:13:40 -07002086 addInScreen(view, container, screenId, cellXY[0], cellXY[1], 1, 1, insertAtFirst);
Adam Cohen7c4c5102013-06-14 17:42:35 -07002087
Adam Cohendcd297f2013-06-18 13:13:40 -07002088 LauncherModel.addOrMoveItemInDatabase(mLauncher, info, container, screenId, cellXY[0],
Winson Chung3d503fb2011-07-13 17:25:49 -07002089 cellXY[1]);
The Android Open Source Project31dd5032009-03-03 19:32:27 -08002090 }
2091
Adam Cohen4b285c52011-07-21 14:24:06 -07002092 public boolean transitionStateShouldAllowDrop() {
Adam Cohen1b36dc32012-02-13 19:27:37 -08002093 return ((!isSwitchingState() || mTransitionProgress > 0.5f) && mState != State.SMALL);
Adam Cohen4b285c52011-07-21 14:24:06 -07002094 }
2095
Patrick Dubroycd68ff52010-10-28 17:57:05 -07002096 /**
2097 * {@inheritDoc}
2098 */
Adam Cohencb3382b2011-05-24 14:07:08 -07002099 public boolean acceptDrop(DragObject d) {
Patrick Dubroycd68ff52010-10-28 17:57:05 -07002100 // If it's an external drop (e.g. from All Apps), check if it should be accepted
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002101 CellLayout dropTargetLayout = mDropToLayout;
Adam Cohencb3382b2011-05-24 14:07:08 -07002102 if (d.dragSource != this) {
Patrick Dubroycd68ff52010-10-28 17:57:05 -07002103 // Don't accept the drop if we're not over a screen at time of drop
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002104 if (dropTargetLayout == null) {
Patrick Dubroycd68ff52010-10-28 17:57:05 -07002105 return false;
2106 }
Adam Cohen4b285c52011-07-21 14:24:06 -07002107 if (!transitionStateShouldAllowDrop()) return false;
Patrick Dubroycd68ff52010-10-28 17:57:05 -07002108
Adam Cohena65beee2011-06-27 21:32:23 -07002109 mDragViewVisualCenter = getDragViewVisualCenter(d.x, d.y, d.xOffset, d.yOffset,
2110 d.dragView, mDragViewVisualCenter);
2111
Adam Cohen2e9f4fb2011-08-30 22:46:55 -07002112 // We want the point to be mapped to the dragTarget.
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002113 if (mLauncher.isHotseatLayout(dropTargetLayout)) {
Adam Cohen307fe232012-08-16 17:55:58 -07002114 mapPointFromSelfToHotseatLayout(mLauncher.getHotseat(), mDragViewVisualCenter);
Adam Cohen2e9f4fb2011-08-30 22:46:55 -07002115 } else {
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002116 mapPointFromSelfToChild(dropTargetLayout, mDragViewVisualCenter, null);
Adam Cohen2e9f4fb2011-08-30 22:46:55 -07002117 }
2118
Winson Chung557d6ed2011-07-08 15:34:52 -07002119 int spanX = 1;
2120 int spanY = 1;
Winson Chung557d6ed2011-07-08 15:34:52 -07002121 if (mDragInfo != null) {
2122 final CellLayout.CellInfo dragCellInfo = mDragInfo;
2123 spanX = dragCellInfo.spanX;
2124 spanY = dragCellInfo.spanY;
Winson Chung557d6ed2011-07-08 15:34:52 -07002125 } else {
2126 final ItemInfo dragInfo = (ItemInfo) d.dragInfo;
2127 spanX = dragInfo.spanX;
2128 spanY = dragInfo.spanY;
2129 }
Patrick Dubroycd68ff52010-10-28 17:57:05 -07002130
Adam Cohend41fbf52012-02-16 23:53:59 -08002131 int minSpanX = spanX;
2132 int minSpanY = spanY;
2133 if (d.dragInfo instanceof PendingAddWidgetInfo) {
2134 minSpanX = ((PendingAddWidgetInfo) d.dragInfo).minSpanX;
2135 minSpanY = ((PendingAddWidgetInfo) d.dragInfo).minSpanY;
2136 }
Adam Cohen482ed822012-03-02 14:15:13 -08002137
Adam Cohena65beee2011-06-27 21:32:23 -07002138 mTargetCell = findNearestArea((int) mDragViewVisualCenter[0],
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002139 (int) mDragViewVisualCenter[1], minSpanX, minSpanY, dropTargetLayout,
Adam Cohenf0777b92012-02-28 14:02:45 -08002140 mTargetCell);
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002141 float distance = dropTargetLayout.getDistanceFromCell(mDragViewVisualCenter[0],
Adam Cohen482ed822012-03-02 14:15:13 -08002142 mDragViewVisualCenter[1], mTargetCell);
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002143 if (willCreateUserFolder((ItemInfo) d.dragInfo, dropTargetLayout,
Adam Cohen482ed822012-03-02 14:15:13 -08002144 mTargetCell, distance, true)) {
Adam Cohena65beee2011-06-27 21:32:23 -07002145 return true;
2146 }
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002147 if (willAddToExistingUserFolder((ItemInfo) d.dragInfo, dropTargetLayout,
Adam Cohen482ed822012-03-02 14:15:13 -08002148 mTargetCell, distance)) {
Adam Cohena65beee2011-06-27 21:32:23 -07002149 return true;
2150 }
2151
Adam Cohen482ed822012-03-02 14:15:13 -08002152 int[] resultSpan = new int[2];
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002153 mTargetCell = dropTargetLayout.createArea((int) mDragViewVisualCenter[0],
Adam Cohen482ed822012-03-02 14:15:13 -08002154 (int) mDragViewVisualCenter[1], minSpanX, minSpanY, spanX, spanY,
2155 null, mTargetCell, resultSpan, CellLayout.MODE_ACCEPT_DROP);
2156 boolean foundCell = mTargetCell[0] >= 0 && mTargetCell[1] >= 0;
2157
Patrick Dubroycd68ff52010-10-28 17:57:05 -07002158 // Don't accept the drop if there's no room for the item
Adam Cohen482ed822012-03-02 14:15:13 -08002159 if (!foundCell) {
Winson Chung96ef4092011-11-22 12:25:14 -08002160 // Don't show the message if we are dropping on the AllApps button and the hotseat
2161 // is full
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002162 boolean isHotseat = mLauncher.isHotseatLayout(dropTargetLayout);
Winson Chung93eef082012-03-23 15:59:27 -07002163 if (mTargetCell != null && isHotseat) {
Winson Chung96ef4092011-11-22 12:25:14 -08002164 Hotseat hotseat = mLauncher.getHotseat();
Andrew Flynn0dca1ec2012-02-29 13:33:22 -08002165 if (hotseat.isAllAppsButtonRank(
Winson Chung96ef4092011-11-22 12:25:14 -08002166 hotseat.getOrderInHotseat(mTargetCell[0], mTargetCell[1]))) {
2167 return false;
2168 }
2169 }
2170
Winson Chung93eef082012-03-23 15:59:27 -07002171 mLauncher.showOutOfSpaceMessage(isHotseat);
Patrick Dubroycd68ff52010-10-28 17:57:05 -07002172 return false;
2173 }
2174 }
Adam Cohendedbd962013-07-11 14:21:49 -07002175
2176 long screenId = getIdForScreen(dropTargetLayout);
2177 if (screenId == EXTRA_EMPTY_SCREEN_ID) {
2178 commitExtraEmptyScreen();
2179 }
2180
Patrick Dubroycd68ff52010-10-28 17:57:05 -07002181 return true;
2182 }
2183
Adam Cohen482ed822012-03-02 14:15:13 -08002184 boolean willCreateUserFolder(ItemInfo info, CellLayout target, int[] targetCell, float
2185 distance, boolean considerTimeout) {
2186 if (distance > mMaxDistanceForFolderCreation) return false;
Adam Cohena65beee2011-06-27 21:32:23 -07002187 View dropOverView = target.getChildAt(targetCell[0], targetCell[1]);
2188
Adam Cohen19f37922012-03-21 11:59:11 -07002189 if (dropOverView != null) {
2190 CellLayout.LayoutParams lp = (CellLayout.LayoutParams) dropOverView.getLayoutParams();
2191 if (lp.useTmpCoords && (lp.tmpCellX != lp.cellX || lp.tmpCellY != lp.tmpCellY)) {
2192 return false;
2193 }
2194 }
2195
Winson Chung3d503fb2011-07-13 17:25:49 -07002196 boolean hasntMoved = false;
2197 if (mDragInfo != null) {
Adam Cohen482ed822012-03-02 14:15:13 -08002198 hasntMoved = dropOverView == mDragInfo.cell;
Winson Chung3d503fb2011-07-13 17:25:49 -07002199 }
Adam Cohene0310962011-04-18 16:15:31 -07002200
Adam Cohena65beee2011-06-27 21:32:23 -07002201 if (dropOverView == null || hasntMoved || (considerTimeout && !mCreateUserFolderOnDrop)) {
2202 return false;
2203 }
Adam Cohene0310962011-04-18 16:15:31 -07002204
Adam Cohena65beee2011-06-27 21:32:23 -07002205 boolean aboveShortcut = (dropOverView.getTag() instanceof ShortcutInfo);
Adam Cohene0310962011-04-18 16:15:31 -07002206 boolean willBecomeShortcut =
Adam Cohenc0dcf592011-06-01 15:30:43 -07002207 (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
2208 info.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT);
Adam Cohene0310962011-04-18 16:15:31 -07002209
2210 return (aboveShortcut && willBecomeShortcut);
2211 }
2212
Adam Cohen482ed822012-03-02 14:15:13 -08002213 boolean willAddToExistingUserFolder(Object dragInfo, CellLayout target, int[] targetCell,
2214 float distance) {
2215 if (distance > mMaxDistanceForFolderCreation) return false;
Adam Cohena65beee2011-06-27 21:32:23 -07002216 View dropOverView = target.getChildAt(targetCell[0], targetCell[1]);
Adam Cohen19f37922012-03-21 11:59:11 -07002217
2218 if (dropOverView != null) {
2219 CellLayout.LayoutParams lp = (CellLayout.LayoutParams) dropOverView.getLayoutParams();
2220 if (lp.useTmpCoords && (lp.tmpCellX != lp.cellX || lp.tmpCellY != lp.tmpCellY)) {
2221 return false;
2222 }
2223 }
2224
Adam Cohena65beee2011-06-27 21:32:23 -07002225 if (dropOverView instanceof FolderIcon) {
2226 FolderIcon fi = (FolderIcon) dropOverView;
2227 if (fi.acceptDrop(dragInfo)) {
2228 return true;
2229 }
2230 }
2231 return false;
2232 }
2233
Winson Chung3d503fb2011-07-13 17:25:49 -07002234 boolean createUserFolderIfNecessary(View newView, long container, CellLayout target,
Adam Cohen482ed822012-03-02 14:15:13 -08002235 int[] targetCell, float distance, boolean external, DragView dragView,
2236 Runnable postAnimationRunnable) {
2237 if (distance > mMaxDistanceForFolderCreation) return false;
Adam Cohenc0dcf592011-06-01 15:30:43 -07002238 View v = target.getChildAt(targetCell[0], targetCell[1]);
Adam Cohen19f37922012-03-21 11:59:11 -07002239
Winson Chungec9a0a42011-07-20 20:42:13 -07002240 boolean hasntMoved = false;
2241 if (mDragInfo != null) {
2242 CellLayout cellParent = getParentCellLayoutForView(mDragInfo.cell);
2243 hasntMoved = (mDragInfo.cellX == targetCell[0] &&
2244 mDragInfo.cellY == targetCell[1]) && (cellParent == target);
2245 }
Adam Cohen10b17372011-04-15 14:21:25 -07002246
Adam Cohen19072da2011-05-31 14:30:45 -07002247 if (v == null || hasntMoved || !mCreateUserFolderOnDrop) return false;
2248 mCreateUserFolderOnDrop = false;
Adam Cohendcd297f2013-06-18 13:13:40 -07002249 final long screenId = (targetCell == null) ? mDragInfo.screenId : getIdForScreen(target);
Adam Cohen10b17372011-04-15 14:21:25 -07002250
2251 boolean aboveShortcut = (v.getTag() instanceof ShortcutInfo);
2252 boolean willBecomeShortcut = (newView.getTag() instanceof ShortcutInfo);
2253
2254 if (aboveShortcut && willBecomeShortcut) {
2255 ShortcutInfo sourceInfo = (ShortcutInfo) newView.getTag();
2256 ShortcutInfo destInfo = (ShortcutInfo) v.getTag();
2257 // if the drag started here, we need to remove it from the workspace
2258 if (!external) {
Winson Chung3d503fb2011-07-13 17:25:49 -07002259 getParentCellLayoutForView(mDragInfo.cell).removeView(mDragInfo.cell);
Adam Cohen10b17372011-04-15 14:21:25 -07002260 }
2261
Adam Cohend0445262011-07-04 23:53:22 -07002262 Rect folderLocation = new Rect();
Adam Cohenac8c8762011-07-13 11:15:27 -07002263 float scale = mLauncher.getDragLayer().getDescendantRectRelativeToSelf(v, folderLocation);
Adam Cohen10b17372011-04-15 14:21:25 -07002264 target.removeView(v);
Adam Cohend0445262011-07-04 23:53:22 -07002265
Winson Chung3d503fb2011-07-13 17:25:49 -07002266 FolderIcon fi =
Adam Cohendcd297f2013-06-18 13:13:40 -07002267 mLauncher.addFolder(target, container, screenId, targetCell[0], targetCell[1]);
Adam Cohena9cf38f2011-05-02 15:36:58 -07002268 destInfo.cellX = -1;
2269 destInfo.cellY = -1;
2270 sourceInfo.cellX = -1;
2271 sourceInfo.cellY = -1;
Adam Cohend0445262011-07-04 23:53:22 -07002272
Adam Cohen558baaf2011-08-15 15:22:57 -07002273 // If the dragView is null, we can't animate
2274 boolean animate = dragView != null;
2275 if (animate) {
2276 fi.performCreateAnimation(destInfo, v, sourceInfo, dragView, folderLocation, scale,
2277 postAnimationRunnable);
2278 } else {
2279 fi.addItem(destInfo);
2280 fi.addItem(sourceInfo);
2281 }
Adam Cohen10b17372011-04-15 14:21:25 -07002282 return true;
2283 }
2284 return false;
2285 }
2286
Adam Cohena65beee2011-06-27 21:32:23 -07002287 boolean addToExistingFolderIfNecessary(View newView, CellLayout target, int[] targetCell,
Adam Cohen482ed822012-03-02 14:15:13 -08002288 float distance, DragObject d, boolean external) {
2289 if (distance > mMaxDistanceForFolderCreation) return false;
2290
Adam Cohena65beee2011-06-27 21:32:23 -07002291 View dropOverView = target.getChildAt(targetCell[0], targetCell[1]);
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002292 if (!mAddToExistingFolderOnDrop) return false;
2293 mAddToExistingFolderOnDrop = false;
Adam Cohen19f37922012-03-21 11:59:11 -07002294
Adam Cohenc0dcf592011-06-01 15:30:43 -07002295 if (dropOverView instanceof FolderIcon) {
2296 FolderIcon fi = (FolderIcon) dropOverView;
Adam Cohen3e8f8112011-07-02 18:03:00 -07002297 if (fi.acceptDrop(d.dragInfo)) {
2298 fi.onDrop(d);
Adam Cohenc0dcf592011-06-01 15:30:43 -07002299
2300 // if the drag started here, we need to remove it from the workspace
2301 if (!external) {
Winson Chung3d503fb2011-07-13 17:25:49 -07002302 getParentCellLayoutForView(mDragInfo.cell).removeView(mDragInfo.cell);
Adam Cohenc0dcf592011-06-01 15:30:43 -07002303 }
2304 return true;
2305 }
2306 }
2307 return false;
2308 }
2309
Adam Cohend41fbf52012-02-16 23:53:59 -08002310 public void onDrop(final DragObject d) {
Adam Cohencb3382b2011-05-24 14:07:08 -07002311 mDragViewVisualCenter = getDragViewVisualCenter(d.x, d.y, d.xOffset, d.yOffset, d.dragView,
Adam Cohene3e27a82011-04-15 12:07:39 -07002312 mDragViewVisualCenter);
2313
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002314 CellLayout dropTargetLayout = mDropToLayout;
2315
Adam Cohene3e27a82011-04-15 12:07:39 -07002316 // We want the point to be mapped to the dragTarget.
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002317 if (dropTargetLayout != null) {
2318 if (mLauncher.isHotseatLayout(dropTargetLayout)) {
Adam Cohenbb00ff22012-07-12 15:43:01 -07002319 mapPointFromSelfToHotseatLayout(mLauncher.getHotseat(), mDragViewVisualCenter);
Winson Chung3d503fb2011-07-13 17:25:49 -07002320 } else {
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002321 mapPointFromSelfToChild(dropTargetLayout, mDragViewVisualCenter, null);
Winson Chung3d503fb2011-07-13 17:25:49 -07002322 }
Adam Cohenba781612011-05-09 14:37:39 -07002323 }
Michael Jurkac6ee42e2010-09-30 12:04:50 -07002324
Adam Cohened51cc92011-08-01 20:28:08 -07002325 int snapScreen = -1;
Adam Cohend41fbf52012-02-16 23:53:59 -08002326 boolean resizeOnDrop = false;
Adam Cohencb3382b2011-05-24 14:07:08 -07002327 if (d.dragSource != this) {
Adam Cohene3e27a82011-04-15 12:07:39 -07002328 final int[] touchXY = new int[] { (int) mDragViewVisualCenter[0],
2329 (int) mDragViewVisualCenter[1] };
Adam Cohen3e8f8112011-07-02 18:03:00 -07002330 onDropExternal(touchXY, d.dragInfo, dropTargetLayout, false, d);
Patrick Dubroyce34a972010-10-19 10:34:32 -07002331 } else if (mDragInfo != null) {
Patrick Dubroyce34a972010-10-19 10:34:32 -07002332 final View cell = mDragInfo.cell;
Patrick Dubroy54fa3b92010-11-17 12:18:45 -08002333
Adam Cohend41fbf52012-02-16 23:53:59 -08002334 Runnable resizeRunnable = null;
Michael Jurka1e2f4652013-07-08 18:03:46 -07002335 if (dropTargetLayout != null && !d.cancelled) {
Winson Chung3d503fb2011-07-13 17:25:49 -07002336 // Move internally
Winson Chung40e882b2011-07-21 19:01:11 -07002337 boolean hasMovedLayouts = (getParentCellLayoutForView(cell) != dropTargetLayout);
2338 boolean hasMovedIntoHotseat = mLauncher.isHotseatLayout(dropTargetLayout);
2339 long container = hasMovedIntoHotseat ?
Winson Chung3d503fb2011-07-13 17:25:49 -07002340 LauncherSettings.Favorites.CONTAINER_HOTSEAT :
2341 LauncherSettings.Favorites.CONTAINER_DESKTOP;
Adam Cohendcd297f2013-06-18 13:13:40 -07002342 long screenId = (mTargetCell[0] < 0) ?
2343 mDragInfo.screenId : getIdForScreen(dropTargetLayout);
Adam Cohenc0dcf592011-06-01 15:30:43 -07002344 int spanX = mDragInfo != null ? mDragInfo.spanX : 1;
2345 int spanY = mDragInfo != null ? mDragInfo.spanY : 1;
2346 // First we find the cell nearest to point at which the item is
2347 // dropped, without any consideration to whether there is an item there.
Adam Cohen482ed822012-03-02 14:15:13 -08002348
Adam Cohenc0dcf592011-06-01 15:30:43 -07002349 mTargetCell = findNearestArea((int) mDragViewVisualCenter[0], (int)
2350 mDragViewVisualCenter[1], spanX, spanY, dropTargetLayout, mTargetCell);
Adam Cohen482ed822012-03-02 14:15:13 -08002351 float distance = dropTargetLayout.getDistanceFromCell(mDragViewVisualCenter[0],
2352 mDragViewVisualCenter[1], mTargetCell);
2353
Adam Cohenc0dcf592011-06-01 15:30:43 -07002354 // If the item being dropped is a shortcut and the nearest drop
Adam Cohen76078c42011-06-09 15:06:52 -07002355 // cell also contains a shortcut, then create a folder with the two shortcuts.
Winson Chung1c4cf4a2011-07-29 14:49:10 -07002356 if (!mInScrollArea && createUserFolderIfNecessary(cell, container,
Adam Cohen482ed822012-03-02 14:15:13 -08002357 dropTargetLayout, mTargetCell, distance, false, d.dragView, null)) {
Winson Chungd2be3812013-07-16 11:11:32 -07002358 stripEmptyScreens();
Adam Cohenc0dcf592011-06-01 15:30:43 -07002359 return;
2360 }
2361
Adam Cohen482ed822012-03-02 14:15:13 -08002362 if (addToExistingFolderIfNecessary(cell, dropTargetLayout, mTargetCell,
2363 distance, d, false)) {
Winson Chungd2be3812013-07-16 11:11:32 -07002364 stripEmptyScreens();
Adam Cohendf035382011-04-11 17:22:04 -07002365 return;
2366 }
2367
2368 // Aside from the special case where we're dropping a shortcut onto a shortcut,
2369 // we need to find the nearest cell location that is vacant
Adam Cohend41fbf52012-02-16 23:53:59 -08002370 ItemInfo item = (ItemInfo) d.dragInfo;
2371 int minSpanX = item.spanX;
2372 int minSpanY = item.spanY;
2373 if (item.minSpanX > 0 && item.minSpanY > 0) {
2374 minSpanX = item.minSpanX;
2375 minSpanY = item.minSpanY;
2376 }
Adam Cohen482ed822012-03-02 14:15:13 -08002377
Adam Cohend41fbf52012-02-16 23:53:59 -08002378 int[] resultSpan = new int[2];
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002379 mTargetCell = dropTargetLayout.createArea((int) mDragViewVisualCenter[0],
Adam Cohen482ed822012-03-02 14:15:13 -08002380 (int) mDragViewVisualCenter[1], minSpanX, minSpanY, spanX, spanY, cell,
2381 mTargetCell, resultSpan, CellLayout.MODE_ON_DROP);
2382
Adam Cohend41fbf52012-02-16 23:53:59 -08002383 boolean foundCell = mTargetCell[0] >= 0 && mTargetCell[1] >= 0;
Adam Cohen9e05a5e2012-09-10 15:53:09 -07002384
Adam Cohenaaa5c212012-10-05 18:14:31 -07002385 // if the widget resizes on drop
Adam Cohen9e05a5e2012-09-10 15:53:09 -07002386 if (foundCell && (cell instanceof AppWidgetHostView) &&
Adam Cohenaaa5c212012-10-05 18:14:31 -07002387 (resultSpan[0] != item.spanX || resultSpan[1] != item.spanY)) {
Adam Cohend41fbf52012-02-16 23:53:59 -08002388 resizeOnDrop = true;
2389 item.spanX = resultSpan[0];
2390 item.spanY = resultSpan[1];
Adam Cohen7bdfc972012-05-22 16:50:35 -07002391 AppWidgetHostView awhv = (AppWidgetHostView) cell;
2392 AppWidgetResizeFrame.updateWidgetSizeRanges(awhv, mLauncher, resultSpan[0],
2393 resultSpan[1]);
Adam Cohend41fbf52012-02-16 23:53:59 -08002394 }
Adam Cohendf035382011-04-11 17:22:04 -07002395
Adam Cohendcd297f2013-06-18 13:13:40 -07002396 if (getScreenIdForPageIndex(mCurrentPage) != screenId && !hasMovedIntoHotseat) {
2397 snapScreen = getPageIndexForScreenId(screenId);
2398 snapToPage(snapScreen);
Patrick Dubroy54fa3b92010-11-17 12:18:45 -08002399 }
2400
Adam Cohend41fbf52012-02-16 23:53:59 -08002401 if (foundCell) {
2402 final ItemInfo info = (ItemInfo) cell.getTag();
Winson Chung40e882b2011-07-21 19:01:11 -07002403 if (hasMovedLayouts) {
Patrick Dubroy94383362010-10-29 15:03:24 -07002404 // Reparent the view
Winson Chung3d503fb2011-07-13 17:25:49 -07002405 getParentCellLayoutForView(cell).removeView(cell);
Adam Cohendcd297f2013-06-18 13:13:40 -07002406 addInScreen(cell, container, screenId, mTargetCell[0], mTargetCell[1],
Adam Cohend41fbf52012-02-16 23:53:59 -08002407 info.spanX, info.spanY);
Patrick Dubroy94383362010-10-29 15:03:24 -07002408 }
2409
2410 // update the item's position after drop
Patrick Dubroy94383362010-10-29 15:03:24 -07002411 CellLayout.LayoutParams lp = (CellLayout.LayoutParams) cell.getLayoutParams();
Adam Cohen19f37922012-03-21 11:59:11 -07002412 lp.cellX = lp.tmpCellX = mTargetCell[0];
2413 lp.cellY = lp.tmpCellY = mTargetCell[1];
Adam Cohend41fbf52012-02-16 23:53:59 -08002414 lp.cellHSpan = item.spanX;
2415 lp.cellVSpan = item.spanY;
Adam Cohen19f37922012-03-21 11:59:11 -07002416 lp.isLockedToGrid = true;
Adam Cohendcd297f2013-06-18 13:13:40 -07002417 cell.setId(LauncherModel.getCellLayoutChildId(container, mDragInfo.screenId,
Patrick Dubroy94383362010-10-29 15:03:24 -07002418 mTargetCell[0], mTargetCell[1], mDragInfo.spanX, mDragInfo.spanY));
2419
Winson Chung3d503fb2011-07-13 17:25:49 -07002420 if (container != LauncherSettings.Favorites.CONTAINER_HOTSEAT &&
2421 cell instanceof LauncherAppWidgetHostView) {
Adam Cohend4844c32011-02-18 19:25:06 -08002422 final CellLayout cellLayout = dropTargetLayout;
2423 // We post this call so that the widget has a chance to be placed
2424 // in its final location
2425
2426 final LauncherAppWidgetHostView hostView = (LauncherAppWidgetHostView) cell;
2427 AppWidgetProviderInfo pinfo = hostView.getAppWidgetInfo();
Adam Cohenc0a5df92012-04-02 16:53:26 -07002428 if (pinfo != null &&
2429 pinfo.resizeMode != AppWidgetProviderInfo.RESIZE_NONE) {
Adam Cohend41fbf52012-02-16 23:53:59 -08002430 final Runnable addResizeFrame = new Runnable() {
Adam Cohend4844c32011-02-18 19:25:06 -08002431 public void run() {
Adam Cohen716b51e2011-06-30 12:09:54 -07002432 DragLayer dragLayer = mLauncher.getDragLayer();
Adam Cohenc0dcf592011-06-01 15:30:43 -07002433 dragLayer.addResizeFrame(info, hostView, cellLayout);
Adam Cohend4844c32011-02-18 19:25:06 -08002434 }
Adam Cohen26976d92011-03-22 15:33:33 -07002435 };
Adam Cohend41fbf52012-02-16 23:53:59 -08002436 resizeRunnable = (new Runnable() {
Adam Cohen26976d92011-03-22 15:33:33 -07002437 public void run() {
2438 if (!isPageMoving()) {
Adam Cohend41fbf52012-02-16 23:53:59 -08002439 addResizeFrame.run();
Adam Cohen26976d92011-03-22 15:33:33 -07002440 } else {
Adam Cohend41fbf52012-02-16 23:53:59 -08002441 mDelayedResizeRunnable = addResizeFrame;
Adam Cohen26976d92011-03-22 15:33:33 -07002442 }
2443 }
Adam Cohend4844c32011-02-18 19:25:06 -08002444 });
2445 }
2446 }
2447
Adam Cohendcd297f2013-06-18 13:13:40 -07002448 LauncherModel.moveItemInDatabase(mLauncher, info, container, screenId, lp.cellX,
Winson Chung3d503fb2011-07-13 17:25:49 -07002449 lp.cellY);
Adam Cohend41fbf52012-02-16 23:53:59 -08002450 } else {
2451 // If we can't find a drop location, we return the item to its original position
2452 CellLayout.LayoutParams lp = (CellLayout.LayoutParams) cell.getLayoutParams();
2453 mTargetCell[0] = lp.cellX;
2454 mTargetCell[1] = lp.cellY;
Adam Cohenf1dcdf62012-05-10 16:51:52 -07002455 CellLayout layout = (CellLayout) cell.getParent().getParent();
2456 layout.markCellsAsOccupiedForView(cell);
Patrick Dubroycd68ff52010-10-28 17:57:05 -07002457 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -08002458 }
Patrick Dubroyce34a972010-10-19 10:34:32 -07002459
Michael Jurka8c920dd2011-01-20 14:16:56 -08002460 final CellLayout parent = (CellLayout) cell.getParent().getParent();
Adam Cohend41fbf52012-02-16 23:53:59 -08002461 final Runnable finalResizeRunnable = resizeRunnable;
Patrick Dubroyce34a972010-10-19 10:34:32 -07002462 // Prepare it to be animated into its new position
2463 // This must be called after the view has been re-parented
Adam Cohend41fbf52012-02-16 23:53:59 -08002464 final Runnable onCompleteRunnable = new Runnable() {
Michael Jurkad74c9842011-07-10 12:44:21 -07002465 @Override
2466 public void run() {
2467 mAnimatingViewIntoPlace = false;
Michael Jurka3a0469d2012-06-21 09:38:41 -07002468 updateChildrenLayersEnabled(false);
Adam Cohend41fbf52012-02-16 23:53:59 -08002469 if (finalResizeRunnable != null) {
2470 finalResizeRunnable.run();
2471 }
Adam Cohend6e7aa32013-07-09 15:32:37 -07002472 stripEmptyScreens();
Michael Jurkad74c9842011-07-10 12:44:21 -07002473 }
2474 };
2475 mAnimatingViewIntoPlace = true;
Adam Cohenfc53cd22011-07-20 15:45:11 -07002476 if (d.dragView.hasDrawn()) {
Adam Cohend41fbf52012-02-16 23:53:59 -08002477 final ItemInfo info = (ItemInfo) cell.getTag();
2478 if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET) {
2479 int animationType = resizeOnDrop ? ANIMATE_INTO_POSITION_AND_RESIZE :
2480 ANIMATE_INTO_POSITION_AND_DISAPPEAR;
2481 animateWidgetDrop(info, parent, d.dragView,
2482 onCompleteRunnable, animationType, cell, false);
2483 } else {
Adam Cohen85b467b2012-02-29 15:38:46 -08002484 int duration = snapScreen < 0 ? -1 : ADJACENT_SCREEN_DROP_DURATION;
2485 mLauncher.getDragLayer().animateViewIntoPosition(d.dragView, cell, duration,
2486 onCompleteRunnable, this);
Adam Cohend41fbf52012-02-16 23:53:59 -08002487 }
Adam Cohenfc53cd22011-07-20 15:45:11 -07002488 } else {
Winson Chung7bd1bbb2012-02-13 18:29:29 -08002489 d.deferDragViewCleanupPostAnimation = false;
Adam Cohenfc53cd22011-07-20 15:45:11 -07002490 cell.setVisibility(VISIBLE);
2491 }
Adam Cohen716b51e2011-06-30 12:09:54 -07002492 parent.onDropChild(cell);
The Android Open Source Project31dd5032009-03-03 19:32:27 -08002493 }
2494 }
2495
Adam Cohendcd297f2013-06-18 13:13:40 -07002496 public void setFinalScrollForPageChange(int pageIndex) {
2497 CellLayout cl = (CellLayout) getChildAt(pageIndex);
2498 if (cl != null) {
Adam Cohened51cc92011-08-01 20:28:08 -07002499 mSavedScrollX = getScrollX();
Adam Cohened51cc92011-08-01 20:28:08 -07002500 mSavedTranslationX = cl.getTranslationX();
2501 mSavedRotationY = cl.getRotationY();
Adam Cohenedb40762013-07-18 16:45:45 -07002502 final int newX = getScrollForPage(pageIndex);
Adam Cohened51cc92011-08-01 20:28:08 -07002503 setScrollX(newX);
2504 cl.setTranslationX(0f);
2505 cl.setRotationY(0f);
2506 }
2507 }
2508
Adam Cohendcd297f2013-06-18 13:13:40 -07002509 public void resetFinalScrollForPageChange(int pageIndex) {
2510 if (pageIndex >= 0) {
2511 CellLayout cl = (CellLayout) getChildAt(pageIndex);
Adam Cohened51cc92011-08-01 20:28:08 -07002512 setScrollX(mSavedScrollX);
2513 cl.setTranslationX(mSavedTranslationX);
2514 cl.setRotationY(mSavedRotationY);
2515 }
2516 }
2517
Adam Cohen76078c42011-06-09 15:06:52 -07002518 public void getViewLocationRelativeToSelf(View v, int[] location) {
Adam Cohen8dfcba42011-07-07 16:38:18 -07002519 getLocationInWindow(location);
Adam Cohene3e27a82011-04-15 12:07:39 -07002520 int x = location[0];
2521 int y = location[1];
2522
Adam Cohen8dfcba42011-07-07 16:38:18 -07002523 v.getLocationInWindow(location);
Adam Cohene3e27a82011-04-15 12:07:39 -07002524 int vX = location[0];
2525 int vY = location[1];
2526
2527 location[0] = vX - x;
2528 location[1] = vY - y;
2529 }
2530
Adam Cohencb3382b2011-05-24 14:07:08 -07002531 public void onDragEnter(DragObject d) {
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002532 mDragEnforcer.onDragEnter();
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002533 mCreateUserFolderOnDrop = false;
2534 mAddToExistingFolderOnDrop = false;
2535
2536 mDropToLayout = null;
2537 CellLayout layout = getCurrentDropLayout();
2538 setCurrentDropLayout(layout);
2539 setCurrentDragOverlappingLayout(layout);
Winson Chungb26f3d62011-06-02 10:49:29 -07002540
Winson Chungc07918d2011-07-01 15:35:26 -07002541 // Because we don't have space in the Phone UI (the CellLayouts run to the edge) we
2542 // don't need to show the outlines
Daniel Sandlere4f98912013-06-25 15:13:26 -04002543 if (LauncherAppState.getInstance().isScreenLarge()) {
Winson Chungc07918d2011-07-01 15:35:26 -07002544 showOutlines();
Michael Jurkad718d6a2010-10-14 15:35:17 -07002545 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -08002546 }
2547
Adam Cohena897f392012-04-27 18:12:05 -07002548 static Rect getCellLayoutMetrics(Launcher launcher, int orientation) {
Winson Chung5f8afe62013-08-12 16:19:28 -07002549 LauncherAppState app = LauncherAppState.getInstance();
2550 DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
2551
Adam Cohena897f392012-04-27 18:12:05 -07002552 Resources res = launcher.getResources();
2553 Display display = launcher.getWindowManager().getDefaultDisplay();
2554 Point smallestSize = new Point();
2555 Point largestSize = new Point();
2556 display.getCurrentSizeRange(smallestSize, largestSize);
Winson Chung892c74d2013-08-22 16:15:50 -07002557 int countX = (int) grid.numColumns;
2558 int countY = (int) grid.numRows;
Adam Cohena897f392012-04-27 18:12:05 -07002559 if (orientation == CellLayout.LANDSCAPE) {
2560 if (mLandscapeCellLayoutMetrics == null) {
Winson Chung5f8afe62013-08-12 16:19:28 -07002561 Rect padding = grid.getWorkspacePadding(CellLayout.LANDSCAPE);
2562 int width = largestSize.x - padding.left - padding.right;
2563 int height = smallestSize.y - padding.top - padding.bottom;
Adam Cohena897f392012-04-27 18:12:05 -07002564 mLandscapeCellLayoutMetrics = new Rect();
Winson Chung66700732013-08-20 16:56:15 -07002565 CellLayout.getMetrics(mLandscapeCellLayoutMetrics, width, height,
Winson Chung892c74d2013-08-22 16:15:50 -07002566 countX, countY);
Adam Cohena897f392012-04-27 18:12:05 -07002567 }
2568 return mLandscapeCellLayoutMetrics;
2569 } else if (orientation == CellLayout.PORTRAIT) {
2570 if (mPortraitCellLayoutMetrics == null) {
Winson Chung5f8afe62013-08-12 16:19:28 -07002571 Rect padding = grid.getWorkspacePadding(CellLayout.PORTRAIT);
2572 int width = smallestSize.x - padding.left - padding.right;
2573 int height = largestSize.y - padding.top - padding.bottom;
Adam Cohena897f392012-04-27 18:12:05 -07002574 mPortraitCellLayoutMetrics = new Rect();
Winson Chung66700732013-08-20 16:56:15 -07002575 CellLayout.getMetrics(mPortraitCellLayoutMetrics, width, height,
Winson Chung892c74d2013-08-22 16:15:50 -07002576 countX, countY);
Adam Cohena897f392012-04-27 18:12:05 -07002577 }
2578 return mPortraitCellLayoutMetrics;
2579 }
2580 return null;
2581 }
2582
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002583 public void onDragExit(DragObject d) {
2584 mDragEnforcer.onDragExit();
Winson Chungc07918d2011-07-01 15:35:26 -07002585
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002586 // Here we store the final page that will be dropped to, if the workspace in fact
2587 // receives the drop
2588 if (mInScrollArea) {
Winson Chungcc1cfe42012-06-18 15:09:17 -07002589 if (isPageMoving()) {
2590 // If the user drops while the page is scrolling, we should use that page as the
2591 // destination instead of the page that is being hovered over.
2592 mDropToLayout = (CellLayout) getPageAt(getNextPage());
2593 } else {
2594 mDropToLayout = mDragOverlappingLayout;
2595 }
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002596 } else {
2597 mDropToLayout = mDragTargetLayout;
2598 }
2599
2600 if (mDragMode == DRAG_MODE_CREATE_FOLDER) {
2601 mCreateUserFolderOnDrop = true;
2602 } else if (mDragMode == DRAG_MODE_ADD_TO_FOLDER) {
2603 mAddToExistingFolderOnDrop = true;
Adam Cohen482ed822012-03-02 14:15:13 -08002604 }
2605
Winson Chungc07918d2011-07-01 15:35:26 -07002606 // Reset the scroll area and previous drag target
2607 onResetScrollArea();
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002608 setCurrentDropLayout(null);
2609 setCurrentDragOverlappingLayout(null);
Winson Chungc07918d2011-07-01 15:35:26 -07002610
Adam Cohen74c28d12011-11-18 14:17:11 -08002611 mSpringLoadedDragController.cancel();
Winson Chungc07918d2011-07-01 15:35:26 -07002612
2613 if (!mIsPageMoving) {
2614 hideOutlines();
2615 }
2616 }
2617
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002618 void setCurrentDropLayout(CellLayout layout) {
2619 if (mDragTargetLayout != null) {
2620 mDragTargetLayout.revertTempState();
2621 mDragTargetLayout.onDragExit();
2622 }
2623 mDragTargetLayout = layout;
2624 if (mDragTargetLayout != null) {
2625 mDragTargetLayout.onDragEnter();
2626 }
2627 cleanupReorder(true);
2628 cleanupFolderCreation();
2629 setCurrentDropOverCell(-1, -1);
2630 }
2631
2632 void setCurrentDragOverlappingLayout(CellLayout layout) {
2633 if (mDragOverlappingLayout != null) {
2634 mDragOverlappingLayout.setIsDragOverlapping(false);
2635 }
2636 mDragOverlappingLayout = layout;
2637 if (mDragOverlappingLayout != null) {
2638 mDragOverlappingLayout.setIsDragOverlapping(true);
2639 }
2640 invalidate();
2641 }
2642
2643 void setCurrentDropOverCell(int x, int y) {
2644 if (x != mDragOverX || y != mDragOverY) {
2645 mDragOverX = x;
2646 mDragOverY = y;
2647 setDragMode(DRAG_MODE_NONE);
2648 }
2649 }
2650
2651 void setDragMode(int dragMode) {
2652 if (dragMode != mDragMode) {
2653 if (dragMode == DRAG_MODE_NONE) {
2654 cleanupAddToFolder();
2655 // We don't want to cancel the re-order alarm every time the target cell changes
2656 // as this feels to slow / unresponsive.
2657 cleanupReorder(false);
2658 cleanupFolderCreation();
2659 } else if (dragMode == DRAG_MODE_ADD_TO_FOLDER) {
2660 cleanupReorder(true);
2661 cleanupFolderCreation();
2662 } else if (dragMode == DRAG_MODE_CREATE_FOLDER) {
2663 cleanupAddToFolder();
2664 cleanupReorder(true);
2665 } else if (dragMode == DRAG_MODE_REORDER) {
2666 cleanupAddToFolder();
2667 cleanupFolderCreation();
2668 }
2669 mDragMode = dragMode;
2670 }
2671 }
2672
2673 private void cleanupFolderCreation() {
2674 if (mDragFolderRingAnimator != null) {
2675 mDragFolderRingAnimator.animateToNaturalState();
2676 }
2677 mFolderCreationAlarm.cancelAlarm();
2678 }
2679
2680 private void cleanupAddToFolder() {
2681 if (mDragOverFolderIcon != null) {
2682 mDragOverFolderIcon.onDragExit(null);
2683 mDragOverFolderIcon = null;
2684 }
2685 }
2686
2687 private void cleanupReorder(boolean cancelAlarm) {
2688 // Any pending reorders are canceled
2689 if (cancelAlarm) {
2690 mReorderAlarm.cancelAlarm();
2691 }
2692 mLastReorderX = -1;
2693 mLastReorderY = -1;
Winson Chungc07918d2011-07-01 15:35:26 -07002694 }
2695
Michael Jurka4516c112010-10-07 15:13:47 -07002696 /*
2697 *
2698 * Convert the 2D coordinate xy from the parent View's coordinate space to this CellLayout's
2699 * coordinate space. The argument xy is modified with the return result.
2700 *
2701 * if cachedInverseMatrix is not null, this method will just use that matrix instead of
Michael Jurkad718d6a2010-10-14 15:35:17 -07002702 * computing it itself; we use this to avoid redundant matrix inversions in
Michael Jurka4516c112010-10-07 15:13:47 -07002703 * findMatchingPageForDragOver
2704 *
2705 */
2706 void mapPointFromSelfToChild(View v, float[] xy, Matrix cachedInverseMatrix) {
Adam Cohen7d30a372013-07-01 17:03:59 -07002707 xy[0] = xy[0] - v.getLeft();
2708 xy[1] = xy[1] - v.getTop();
Michael Jurka4516c112010-10-07 15:13:47 -07002709 }
2710
Adam Cohen7d30a372013-07-01 17:03:59 -07002711 boolean isPointInSelfOverHotseat(int x, int y, Rect r) {
2712 if (r == null) {
2713 r = new Rect();
2714 }
2715 mTempPt[0] = x;
2716 mTempPt[1] = y;
2717 mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(this, mTempPt, true);
2718 mLauncher.getHotseat().getHitRect(r);
2719 if (r.contains(mTempPt[0], mTempPt[1])) {
2720 return true;
2721 }
2722 return false;
2723 }
Winson Chung3d503fb2011-07-13 17:25:49 -07002724
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002725 void mapPointFromSelfToHotseatLayout(Hotseat hotseat, float[] xy) {
Adam Cohen7d30a372013-07-01 17:03:59 -07002726 mTempPt[0] = (int) xy[0];
2727 mTempPt[1] = (int) xy[1];
2728 mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(this, mTempPt, true);
Winson Chung156ab5b2013-07-12 14:14:16 -07002729 mLauncher.getDragLayer().mapCoordInSelfToDescendent(hotseat.getLayout(), mTempPt);
Adam Cohen7d30a372013-07-01 17:03:59 -07002730
2731 xy[0] = mTempPt[0];
2732 xy[1] = mTempPt[1];
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002733 }
2734
Winson Chung3d503fb2011-07-13 17:25:49 -07002735 /*
Michael Jurka4516c112010-10-07 15:13:47 -07002736 *
2737 * Convert the 2D coordinate xy from this CellLayout's coordinate space to
2738 * the parent View's coordinate space. The argument xy is modified with the return result.
2739 *
2740 */
2741 void mapPointFromChildToSelf(View v, float[] xy) {
Adam Cohen7d30a372013-07-01 17:03:59 -07002742 xy[0] += v.getLeft();
2743 xy[1] += v.getTop();
Michael Jurka4516c112010-10-07 15:13:47 -07002744 }
2745
Adam Cohene3e27a82011-04-15 12:07:39 -07002746 static private float squaredDistance(float[] point1, float[] point2) {
Michael Jurka4516c112010-10-07 15:13:47 -07002747 float distanceX = point1[0] - point2[0];
2748 float distanceY = point2[1] - point2[1];
2749 return distanceX * distanceX + distanceY * distanceY;
Adam Cohene3e27a82011-04-15 12:07:39 -07002750 }
Michael Jurka0280c3b2010-09-17 15:00:07 -07002751
Michael Jurka4516c112010-10-07 15:13:47 -07002752 /*
2753 *
Michael Jurka4516c112010-10-07 15:13:47 -07002754 * This method returns the CellLayout that is currently being dragged to. In order to drag
2755 * to a CellLayout, either the touch point must be directly over the CellLayout, or as a second
2756 * strategy, we see if the dragView is overlapping any CellLayout and choose the closest one
2757 *
2758 * Return null if no CellLayout is currently being dragged over
2759 *
2760 */
2761 private CellLayout findMatchingPageForDragOver(
Adam Cohen00618752011-07-20 12:06:04 -07002762 DragView dragView, float originX, float originY, boolean exact) {
Michael Jurka4516c112010-10-07 15:13:47 -07002763 // We loop through all the screens (ie CellLayouts) and see which ones overlap
2764 // with the item being dragged and then choose the one that's closest to the touch point
Michael Jurkaa63c4522010-08-19 13:52:27 -07002765 final int screenCount = getChildCount();
2766 CellLayout bestMatchingScreen = null;
Michael Jurka0280c3b2010-09-17 15:00:07 -07002767 float smallestDistSoFar = Float.MAX_VALUE;
Michael Jurka4516c112010-10-07 15:13:47 -07002768
Michael Jurkaa63c4522010-08-19 13:52:27 -07002769 for (int i = 0; i < screenCount; i++) {
Winson Chung3d503fb2011-07-13 17:25:49 -07002770 CellLayout cl = (CellLayout) getChildAt(i);
Michael Jurkaa63c4522010-08-19 13:52:27 -07002771
Adam Cohen00618752011-07-20 12:06:04 -07002772 final float[] touchXy = {originX, originY};
Michael Jurka4516c112010-10-07 15:13:47 -07002773 // Transform the touch coordinates to the CellLayout's local coordinates
2774 // If the touch point is within the bounds of the cell layout, we can return immediately
Michael Jurka0280c3b2010-09-17 15:00:07 -07002775 cl.getMatrix().invert(mTempInverseMatrix);
Michael Jurka4516c112010-10-07 15:13:47 -07002776 mapPointFromSelfToChild(cl, touchXy, mTempInverseMatrix);
Michael Jurkaa63c4522010-08-19 13:52:27 -07002777
Michael Jurka4516c112010-10-07 15:13:47 -07002778 if (touchXy[0] >= 0 && touchXy[0] <= cl.getWidth() &&
2779 touchXy[1] >= 0 && touchXy[1] <= cl.getHeight()) {
2780 return cl;
2781 }
Michael Jurkaa63c4522010-08-19 13:52:27 -07002782
Winson Chung96ef4092011-11-22 12:25:14 -08002783 if (!exact) {
Michael Jurka4516c112010-10-07 15:13:47 -07002784 // Get the center of the cell layout in screen coordinates
2785 final float[] cellLayoutCenter = mTempCellLayoutCenterCoordinates;
2786 cellLayoutCenter[0] = cl.getWidth()/2;
2787 cellLayoutCenter[1] = cl.getHeight()/2;
2788 mapPointFromChildToSelf(cl, cellLayoutCenter);
Michael Jurka0280c3b2010-09-17 15:00:07 -07002789
Adam Cohen00618752011-07-20 12:06:04 -07002790 touchXy[0] = originX;
2791 touchXy[1] = originY;
Michael Jurka0280c3b2010-09-17 15:00:07 -07002792
Michael Jurka4516c112010-10-07 15:13:47 -07002793 // Calculate the distance between the center of the CellLayout
2794 // and the touch point
2795 float dist = squaredDistance(touchXy, cellLayoutCenter);
2796
2797 if (dist < smallestDistSoFar) {
Michael Jurka0280c3b2010-09-17 15:00:07 -07002798 smallestDistSoFar = dist;
Michael Jurkaa63c4522010-08-19 13:52:27 -07002799 bestMatchingScreen = cl;
Michael Jurkaa63c4522010-08-19 13:52:27 -07002800 }
Michael Jurka4516c112010-10-07 15:13:47 -07002801 }
Michael Jurkaa63c4522010-08-19 13:52:27 -07002802 }
Michael Jurkaa63c4522010-08-19 13:52:27 -07002803 return bestMatchingScreen;
2804 }
2805
Adam Cohene3e27a82011-04-15 12:07:39 -07002806 // This is used to compute the visual center of the dragView. This point is then
2807 // used to visualize drop locations and determine where to drop an item. The idea is that
2808 // the visual center represents the user's interpretation of where the item is, and hence
2809 // is the appropriate point to use when determining drop location.
2810 private float[] getDragViewVisualCenter(int x, int y, int xOffset, int yOffset,
2811 DragView dragView, float[] recycle) {
2812 float res[];
2813 if (recycle == null) {
2814 res = new float[2];
2815 } else {
2816 res = recycle;
2817 }
2818
2819 // First off, the drag view has been shifted in a way that is not represented in the
2820 // x and y values or the x/yOffsets. Here we account for that shift.
2821 x += getResources().getDimensionPixelSize(R.dimen.dragViewOffsetX);
2822 y += getResources().getDimensionPixelSize(R.dimen.dragViewOffsetY);
2823
2824 // These represent the visual top and left of drag view if a dragRect was provided.
2825 // If a dragRect was not provided, then they correspond to the actual view left and
2826 // top, as the dragRect is in that case taken to be the entire dragView.
2827 // R.dimen.dragViewOffsetY.
2828 int left = x - xOffset;
2829 int top = y - yOffset;
2830
2831 // In order to find the visual center, we shift by half the dragRect
2832 res[0] = left + dragView.getDragRegion().width() / 2;
2833 res[1] = top + dragView.getDragRegion().height() / 2;
2834
2835 return res;
2836 }
2837
Winson Chungea359c62011-08-03 17:06:35 -07002838 private boolean isDragWidget(DragObject d) {
2839 return (d.dragInfo instanceof LauncherAppWidgetInfo ||
2840 d.dragInfo instanceof PendingAddWidgetInfo);
2841 }
2842 private boolean isExternalDragWidget(DragObject d) {
2843 return d.dragSource != this && isDragWidget(d);
2844 }
2845
Adam Cohencb3382b2011-05-24 14:07:08 -07002846 public void onDragOver(DragObject d) {
Winson Chungc07918d2011-07-01 15:35:26 -07002847 // Skip drag over events while we are dragging over side pages
Adam Cohen82ac8a22012-02-14 16:27:49 -08002848 if (mInScrollArea || mIsSwitchingState || mState == State.SMALL) return;
Winson Chungc07918d2011-07-01 15:35:26 -07002849
Winson Chung4afe9b32011-07-27 17:46:20 -07002850 Rect r = new Rect();
Winson Chung3d503fb2011-07-13 17:25:49 -07002851 CellLayout layout = null;
Winson Chungc07918d2011-07-01 15:35:26 -07002852 ItemInfo item = (ItemInfo) d.dragInfo;
2853
2854 // Ensure that we have proper spans for the item that we are dropping
2855 if (item.spanX < 0 || item.spanY < 0) throw new RuntimeException("Improper spans found");
Adam Cohen00618752011-07-20 12:06:04 -07002856 mDragViewVisualCenter = getDragViewVisualCenter(d.x, d.y, d.xOffset, d.yOffset,
Winson Chung4afe9b32011-07-27 17:46:20 -07002857 d.dragView, mDragViewVisualCenter);
Adam Cohen00618752011-07-20 12:06:04 -07002858
Adam Cohen482ed822012-03-02 14:15:13 -08002859 final View child = (mDragInfo == null) ? null : mDragInfo.cell;
Winson Chungc07918d2011-07-01 15:35:26 -07002860 // Identify whether we have dragged over a side page
Michael Jurkad74c9842011-07-10 12:44:21 -07002861 if (isSmall()) {
Winson Chungea359c62011-08-03 17:06:35 -07002862 if (mLauncher.getHotseat() != null && !isExternalDragWidget(d)) {
Adam Cohen7d30a372013-07-01 17:03:59 -07002863 if (isPointInSelfOverHotseat(d.x, d.y, r)) {
Winson Chung4afe9b32011-07-27 17:46:20 -07002864 layout = mLauncher.getHotseat().getLayout();
2865 }
2866 }
2867 if (layout == null) {
Winson Chung96ef4092011-11-22 12:25:14 -08002868 layout = findMatchingPageForDragOver(d.dragView, d.x, d.y, false);
Winson Chung4afe9b32011-07-27 17:46:20 -07002869 }
Winson Chungc07918d2011-07-01 15:35:26 -07002870 if (layout != mDragTargetLayout) {
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002871 setCurrentDropLayout(layout);
2872 setCurrentDragOverlappingLayout(layout);
Winson Chungc07918d2011-07-01 15:35:26 -07002873
Michael Jurkad74c9842011-07-10 12:44:21 -07002874 boolean isInSpringLoadedMode = (mState == State.SPRING_LOADED);
Winson Chungc07918d2011-07-01 15:35:26 -07002875 if (isInSpringLoadedMode) {
Winson Chung4afe9b32011-07-27 17:46:20 -07002876 if (mLauncher.isHotseatLayout(layout)) {
2877 mSpringLoadedDragController.cancel();
2878 } else {
2879 mSpringLoadedDragController.setAlarm(mDragTargetLayout);
2880 }
Winson Chungc07918d2011-07-01 15:35:26 -07002881 }
2882 }
2883 } else {
Winson Chung3d503fb2011-07-13 17:25:49 -07002884 // Test to see if we are over the hotseat otherwise just use the current page
Winson Chungea359c62011-08-03 17:06:35 -07002885 if (mLauncher.getHotseat() != null && !isDragWidget(d)) {
Adam Cohen7d30a372013-07-01 17:03:59 -07002886 if (isPointInSelfOverHotseat(d.x, d.y, r)) {
Winson Chung3d503fb2011-07-13 17:25:49 -07002887 layout = mLauncher.getHotseat().getLayout();
2888 }
2889 }
2890 if (layout == null) {
2891 layout = getCurrentDropLayout();
2892 }
Winson Chungc07918d2011-07-01 15:35:26 -07002893 if (layout != mDragTargetLayout) {
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002894 setCurrentDropLayout(layout);
2895 setCurrentDragOverlappingLayout(layout);
Winson Chungc07918d2011-07-01 15:35:26 -07002896 }
2897 }
2898
2899 // Handle the drag over
2900 if (mDragTargetLayout != null) {
Winson Chungc07918d2011-07-01 15:35:26 -07002901 // We want the point to be mapped to the dragTarget.
Winson Chung3d503fb2011-07-13 17:25:49 -07002902 if (mLauncher.isHotseatLayout(mDragTargetLayout)) {
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002903 mapPointFromSelfToHotseatLayout(mLauncher.getHotseat(), mDragViewVisualCenter);
Winson Chung3d503fb2011-07-13 17:25:49 -07002904 } else {
2905 mapPointFromSelfToChild(mDragTargetLayout, mDragViewVisualCenter, null);
2906 }
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002907
Winson Chungc07918d2011-07-01 15:35:26 -07002908 ItemInfo info = (ItemInfo) d.dragInfo;
Patrick Dubroy1262e362010-10-06 15:49:50 -07002909
Winson Chungc07918d2011-07-01 15:35:26 -07002910 mTargetCell = findNearestArea((int) mDragViewVisualCenter[0],
Adam Cohend024f982012-05-23 18:26:45 -07002911 (int) mDragViewVisualCenter[1], item.spanX, item.spanY,
2912 mDragTargetLayout, mTargetCell);
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002913
2914 setCurrentDropOverCell(mTargetCell[0], mTargetCell[1]);
2915
Adam Cohen482ed822012-03-02 14:15:13 -08002916 float targetCellDistance = mDragTargetLayout.getDistanceFromCell(
2917 mDragViewVisualCenter[0], mDragViewVisualCenter[1], mTargetCell);
2918
Winson Chungc07918d2011-07-01 15:35:26 -07002919 final View dragOverView = mDragTargetLayout.getChildAt(mTargetCell[0],
2920 mTargetCell[1]);
Winson Chung785d2eb2011-04-14 16:08:02 -07002921
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002922 manageFolderFeedback(info, mDragTargetLayout, mTargetCell,
2923 targetCellDistance, dragOverView);
Adam Cohen482ed822012-03-02 14:15:13 -08002924
2925 int minSpanX = item.spanX;
2926 int minSpanY = item.spanY;
2927 if (item.minSpanX > 0 && item.minSpanY > 0) {
2928 minSpanX = item.minSpanX;
2929 minSpanY = item.minSpanY;
2930 }
2931
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002932 boolean nearestDropOccupied = mDragTargetLayout.isNearestDropLocationOccupied((int)
2933 mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1], item.spanX,
2934 item.spanY, child, mTargetCell);
2935
2936 if (!nearestDropOccupied) {
Adam Cohen19f37922012-03-21 11:59:11 -07002937 mDragTargetLayout.visualizeDropLocation(child, mDragOutline,
2938 (int) mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1],
2939 mTargetCell[0], mTargetCell[1], item.spanX, item.spanY, false,
2940 d.dragView.getDragVisualizeOffset(), d.dragView.getDragRegion());
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002941 } else if ((mDragMode == DRAG_MODE_NONE || mDragMode == DRAG_MODE_REORDER)
Adam Cohend024f982012-05-23 18:26:45 -07002942 && !mReorderAlarm.alarmPending() && (mLastReorderX != mTargetCell[0] ||
2943 mLastReorderY != mTargetCell[1])) {
2944
Adam Cohen19f37922012-03-21 11:59:11 -07002945 // Otherwise, if we aren't adding to or creating a folder and there's no pending
2946 // reorder, then we schedule a reorder
Adam Cohen482ed822012-03-02 14:15:13 -08002947 ReorderAlarmListener listener = new ReorderAlarmListener(mDragViewVisualCenter,
2948 minSpanX, minSpanY, item.spanX, item.spanY, d.dragView, child);
2949 mReorderAlarm.setOnAlarmListener(listener);
2950 mReorderAlarm.setAlarm(REORDER_TIMEOUT);
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002951 }
2952
2953 if (mDragMode == DRAG_MODE_CREATE_FOLDER || mDragMode == DRAG_MODE_ADD_TO_FOLDER ||
2954 !nearestDropOccupied) {
2955 if (mDragTargetLayout != null) {
2956 mDragTargetLayout.revertTempState();
Michael Jurkad3ef3062010-11-23 16:23:58 -08002957 }
2958 }
Adam Cohen482ed822012-03-02 14:15:13 -08002959 }
2960 }
2961
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002962 private void manageFolderFeedback(ItemInfo info, CellLayout targetLayout,
2963 int[] targetCell, float distance, View dragOverView) {
Adam Cohen482ed822012-03-02 14:15:13 -08002964 boolean userFolderPending = willCreateUserFolder(info, targetLayout, targetCell, distance,
2965 false);
2966
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002967 if (mDragMode == DRAG_MODE_NONE && userFolderPending &&
2968 !mFolderCreationAlarm.alarmPending()) {
Adam Cohen482ed822012-03-02 14:15:13 -08002969 mFolderCreationAlarm.setOnAlarmListener(new
2970 FolderCreationAlarmListener(targetLayout, targetCell[0], targetCell[1]));
2971 mFolderCreationAlarm.setAlarm(FOLDER_CREATION_TIMEOUT);
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002972 return;
Adam Cohen482ed822012-03-02 14:15:13 -08002973 }
2974
2975 boolean willAddToFolder =
2976 willAddToExistingUserFolder(info, targetLayout, targetCell, distance);
2977
2978 if (willAddToFolder && mDragMode == DRAG_MODE_NONE) {
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002979 mDragOverFolderIcon = ((FolderIcon) dragOverView);
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002980 mDragOverFolderIcon.onDragEnter(info);
Adam Cohen482ed822012-03-02 14:15:13 -08002981 if (targetLayout != null) {
2982 targetLayout.clearDragOutlines();
Winson Chungc07918d2011-07-01 15:35:26 -07002983 }
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002984 setDragMode(DRAG_MODE_ADD_TO_FOLDER);
2985 return;
Patrick Dubroy976ebec2010-08-04 20:03:37 -07002986 }
Adam Cohen482ed822012-03-02 14:15:13 -08002987
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002988 if (mDragMode == DRAG_MODE_ADD_TO_FOLDER && !willAddToFolder) {
2989 setDragMode(DRAG_MODE_NONE);
2990 }
2991 if (mDragMode == DRAG_MODE_CREATE_FOLDER && !userFolderPending) {
2992 setDragMode(DRAG_MODE_NONE);
Adam Cohen482ed822012-03-02 14:15:13 -08002993 }
2994
Adam Cohenc6cc61d2012-04-04 12:47:08 -07002995 return;
Adam Cohenc0dcf592011-06-01 15:30:43 -07002996 }
2997
Adam Cohen19072da2011-05-31 14:30:45 -07002998 class FolderCreationAlarmListener implements OnAlarmListener {
Adam Cohen69ce2e52011-07-03 19:25:21 -07002999 CellLayout layout;
3000 int cellX;
3001 int cellY;
Adam Cohen19072da2011-05-31 14:30:45 -07003002
Adam Cohen69ce2e52011-07-03 19:25:21 -07003003 public FolderCreationAlarmListener(CellLayout layout, int cellX, int cellY) {
3004 this.layout = layout;
3005 this.cellX = cellX;
3006 this.cellY = cellY;
Adam Cohen19072da2011-05-31 14:30:45 -07003007 }
3008
3009 public void onAlarm(Alarm alarm) {
Adam Cohen19072da2011-05-31 14:30:45 -07003010 if (mDragFolderRingAnimator == null) {
3011 mDragFolderRingAnimator = new FolderRingAnimator(mLauncher, null);
3012 }
Adam Cohen69ce2e52011-07-03 19:25:21 -07003013 mDragFolderRingAnimator.setCell(cellX, cellY);
3014 mDragFolderRingAnimator.setCellLayout(layout);
Adam Cohen19072da2011-05-31 14:30:45 -07003015 mDragFolderRingAnimator.animateToAcceptState();
Adam Cohen69ce2e52011-07-03 19:25:21 -07003016 layout.showFolderAccept(mDragFolderRingAnimator);
3017 layout.clearDragOutlines();
Adam Cohenc6cc61d2012-04-04 12:47:08 -07003018 setDragMode(DRAG_MODE_CREATE_FOLDER);
Adam Cohen482ed822012-03-02 14:15:13 -08003019 }
3020 }
3021
3022 class ReorderAlarmListener implements OnAlarmListener {
3023 float[] dragViewCenter;
3024 int minSpanX, minSpanY, spanX, spanY;
3025 DragView dragView;
3026 View child;
3027
3028 public ReorderAlarmListener(float[] dragViewCenter, int minSpanX, int minSpanY, int spanX,
3029 int spanY, DragView dragView, View child) {
3030 this.dragViewCenter = dragViewCenter;
3031 this.minSpanX = minSpanX;
3032 this.minSpanY = minSpanY;
3033 this.spanX = spanX;
3034 this.spanY = spanY;
3035 this.child = child;
3036 this.dragView = dragView;
3037 }
3038
3039 public void onAlarm(Alarm alarm) {
3040 int[] resultSpan = new int[2];
Adam Cohen19f37922012-03-21 11:59:11 -07003041 mTargetCell = findNearestArea((int) mDragViewVisualCenter[0],
3042 (int) mDragViewVisualCenter[1], spanX, spanY, mDragTargetLayout, mTargetCell);
3043 mLastReorderX = mTargetCell[0];
3044 mLastReorderY = mTargetCell[1];
3045
Adam Cohen482ed822012-03-02 14:15:13 -08003046 mTargetCell = mDragTargetLayout.createArea((int) mDragViewVisualCenter[0],
3047 (int) mDragViewVisualCenter[1], minSpanX, minSpanY, spanX, spanY,
3048 child, mTargetCell, resultSpan, CellLayout.MODE_DRAG_OVER);
3049
Adam Cohen19f37922012-03-21 11:59:11 -07003050 if (mTargetCell[0] < 0 || mTargetCell[1] < 0) {
3051 mDragTargetLayout.revertTempState();
Adam Cohenc6cc61d2012-04-04 12:47:08 -07003052 } else {
3053 setDragMode(DRAG_MODE_REORDER);
Adam Cohen19f37922012-03-21 11:59:11 -07003054 }
Adam Cohen482ed822012-03-02 14:15:13 -08003055
Adam Cohen482ed822012-03-02 14:15:13 -08003056 boolean resize = resultSpan[0] != spanX || resultSpan[1] != spanY;
3057 mDragTargetLayout.visualizeDropLocation(child, mDragOutline,
3058 (int) mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1],
3059 mTargetCell[0], mTargetCell[1], resultSpan[0], resultSpan[1], resize,
3060 dragView.getDragVisualizeOffset(), dragView.getDragRegion());
Adam Cohen19072da2011-05-31 14:30:45 -07003061 }
3062 }
3063
Winson Chunga34abf82010-11-12 12:10:35 -08003064 @Override
Adam Cohen7d30a372013-07-01 17:03:59 -07003065 public void getHitRectRelativeToDragLayer(Rect outRect) {
Winson Chunga34abf82010-11-12 12:10:35 -08003066 // We want the workspace to have the whole area of the display (it will find the correct
3067 // cell layout to drop to in the existing drag/drop logic.
Adam Cohen7d30a372013-07-01 17:03:59 -07003068 mLauncher.getDragLayer().getDescendantRectRelativeToSelf(this, outRect);
Winson Chunga34abf82010-11-12 12:10:35 -08003069 }
3070
Patrick Dubroy2b9ff372010-09-07 17:49:27 -07003071 /**
3072 * Add the item specified by dragInfo to the given layout.
Patrick Dubroy2b9ff372010-09-07 17:49:27 -07003073 * @return true if successful
3074 */
Adam Cohen120980b2010-12-08 11:05:37 -08003075 public boolean addExternalItemToScreen(ItemInfo dragInfo, CellLayout layout) {
3076 if (layout.findCellForSpan(mTempEstimate, dragInfo.spanX, dragInfo.spanY)) {
Patrick Dubroybbaa75c2011-03-08 18:47:40 -08003077 onDropExternal(dragInfo.dropPos, (ItemInfo) dragInfo, (CellLayout) layout, false);
Patrick Dubroy2b9ff372010-09-07 17:49:27 -07003078 return true;
3079 }
Winson Chung93eef082012-03-23 15:59:27 -07003080 mLauncher.showOutOfSpaceMessage(mLauncher.isHotseatLayout(layout));
Patrick Dubroy2b9ff372010-09-07 17:49:27 -07003081 return false;
3082 }
3083
Adam Cohend5e42732011-03-28 17:33:39 -07003084 private void onDropExternal(int[] touchXY, Object dragInfo,
3085 CellLayout cellLayout, boolean insertAtFirst) {
Adam Cohene3e27a82011-04-15 12:07:39 -07003086 onDropExternal(touchXY, dragInfo, cellLayout, insertAtFirst, null);
Adam Cohend5e42732011-03-28 17:33:39 -07003087 }
3088
Adam Cohen120980b2010-12-08 11:05:37 -08003089 /**
3090 * Drop an item that didn't originate on one of the workspace screens.
3091 * It may have come from Launcher (e.g. from all apps or customize), or it may have
3092 * come from another app altogether.
3093 *
3094 * NOTE: This can also be called when we are outside of a drag event, when we want
3095 * to add an item to one of the workspace screens.
3096 */
Winson Chung557d6ed2011-07-08 15:34:52 -07003097 private void onDropExternal(final int[] touchXY, final Object dragInfo,
3098 final CellLayout cellLayout, boolean insertAtFirst, DragObject d) {
3099 final Runnable exitSpringLoadedRunnable = new Runnable() {
3100 @Override
3101 public void run() {
Adam Cohened66b2b2012-01-23 17:28:51 -08003102 mLauncher.exitSpringLoadedDragModeDelayed(true, false, null);
Winson Chung557d6ed2011-07-08 15:34:52 -07003103 }
3104 };
Adam Cohenb7e16182011-07-15 17:55:02 -07003105
3106 ItemInfo info = (ItemInfo) dragInfo;
3107 int spanX = info.spanX;
3108 int spanY = info.spanY;
3109 if (mDragInfo != null) {
3110 spanX = mDragInfo.spanX;
3111 spanY = mDragInfo.spanY;
3112 }
3113
Winson Chung3d503fb2011-07-13 17:25:49 -07003114 final long container = mLauncher.isHotseatLayout(cellLayout) ?
3115 LauncherSettings.Favorites.CONTAINER_HOTSEAT :
3116 LauncherSettings.Favorites.CONTAINER_DESKTOP;
Adam Cohendcd297f2013-06-18 13:13:40 -07003117 final long screenId = getIdForScreen(cellLayout);
3118 if (!mLauncher.isHotseatLayout(cellLayout)
3119 && screenId != getScreenIdForPageIndex(mCurrentPage)
Winson Chung3d503fb2011-07-13 17:25:49 -07003120 && mState != State.SPRING_LOADED) {
Adam Cohendcd297f2013-06-18 13:13:40 -07003121 snapToScreenId(screenId, null);
Adam Cohen76078c42011-06-09 15:06:52 -07003122 }
Adam Cohenb7e16182011-07-15 17:55:02 -07003123
3124 if (info instanceof PendingAddItemInfo) {
3125 final PendingAddItemInfo pendingInfo = (PendingAddItemInfo) dragInfo;
3126
Adam Cohen558baaf2011-08-15 15:22:57 -07003127 boolean findNearestVacantCell = true;
3128 if (pendingInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) {
3129 mTargetCell = findNearestArea((int) touchXY[0], (int) touchXY[1], spanX, spanY,
3130 cellLayout, mTargetCell);
Adam Cohen482ed822012-03-02 14:15:13 -08003131 float distance = cellLayout.getDistanceFromCell(mDragViewVisualCenter[0],
3132 mDragViewVisualCenter[1], mTargetCell);
Adam Cohenc6cc61d2012-04-04 12:47:08 -07003133 if (willCreateUserFolder((ItemInfo) d.dragInfo, cellLayout, mTargetCell,
Adam Cohen482ed822012-03-02 14:15:13 -08003134 distance, true) || willAddToExistingUserFolder((ItemInfo) d.dragInfo,
Adam Cohenc6cc61d2012-04-04 12:47:08 -07003135 cellLayout, mTargetCell, distance)) {
Adam Cohen558baaf2011-08-15 15:22:57 -07003136 findNearestVacantCell = false;
3137 }
3138 }
Adam Cohen482ed822012-03-02 14:15:13 -08003139
Adam Cohend41fbf52012-02-16 23:53:59 -08003140 final ItemInfo item = (ItemInfo) d.dragInfo;
Adam Cohenaaa5c212012-10-05 18:14:31 -07003141 boolean updateWidgetSize = false;
Adam Cohen558baaf2011-08-15 15:22:57 -07003142 if (findNearestVacantCell) {
Adam Cohen482ed822012-03-02 14:15:13 -08003143 int minSpanX = item.spanX;
3144 int minSpanY = item.spanY;
3145 if (item.minSpanX > 0 && item.minSpanY > 0) {
3146 minSpanX = item.minSpanX;
3147 minSpanY = item.minSpanY;
3148 }
Adam Cohend41fbf52012-02-16 23:53:59 -08003149 int[] resultSpan = new int[2];
Adam Cohenc6cc61d2012-04-04 12:47:08 -07003150 mTargetCell = cellLayout.createArea((int) mDragViewVisualCenter[0],
Adam Cohen482ed822012-03-02 14:15:13 -08003151 (int) mDragViewVisualCenter[1], minSpanX, minSpanY, info.spanX, info.spanY,
3152 null, mTargetCell, resultSpan, CellLayout.MODE_ON_DROP_EXTERNAL);
Adam Cohen9e05a5e2012-09-10 15:53:09 -07003153
3154 if (resultSpan[0] != item.spanX || resultSpan[1] != item.spanY) {
3155 updateWidgetSize = true;
3156 }
Adam Cohend41fbf52012-02-16 23:53:59 -08003157 item.spanX = resultSpan[0];
3158 item.spanY = resultSpan[1];
Adam Cohen558baaf2011-08-15 15:22:57 -07003159 }
3160
Adam Cohenb7e16182011-07-15 17:55:02 -07003161 Runnable onAnimationCompleteRunnable = new Runnable() {
Winson Chung557d6ed2011-07-08 15:34:52 -07003162 @Override
3163 public void run() {
3164 // When dragging and dropping from customization tray, we deal with creating
3165 // widgets/shortcuts/folders in a slightly different way
Adam Cohenb7e16182011-07-15 17:55:02 -07003166 switch (pendingInfo.itemType) {
Winson Chung557d6ed2011-07-08 15:34:52 -07003167 case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
Adam Cohend41fbf52012-02-16 23:53:59 -08003168 int span[] = new int[2];
3169 span[0] = item.spanX;
3170 span[1] = item.spanY;
Adam Cohenb7e16182011-07-15 17:55:02 -07003171 mLauncher.addAppWidgetFromDrop((PendingAddWidgetInfo) pendingInfo,
Adam Cohendcd297f2013-06-18 13:13:40 -07003172 container, screenId, mTargetCell, span, null);
Winson Chung557d6ed2011-07-08 15:34:52 -07003173 break;
3174 case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
Adam Cohenb7e16182011-07-15 17:55:02 -07003175 mLauncher.processShortcutFromDrop(pendingInfo.componentName,
Adam Cohendcd297f2013-06-18 13:13:40 -07003176 container, screenId, mTargetCell, null);
Winson Chung557d6ed2011-07-08 15:34:52 -07003177 break;
3178 default:
Adam Cohenb7e16182011-07-15 17:55:02 -07003179 throw new IllegalStateException("Unknown item type: " +
3180 pendingInfo.itemType);
Winson Chung557d6ed2011-07-08 15:34:52 -07003181 }
Winson Chung557d6ed2011-07-08 15:34:52 -07003182 }
Adam Cohenb7e16182011-07-15 17:55:02 -07003183 };
Adam Cohend41fbf52012-02-16 23:53:59 -08003184 View finalView = pendingInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET
3185 ? ((PendingAddWidgetInfo) pendingInfo).boundWidget : null;
Adam Cohen9e05a5e2012-09-10 15:53:09 -07003186
3187 if (finalView instanceof AppWidgetHostView && updateWidgetSize) {
3188 AppWidgetHostView awhv = (AppWidgetHostView) finalView;
3189 AppWidgetResizeFrame.updateWidgetSizeRanges(awhv, mLauncher, item.spanX,
3190 item.spanY);
3191 }
3192
Adam Cohend41fbf52012-02-16 23:53:59 -08003193 int animationStyle = ANIMATE_INTO_POSITION_AND_DISAPPEAR;
3194 if (pendingInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET &&
3195 ((PendingAddWidgetInfo) pendingInfo).info.configure != null) {
3196 animationStyle = ANIMATE_INTO_POSITION_AND_REMAIN;
3197 }
3198 animateWidgetDrop(info, cellLayout, d.dragView, onAnimationCompleteRunnable,
3199 animationStyle, finalView, true);
Patrick Dubroy6569f2c2010-07-12 14:25:18 -07003200 } else {
Michael Jurka9c6de3d2010-11-23 16:23:58 -08003201 // This is for other drag/drop cases, like dragging from All Apps
Michael Jurka9c6de3d2010-11-23 16:23:58 -08003202 View view = null;
3203
3204 switch (info.itemType) {
3205 case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
3206 case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
3207 if (info.container == NO_ID && info instanceof ApplicationInfo) {
3208 // Came from all apps -- make a copy
Michael Jurkac9d95c52011-08-29 14:03:34 -07003209 info = new ShortcutInfo((ApplicationInfo) info);
Michael Jurka9c6de3d2010-11-23 16:23:58 -08003210 }
3211 view = mLauncher.createShortcut(R.layout.application, cellLayout,
3212 (ShortcutInfo) info);
3213 break;
Adam Cohendf2cc412011-04-27 16:56:57 -07003214 case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
Adam Cohenc0dcf592011-06-01 15:30:43 -07003215 view = FolderIcon.fromXml(R.layout.folder_icon, mLauncher, cellLayout,
3216 (FolderInfo) info, mIconCache);
Michael Jurka9c6de3d2010-11-23 16:23:58 -08003217 break;
3218 default:
3219 throw new IllegalStateException("Unknown item type: " + info.itemType);
3220 }
3221
Adam Cohenc0dcf592011-06-01 15:30:43 -07003222 // First we find the cell nearest to point at which the item is
3223 // dropped, without any consideration to whether there is an item there.
3224 if (touchXY != null) {
3225 mTargetCell = findNearestArea((int) touchXY[0], (int) touchXY[1], spanX, spanY,
3226 cellLayout, mTargetCell);
Adam Cohen482ed822012-03-02 14:15:13 -08003227 float distance = cellLayout.getDistanceFromCell(mDragViewVisualCenter[0],
3228 mDragViewVisualCenter[1], mTargetCell);
Winson Chung557d6ed2011-07-08 15:34:52 -07003229 d.postAnimationRunnable = exitSpringLoadedRunnable;
Adam Cohen482ed822012-03-02 14:15:13 -08003230 if (createUserFolderIfNecessary(view, container, cellLayout, mTargetCell, distance,
3231 true, d.dragView, d.postAnimationRunnable)) {
Adam Cohenc0dcf592011-06-01 15:30:43 -07003232 return;
3233 }
Adam Cohen482ed822012-03-02 14:15:13 -08003234 if (addToExistingFolderIfNecessary(view, cellLayout, mTargetCell, distance, d,
3235 true)) {
Adam Cohenc0dcf592011-06-01 15:30:43 -07003236 return;
3237 }
Adam Cohen10b17372011-04-15 14:21:25 -07003238 }
3239
Michael Jurkac4e772e2011-02-10 13:32:01 -08003240 if (touchXY != null) {
Michael Jurka9c6de3d2010-11-23 16:23:58 -08003241 // when dragging and dropping, just find the closest free spot
Adam Cohenc6cc61d2012-04-04 12:47:08 -07003242 mTargetCell = cellLayout.createArea((int) mDragViewVisualCenter[0],
Adam Cohen482ed822012-03-02 14:15:13 -08003243 (int) mDragViewVisualCenter[1], 1, 1, 1, 1,
Adam Cohenea889a22012-03-27 16:45:39 -07003244 null, mTargetCell, null, CellLayout.MODE_ON_DROP_EXTERNAL);
Michael Jurka9c6de3d2010-11-23 16:23:58 -08003245 } else {
3246 cellLayout.findCellForSpan(mTargetCell, 1, 1);
3247 }
Adam Cohendcd297f2013-06-18 13:13:40 -07003248 addInScreen(view, container, screenId, mTargetCell[0], mTargetCell[1], info.spanX,
Winson Chung3d503fb2011-07-13 17:25:49 -07003249 info.spanY, insertAtFirst);
Adam Cohen716b51e2011-06-30 12:09:54 -07003250 cellLayout.onDropChild(view);
Patrick Dubroy6569f2c2010-07-12 14:25:18 -07003251 CellLayout.LayoutParams lp = (CellLayout.LayoutParams) view.getLayoutParams();
Michael Jurkaa52570f2012-03-20 03:18:20 -07003252 cellLayout.getShortcutsAndWidgets().measureChild(view);
Adam Cohend5e42732011-03-28 17:33:39 -07003253
Adam Cohendcd297f2013-06-18 13:13:40 -07003254 LauncherModel.addOrMoveItemInDatabase(mLauncher, info, container, screenId,
Winson Chungaafa03c2010-06-11 17:34:16 -07003255 lp.cellX, lp.cellY);
Adam Cohen3e8f8112011-07-02 18:03:00 -07003256
3257 if (d.dragView != null) {
Adam Cohen4b285c52011-07-21 14:24:06 -07003258 // We wrap the animation call in the temporary set and reset of the current
3259 // cellLayout to its final transform -- this means we animate the drag view to
3260 // the correct final location.
3261 setFinalTransitionTransform(cellLayout);
Winson Chung557d6ed2011-07-08 15:34:52 -07003262 mLauncher.getDragLayer().animateViewIntoPosition(d.dragView, view,
Adam Cohen4b285c52011-07-21 14:24:06 -07003263 exitSpringLoadedRunnable);
3264 resetTransitionTransform(cellLayout);
Adam Cohen3e8f8112011-07-02 18:03:00 -07003265 }
Joe Onorato00acb122009-08-04 16:04:30 -04003266 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003267 }
Winson Chungaafa03c2010-06-11 17:34:16 -07003268
Adam Cohend41fbf52012-02-16 23:53:59 -08003269 public Bitmap createWidgetBitmap(ItemInfo widgetInfo, View layout) {
Adam Cohened66b2b2012-01-23 17:28:51 -08003270 int[] unScaledSize = mLauncher.getWorkspace().estimateItemSize(widgetInfo.spanX,
3271 widgetInfo.spanY, widgetInfo, false);
Adam Cohend41fbf52012-02-16 23:53:59 -08003272 int visibility = layout.getVisibility();
Adam Cohened66b2b2012-01-23 17:28:51 -08003273 layout.setVisibility(VISIBLE);
3274
3275 int width = MeasureSpec.makeMeasureSpec(unScaledSize[0], MeasureSpec.EXACTLY);
3276 int height = MeasureSpec.makeMeasureSpec(unScaledSize[1], MeasureSpec.EXACTLY);
3277 Bitmap b = Bitmap.createBitmap(unScaledSize[0], unScaledSize[1],
3278 Bitmap.Config.ARGB_8888);
3279 Canvas c = new Canvas(b);
3280
3281 layout.measure(width, height);
3282 layout.layout(0, 0, unScaledSize[0], unScaledSize[1]);
Adam Cohened66b2b2012-01-23 17:28:51 -08003283 layout.draw(c);
3284 c.setBitmap(null);
Adam Cohend41fbf52012-02-16 23:53:59 -08003285 layout.setVisibility(visibility);
Adam Cohened66b2b2012-01-23 17:28:51 -08003286 return b;
3287 }
3288
Adam Cohend41fbf52012-02-16 23:53:59 -08003289 private void getFinalPositionForDropAnimation(int[] loc, float[] scaleXY,
Adam Cohen9d5b7d82012-05-09 18:00:44 -07003290 DragView dragView, CellLayout layout, ItemInfo info, int[] targetCell,
Michael Jurkaa2fe7862012-05-29 05:58:17 -07003291 boolean external, boolean scale) {
Adam Cohened66b2b2012-01-23 17:28:51 -08003292 // Now we animate the dragView, (ie. the widget or shortcut preview) into its final
3293 // location and size on the home screen.
Adam Cohend41fbf52012-02-16 23:53:59 -08003294 int spanX = info.spanX;
3295 int spanY = info.spanY;
Adam Cohened66b2b2012-01-23 17:28:51 -08003296
Adam Cohend41fbf52012-02-16 23:53:59 -08003297 Rect r = estimateItemPosition(layout, info, targetCell[0], targetCell[1], spanX, spanY);
3298 loc[0] = r.left;
3299 loc[1] = r.top;
3300
3301 setFinalTransitionTransform(layout);
3302 float cellLayoutScale =
Adam Cohen7d30a372013-07-01 17:03:59 -07003303 mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(layout, loc, true);
Adam Cohend41fbf52012-02-16 23:53:59 -08003304 resetTransitionTransform(layout);
Michael Jurkaa2fe7862012-05-29 05:58:17 -07003305
3306 float dragViewScaleX;
3307 float dragViewScaleY;
3308 if (scale) {
3309 dragViewScaleX = (1.0f * r.width()) / dragView.getMeasuredWidth();
3310 dragViewScaleY = (1.0f * r.height()) / dragView.getMeasuredHeight();
3311 } else {
3312 dragViewScaleX = 1f;
3313 dragViewScaleY = 1f;
3314 }
Adam Cohend41fbf52012-02-16 23:53:59 -08003315
Adam Cohened66b2b2012-01-23 17:28:51 -08003316 // The animation will scale the dragView about its center, so we need to center about
3317 // the final location.
3318 loc[0] -= (dragView.getMeasuredWidth() - cellLayoutScale * r.width()) / 2;
3319 loc[1] -= (dragView.getMeasuredHeight() - cellLayoutScale * r.height()) / 2;
3320
Adam Cohend41fbf52012-02-16 23:53:59 -08003321 scaleXY[0] = dragViewScaleX * cellLayoutScale;
3322 scaleXY[1] = dragViewScaleY * cellLayoutScale;
3323 }
3324
3325 public void animateWidgetDrop(ItemInfo info, CellLayout cellLayout, DragView dragView,
3326 final Runnable onCompleteRunnable, int animationType, final View finalView,
3327 boolean external) {
3328 Rect from = new Rect();
3329 mLauncher.getDragLayer().getViewRectRelativeToSelf(dragView, from);
3330
3331 int[] finalPos = new int[2];
3332 float scaleXY[] = new float[2];
Michael Jurkaa2fe7862012-05-29 05:58:17 -07003333 boolean scalePreview = !(info instanceof PendingAddShortcutInfo);
Adam Cohend41fbf52012-02-16 23:53:59 -08003334 getFinalPositionForDropAnimation(finalPos, scaleXY, dragView, cellLayout, info, mTargetCell,
Michael Jurkaa2fe7862012-05-29 05:58:17 -07003335 external, scalePreview);
Adam Cohened66b2b2012-01-23 17:28:51 -08003336
3337 Resources res = mLauncher.getResources();
3338 int duration = res.getInteger(R.integer.config_dropAnimMaxDuration) - 200;
3339
Adam Cohend41fbf52012-02-16 23:53:59 -08003340 // In the case where we've prebound the widget, we remove it from the DragLayer
3341 if (finalView instanceof AppWidgetHostView && external) {
Adam Cohen68f681b2012-05-28 15:01:16 -07003342 Log.d(TAG, "6557954 Animate widget drop, final view is appWidgetHostView");
Adam Cohend41fbf52012-02-16 23:53:59 -08003343 mLauncher.getDragLayer().removeView(finalView);
3344 }
3345 if ((animationType == ANIMATE_INTO_POSITION_AND_RESIZE || external) && finalView != null) {
3346 Bitmap crossFadeBitmap = createWidgetBitmap(info, finalView);
Adam Cohened66b2b2012-01-23 17:28:51 -08003347 dragView.setCrossFadeBitmap(crossFadeBitmap);
3348 dragView.crossFade((int) (duration * 0.8f));
Adam Cohend41fbf52012-02-16 23:53:59 -08003349 } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET && external) {
3350 scaleXY[0] = scaleXY[1] = Math.min(scaleXY[0], scaleXY[1]);
Adam Cohened66b2b2012-01-23 17:28:51 -08003351 }
3352
Adam Cohend41fbf52012-02-16 23:53:59 -08003353 DragLayer dragLayer = mLauncher.getDragLayer();
Winson Chung7bd1bbb2012-02-13 18:29:29 -08003354 if (animationType == CANCEL_TWO_STAGE_WIDGET_DROP_ANIMATION) {
Adam Cohend41fbf52012-02-16 23:53:59 -08003355 mLauncher.getDragLayer().animateViewIntoPosition(dragView, finalPos, 0f, 0.1f, 0.1f,
Adam Cohened66b2b2012-01-23 17:28:51 -08003356 DragLayer.ANIMATION_END_DISAPPEAR, onCompleteRunnable, duration);
3357 } else {
Adam Cohend41fbf52012-02-16 23:53:59 -08003358 int endStyle;
3359 if (animationType == ANIMATE_INTO_POSITION_AND_REMAIN) {
3360 endStyle = DragLayer.ANIMATION_END_REMAIN_VISIBLE;
3361 } else {
3362 endStyle = DragLayer.ANIMATION_END_DISAPPEAR;;
3363 }
3364
3365 Runnable onComplete = new Runnable() {
3366 @Override
3367 public void run() {
3368 if (finalView != null) {
3369 finalView.setVisibility(VISIBLE);
3370 }
3371 if (onCompleteRunnable != null) {
3372 onCompleteRunnable.run();
3373 }
3374 }
3375 };
3376 dragLayer.animateViewIntoPosition(dragView, from.left, from.top, finalPos[0],
3377 finalPos[1], 1, 1, 1, scaleXY[0], scaleXY[1], onComplete, endStyle,
3378 duration, this);
Adam Cohened66b2b2012-01-23 17:28:51 -08003379 }
3380 }
3381
Adam Cohen4b285c52011-07-21 14:24:06 -07003382 public void setFinalTransitionTransform(CellLayout layout) {
3383 if (isSwitchingState()) {
Adam Cohen7d30a372013-07-01 17:03:59 -07003384 mCurrentScale = getScaleX();
3385 setScaleX(mNewScale);
3386 setScaleY(mNewScale);
Adam Cohen4b285c52011-07-21 14:24:06 -07003387 }
3388 }
3389 public void resetTransitionTransform(CellLayout layout) {
3390 if (isSwitchingState()) {
Adam Cohen7d30a372013-07-01 17:03:59 -07003391 setScaleX(mCurrentScale);
3392 setScaleY(mCurrentScale);
Adam Cohen4b285c52011-07-21 14:24:06 -07003393 }
3394 }
3395
Jeff Sharkey70864282009-04-07 21:08:40 -07003396 /**
3397 * Return the current {@link CellLayout}, correctly picking the destination
3398 * screen while a scroll is in progress.
3399 */
Patrick Dubroy5f445422011-02-18 14:35:21 -08003400 public CellLayout getCurrentDropLayout() {
Winson Chung360e63f2012-04-27 13:48:05 -07003401 return (CellLayout) getChildAt(getNextPage());
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003402 }
3403
Jeff Sharkey70864282009-04-07 21:08:40 -07003404 /**
Michael Jurka0280c3b2010-09-17 15:00:07 -07003405 * Return the current CellInfo describing our current drag; this method exists
3406 * so that Launcher can sync this object with the correct info when the activity is created/
3407 * destroyed
3408 *
3409 */
3410 public CellLayout.CellInfo getDragInfo() {
3411 return mDragInfo;
3412 }
3413
3414 /**
Jeff Sharkey70864282009-04-07 21:08:40 -07003415 * Calculate the nearest cell where the given object would be dropped.
Adam Cohene3e27a82011-04-15 12:07:39 -07003416 *
3417 * pixelX and pixelY should be in the coordinate system of layout
Jeff Sharkey70864282009-04-07 21:08:40 -07003418 */
Adam Cohendf035382011-04-11 17:22:04 -07003419 private int[] findNearestArea(int pixelX, int pixelY,
Adam Cohene3e27a82011-04-15 12:07:39 -07003420 int spanX, int spanY, CellLayout layout, int[] recycle) {
Adam Cohendf035382011-04-11 17:22:04 -07003421 return layout.findNearestArea(
Adam Cohene3e27a82011-04-15 12:07:39 -07003422 pixelX, pixelY, spanX, spanY, recycle);
Adam Cohendf035382011-04-11 17:22:04 -07003423 }
3424
Adam Cohencff6af82011-09-13 14:51:53 -07003425 void setup(DragController dragController) {
Michael Jurkac2f7f472010-12-14 15:34:42 -08003426 mSpringLoadedDragController = new SpringLoadedDragController(mLauncher);
Joe Onorato00acb122009-08-04 16:04:30 -04003427 mDragController = dragController;
Michael Jurkad74c9842011-07-10 12:44:21 -07003428
Michael Jurkad74c9842011-07-10 12:44:21 -07003429 // hardware layers on children are enabled on startup, but should be disabled until
3430 // needed
Michael Jurka3a0469d2012-06-21 09:38:41 -07003431 updateChildrenLayersEnabled(false);
Michael Jurkad74c9842011-07-10 12:44:21 -07003432 setWallpaperDimension();
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003433 }
3434
Patrick Dubroye3887cc2011-01-20 10:43:40 -08003435 /**
3436 * Called at the end of a drag which originated on the workspace.
3437 */
Michael Jurka1e2f4652013-07-08 18:03:46 -07003438 public void onDropCompleted(final View target, final DragObject d,
3439 final boolean isFlingToDelete, final boolean success) {
3440 if (mDeferDropAfterUninstall) {
3441 mDeferredAction = new Runnable() {
3442 public void run() {
3443 onDropCompleted(target, d, isFlingToDelete, success);
3444 mDeferredAction = null;
Michael Jurkad74c9842011-07-10 12:44:21 -07003445 }
Michael Jurka1e2f4652013-07-08 18:03:46 -07003446 };
3447 return;
3448 }
3449
3450 boolean beingCalledAfterUninstall = mDeferredAction != null;
3451
3452 if (success && !(beingCalledAfterUninstall && !mUninstallSuccessful)) {
3453 if (target != this && mDragInfo != null) {
3454 getParentCellLayoutForView(mDragInfo.cell).removeView(mDragInfo.cell);
3455 if (mDragInfo.cell instanceof DropTarget) {
3456 mDragController.removeDropTarget((DropTarget) mDragInfo.cell);
Joe Onorato00acb122009-08-04 16:04:30 -04003457 }
Adam Cohend6e7aa32013-07-09 15:32:37 -07003458 // If we move the item to anything not on the Workspace, check if any empty
3459 // screens need to be removed. If we dropped back on the workspace, this will
3460 // be done post drop animation.
3461 stripEmptyScreens();
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003462 }
Patrick Dubroyce34a972010-10-19 10:34:32 -07003463 } else if (mDragInfo != null) {
Winson Chung3d503fb2011-07-13 17:25:49 -07003464 CellLayout cellLayout;
3465 if (mLauncher.isHotseatLayout(target)) {
3466 cellLayout = mLauncher.getHotseat().getLayout();
3467 } else {
Adam Cohendcd297f2013-06-18 13:13:40 -07003468 cellLayout = getScreenWithId(mDragInfo.screenId);
Winson Chung3d503fb2011-07-13 17:25:49 -07003469 }
3470 cellLayout.onDropChild(mDragInfo.cell);
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003471 }
Michael Jurka1e2f4652013-07-08 18:03:46 -07003472 if ((d.cancelled || (beingCalledAfterUninstall && !mUninstallSuccessful))
3473 && mDragInfo.cell != null) {
3474 mDragInfo.cell.setVisibility(VISIBLE);
Adam Cohen36cc09b2011-09-29 17:33:15 -07003475 }
Joe Onorato4be866d2010-10-10 11:26:02 -07003476 mDragOutline = null;
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003477 mDragInfo = null;
3478 }
3479
Michael Jurka1e2f4652013-07-08 18:03:46 -07003480 public void deferCompleteDropAfterUninstallActivity() {
3481 mDeferDropAfterUninstall = true;
3482 }
3483
3484 /// maybe move this into a smaller part
3485 public void onUninstallActivityReturned(boolean success) {
3486 mDeferDropAfterUninstall = false;
3487 mUninstallSuccessful = success;
3488 if (mDeferredAction != null) {
3489 mDeferredAction.run();
3490 }
3491 }
3492
Adam Cohenea889a22012-03-27 16:45:39 -07003493 void updateItemLocationsInDatabase(CellLayout cl) {
Michael Jurkaa52570f2012-03-20 03:18:20 -07003494 int count = cl.getShortcutsAndWidgets().getChildCount();
Adam Cohend3461712012-03-29 17:25:17 -07003495
Adam Cohendcd297f2013-06-18 13:13:40 -07003496 long screenId = getIdForScreen(cl);
Adam Cohend3461712012-03-29 17:25:17 -07003497 int container = Favorites.CONTAINER_DESKTOP;
3498
3499 if (mLauncher.isHotseatLayout(cl)) {
Adam Cohendcd297f2013-06-18 13:13:40 -07003500 screenId = -1;
Adam Cohend3461712012-03-29 17:25:17 -07003501 container = Favorites.CONTAINER_HOTSEAT;
3502 }
3503
Adam Cohen482ed822012-03-02 14:15:13 -08003504 for (int i = 0; i < count; i++) {
Michael Jurkaa52570f2012-03-20 03:18:20 -07003505 View v = cl.getShortcutsAndWidgets().getChildAt(i);
Adam Cohen482ed822012-03-02 14:15:13 -08003506 ItemInfo info = (ItemInfo) v.getTag();
Adam Cohen2acce882012-03-28 19:03:19 -07003507 // Null check required as the AllApps button doesn't have an item info
Adam Cohen487f7dd2012-06-28 18:12:10 -07003508 if (info != null && info.requiresDbUpdate) {
3509 info.requiresDbUpdate = false;
Adam Cohendcd297f2013-06-18 13:13:40 -07003510 LauncherModel.modifyItemInDatabase(mLauncher, info, container, screenId, info.cellX,
Adam Cohenbebf0422012-04-11 18:06:28 -07003511 info.cellY, info.spanX, info.spanY);
Adam Cohen2acce882012-03-28 19:03:19 -07003512 }
Adam Cohen482ed822012-03-02 14:15:13 -08003513 }
3514 }
3515
Adam Cohena0b57492013-06-14 15:33:35 -07003516 ArrayList<ComponentName> stripDuplicateApps() {
Adam Cohene25af792013-06-06 23:08:25 -07003517 ArrayList<ComponentName> uniqueIntents = new ArrayList<ComponentName>();
Adam Cohena0b57492013-06-14 15:33:35 -07003518 stripDuplicateApps((CellLayout) mLauncher.getHotseat().getLayout(), uniqueIntents);
Adam Cohene25af792013-06-06 23:08:25 -07003519 int count = getChildCount();
3520 for (int i = 0; i < count; i++) {
3521 CellLayout cl = (CellLayout) getChildAt(i);
Adam Cohena0b57492013-06-14 15:33:35 -07003522 stripDuplicateApps(cl, uniqueIntents);
Adam Cohene25af792013-06-06 23:08:25 -07003523 }
3524 return uniqueIntents;
3525 }
3526
Adam Cohena0b57492013-06-14 15:33:35 -07003527 void stripDuplicateApps(CellLayout cl, ArrayList<ComponentName> uniqueIntents) {
Adam Cohene25af792013-06-06 23:08:25 -07003528 int count = cl.getShortcutsAndWidgets().getChildCount();
3529
3530 ArrayList<View> children = new ArrayList<View>();
3531 for (int i = 0; i < count; i++) {
3532 View v = cl.getShortcutsAndWidgets().getChildAt(i);
3533 children.add(v);
3534 }
3535
3536 for (int i = 0; i < count; i++) {
3537 View v = children.get(i);
3538 ItemInfo info = (ItemInfo) v.getTag();
3539 // Null check required as the AllApps button doesn't have an item info
3540 if (info instanceof ShortcutInfo) {
3541 ShortcutInfo si = (ShortcutInfo) info;
3542 ComponentName cn = si.intent.getComponent();
3543
Adam Cohena0b57492013-06-14 15:33:35 -07003544 if (si.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) {
Adam Cohen99894d92013-06-14 11:22:59 -07003545 continue;
3546 }
Adam Cohena0b57492013-06-14 15:33:35 -07003547
Adam Cohene25af792013-06-06 23:08:25 -07003548 if (!uniqueIntents.contains(cn)) {
3549 uniqueIntents.add(cn);
3550 } else {
3551 cl.removeViewInLayout(v);
3552 LauncherModel.deleteItemFromDatabase(mLauncher, si);
3553 }
3554 }
3555 if (v instanceof FolderIcon) {
3556 FolderIcon fi = (FolderIcon) v;
3557 ArrayList<View> items = fi.getFolder().getItemsInReadingOrder();
3558 for (int j = 0; j < items.size(); j++) {
3559 if (items.get(j).getTag() instanceof ShortcutInfo) {
3560 ShortcutInfo si = (ShortcutInfo) items.get(j).getTag();
3561 ComponentName cn = si.intent.getComponent();
3562
Adam Cohena0b57492013-06-14 15:33:35 -07003563 if (si.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) {
Adam Cohen99894d92013-06-14 11:22:59 -07003564 continue;
3565 }
Adam Cohene25af792013-06-06 23:08:25 -07003566 if (!uniqueIntents.contains(cn)) {
3567 uniqueIntents.add(cn);
3568 } else {
3569 fi.getFolderInfo().remove(si);
3570 LauncherModel.deleteItemFromDatabase(mLauncher, si);
3571 }
3572 }
3573 }
3574 }
3575 }
3576 }
3577
3578 void saveWorkspaceToDb() {
3579 saveWorkspaceScreenToDb((CellLayout) mLauncher.getHotseat().getLayout());
3580 int count = getChildCount();
3581 for (int i = 0; i < count; i++) {
3582 CellLayout cl = (CellLayout) getChildAt(i);
3583 saveWorkspaceScreenToDb(cl);
3584 }
3585 }
3586
3587 void saveWorkspaceScreenToDb(CellLayout cl) {
3588 int count = cl.getShortcutsAndWidgets().getChildCount();
3589
Adam Cohendcd297f2013-06-18 13:13:40 -07003590 long screenId = getIdForScreen(cl);
Adam Cohene25af792013-06-06 23:08:25 -07003591 int container = Favorites.CONTAINER_DESKTOP;
3592
Winson Chungf70696d2013-06-25 16:19:53 -07003593 Hotseat hotseat = mLauncher.getHotseat();
Adam Cohene25af792013-06-06 23:08:25 -07003594 if (mLauncher.isHotseatLayout(cl)) {
Adam Cohendcd297f2013-06-18 13:13:40 -07003595 screenId = -1;
Adam Cohene25af792013-06-06 23:08:25 -07003596 container = Favorites.CONTAINER_HOTSEAT;
3597 }
3598
3599 for (int i = 0; i < count; i++) {
3600 View v = cl.getShortcutsAndWidgets().getChildAt(i);
3601 ItemInfo info = (ItemInfo) v.getTag();
3602 // Null check required as the AllApps button doesn't have an item info
3603 if (info != null) {
Winson Chungf70696d2013-06-25 16:19:53 -07003604 int cellX = info.cellX;
3605 int cellY = info.cellY;
3606 if (container == Favorites.CONTAINER_HOTSEAT) {
3607 cellX = hotseat.getCellXFromOrder((int) info.screenId);
3608 cellY = hotseat.getCellYFromOrder((int) info.screenId);
3609 }
3610 LauncherModel.addItemToDatabase(mLauncher, info, container, screenId, cellX,
3611 cellY, false);
Adam Cohene25af792013-06-06 23:08:25 -07003612 }
3613 if (v instanceof FolderIcon) {
3614 FolderIcon fi = (FolderIcon) v;
3615 fi.getFolder().addItemLocationsInDatabase();
3616 }
3617 }
3618 }
3619
Winson Chunga48487a2012-03-20 16:19:37 -07003620 @Override
Winson Chung043f2af2012-03-01 16:09:54 -08003621 public boolean supportsFlingToDelete() {
3622 return true;
3623 }
3624
Winson Chunga48487a2012-03-20 16:19:37 -07003625 @Override
3626 public void onFlingToDelete(DragObject d, int x, int y, PointF vec) {
3627 // Do nothing
3628 }
3629
3630 @Override
3631 public void onFlingToDeleteCompleted() {
3632 // Do nothing
3633 }
3634
Michael Jurka0280c3b2010-09-17 15:00:07 -07003635 public boolean isDropEnabled() {
3636 return true;
3637 }
3638
Michael Jurka0142d492010-08-25 17:46:15 -07003639 @Override
3640 protected void onRestoreInstanceState(Parcelable state) {
3641 super.onRestoreInstanceState(state);
3642 Launcher.setScreen(mCurrentPage);
3643 }
3644
3645 @Override
Adam Cohen1462de32012-07-24 22:34:36 -07003646 protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
3647 // We don't dispatch restoreInstanceState to our children using this code path.
3648 // Some pages will be restored immediately as their items are bound immediately, and
3649 // others we will need to wait until after their items are bound.
3650 mSavedStates = container;
3651 }
3652
3653 public void restoreInstanceStateForChild(int child) {
3654 if (mSavedStates != null) {
3655 mRestoredPages.add(child);
3656 CellLayout cl = (CellLayout) getChildAt(child);
3657 cl.restoreInstanceState(mSavedStates);
3658 }
3659 }
3660
3661 public void restoreInstanceStateForRemainingPages() {
3662 int count = getChildCount();
3663 for (int i = 0; i < count; i++) {
3664 if (!mRestoredPages.contains(i)) {
3665 restoreInstanceStateForChild(i);
3666 }
3667 }
3668 mRestoredPages.clear();
3669 }
3670
3671 @Override
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003672 public void scrollLeft() {
Michael Jurkad74c9842011-07-10 12:44:21 -07003673 if (!isSmall() && !mIsSwitchingState) {
Michael Jurka0142d492010-08-25 17:46:15 -07003674 super.scrollLeft();
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003675 }
Adam Cohen95bb8002011-07-03 23:40:28 -07003676 Folder openFolder = getOpenFolder();
3677 if (openFolder != null) {
3678 openFolder.completeDragExit();
3679 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003680 }
3681
Michael Jurka0142d492010-08-25 17:46:15 -07003682 @Override
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003683 public void scrollRight() {
Michael Jurkad74c9842011-07-10 12:44:21 -07003684 if (!isSmall() && !mIsSwitchingState) {
Michael Jurka0142d492010-08-25 17:46:15 -07003685 super.scrollRight();
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003686 }
Adam Cohen95bb8002011-07-03 23:40:28 -07003687 Folder openFolder = getOpenFolder();
3688 if (openFolder != null) {
3689 openFolder.completeDragExit();
3690 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003691 }
3692
Patrick Dubroy1262e362010-10-06 15:49:50 -07003693 @Override
Winson Chung3e0839e2011-10-03 15:15:18 -07003694 public boolean onEnterScrollArea(int x, int y, int direction) {
Winson Chung1c4cf4a2011-07-29 14:49:10 -07003695 // Ignore the scroll area if we are dragging over the hot seat
Daniel Sandlercc8befa2013-06-11 14:45:48 -04003696 boolean isPortrait = !LauncherAppState.isScreenLandscape(getContext());
Winson Chung10bfc6e2012-03-28 15:41:26 -07003697 if (mLauncher.getHotseat() != null && isPortrait) {
Winson Chung1c4cf4a2011-07-29 14:49:10 -07003698 Rect r = new Rect();
3699 mLauncher.getHotseat().getHitRect(r);
3700 if (r.contains(x, y)) {
Winson Chung3e0839e2011-10-03 15:15:18 -07003701 return false;
Winson Chung1c4cf4a2011-07-29 14:49:10 -07003702 }
3703 }
3704
Winson Chung3e0839e2011-10-03 15:15:18 -07003705 boolean result = false;
Adam Cohen61a9a5c2013-08-14 13:32:04 -07003706 if (!isSmall() && !mIsSwitchingState && getOpenFolder() == null) {
Michael Jurkad718d6a2010-10-14 15:35:17 -07003707 mInScrollArea = true;
Patrick Dubroy54fa3b92010-11-17 12:18:45 -08003708
Winson Chung360e63f2012-04-27 13:48:05 -07003709 final int page = getNextPage() +
Winson Chungaa15ffe2012-01-18 15:45:28 -08003710 (direction == DragController.SCROLL_LEFT ? -1 : 1);
Adam Cohenc6cc61d2012-04-04 12:47:08 -07003711 // We always want to exit the current layout to ensure parity of enter / exit
3712 setCurrentDropLayout(null);
Patrick Dubroy54fa3b92010-11-17 12:18:45 -08003713
Winson Chungaa15ffe2012-01-18 15:45:28 -08003714 if (0 <= page && page < getChildCount()) {
Winson Chung482a5b62013-07-31 17:19:51 -07003715 // Ensure that we are not dragging over to the custom content screen
3716 if (getScreenIdForPageIndex(page) == CUSTOM_CONTENT_SCREEN_ID) {
3717 return false;
3718 }
3719
Winson Chungaa15ffe2012-01-18 15:45:28 -08003720 CellLayout layout = (CellLayout) getChildAt(page);
Adam Cohenc6cc61d2012-04-04 12:47:08 -07003721 setCurrentDragOverlappingLayout(layout);
Winson Chungc07918d2011-07-01 15:35:26 -07003722
3723 // Workspace is responsible for drawing the edge glow on adjacent pages,
3724 // so we need to redraw the workspace when this may have changed.
3725 invalidate();
Winson Chung3e0839e2011-10-03 15:15:18 -07003726 result = true;
Michael Jurkad718d6a2010-10-14 15:35:17 -07003727 }
Patrick Dubroy1262e362010-10-06 15:49:50 -07003728 }
Winson Chung3e0839e2011-10-03 15:15:18 -07003729 return result;
Patrick Dubroy1262e362010-10-06 15:49:50 -07003730 }
3731
3732 @Override
Winson Chung3e0839e2011-10-03 15:15:18 -07003733 public boolean onExitScrollArea() {
3734 boolean result = false;
Michael Jurkad718d6a2010-10-14 15:35:17 -07003735 if (mInScrollArea) {
Adam Cohenc6cc61d2012-04-04 12:47:08 -07003736 invalidate();
3737 CellLayout layout = getCurrentDropLayout();
3738 setCurrentDropLayout(layout);
3739 setCurrentDragOverlappingLayout(layout);
3740
Adam Cohen8a18afc2011-12-13 15:57:01 -08003741 result = true;
Winson Chungc07918d2011-07-01 15:35:26 -07003742 mInScrollArea = false;
Patrick Dubroy1262e362010-10-06 15:49:50 -07003743 }
Winson Chung3e0839e2011-10-03 15:15:18 -07003744 return result;
Patrick Dubroy1262e362010-10-06 15:49:50 -07003745 }
3746
Winson Chungc07918d2011-07-01 15:35:26 -07003747 private void onResetScrollArea() {
Adam Cohenc6cc61d2012-04-04 12:47:08 -07003748 setCurrentDragOverlappingLayout(null);
Winson Chungc07918d2011-07-01 15:35:26 -07003749 mInScrollArea = false;
3750 }
3751
Winson Chung3d503fb2011-07-13 17:25:49 -07003752 /**
3753 * Returns a specific CellLayout
3754 */
3755 CellLayout getParentCellLayoutForView(View v) {
3756 ArrayList<CellLayout> layouts = getWorkspaceAndHotseatCellLayouts();
3757 for (CellLayout layout : layouts) {
Michael Jurkaa52570f2012-03-20 03:18:20 -07003758 if (layout.getShortcutsAndWidgets().indexOfChild(v) > -1) {
Winson Chung3d503fb2011-07-13 17:25:49 -07003759 return layout;
3760 }
3761 }
3762 return null;
3763 }
3764
3765 /**
3766 * Returns a list of all the CellLayouts in the workspace.
3767 */
3768 ArrayList<CellLayout> getWorkspaceAndHotseatCellLayouts() {
3769 ArrayList<CellLayout> layouts = new ArrayList<CellLayout>();
3770 int screenCount = getChildCount();
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003771 for (int screen = 0; screen < screenCount; screen++) {
Winson Chung3d503fb2011-07-13 17:25:49 -07003772 layouts.add(((CellLayout) getChildAt(screen)));
3773 }
3774 if (mLauncher.getHotseat() != null) {
3775 layouts.add(mLauncher.getHotseat().getLayout());
3776 }
3777 return layouts;
3778 }
3779
3780 /**
3781 * We should only use this to search for specific children. Do not use this method to modify
Michael Jurkaa52570f2012-03-20 03:18:20 -07003782 * ShortcutsAndWidgetsContainer directly. Includes ShortcutAndWidgetContainers from
3783 * the hotseat and workspace pages
Winson Chung3d503fb2011-07-13 17:25:49 -07003784 */
Michael Jurkaa52570f2012-03-20 03:18:20 -07003785 ArrayList<ShortcutAndWidgetContainer> getAllShortcutAndWidgetContainers() {
3786 ArrayList<ShortcutAndWidgetContainer> childrenLayouts =
3787 new ArrayList<ShortcutAndWidgetContainer>();
Winson Chung3d503fb2011-07-13 17:25:49 -07003788 int screenCount = getChildCount();
3789 for (int screen = 0; screen < screenCount; screen++) {
Michael Jurkaa52570f2012-03-20 03:18:20 -07003790 childrenLayouts.add(((CellLayout) getChildAt(screen)).getShortcutsAndWidgets());
Winson Chung3d503fb2011-07-13 17:25:49 -07003791 }
3792 if (mLauncher.getHotseat() != null) {
Michael Jurkaa52570f2012-03-20 03:18:20 -07003793 childrenLayouts.add(mLauncher.getHotseat().getLayout().getShortcutsAndWidgets());
Winson Chung3d503fb2011-07-13 17:25:49 -07003794 }
3795 return childrenLayouts;
3796 }
3797
3798 public Folder getFolderForTag(Object tag) {
Michael Jurkaa52570f2012-03-20 03:18:20 -07003799 ArrayList<ShortcutAndWidgetContainer> childrenLayouts =
3800 getAllShortcutAndWidgetContainers();
3801 for (ShortcutAndWidgetContainer layout: childrenLayouts) {
Winson Chung3d503fb2011-07-13 17:25:49 -07003802 int count = layout.getChildCount();
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003803 for (int i = 0; i < count; i++) {
Winson Chung3d503fb2011-07-13 17:25:49 -07003804 View child = layout.getChildAt(i);
Winson Chung3d503fb2011-07-13 17:25:49 -07003805 if (child instanceof Folder) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003806 Folder f = (Folder) child;
Winson Chungaafa03c2010-06-11 17:34:16 -07003807 if (f.getInfo() == tag && f.getInfo().opened) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003808 return f;
3809 }
3810 }
3811 }
3812 }
3813 return null;
3814 }
3815
3816 public View getViewForTag(Object tag) {
Michael Jurkaa52570f2012-03-20 03:18:20 -07003817 ArrayList<ShortcutAndWidgetContainer> childrenLayouts =
3818 getAllShortcutAndWidgetContainers();
3819 for (ShortcutAndWidgetContainer layout: childrenLayouts) {
Winson Chung3d503fb2011-07-13 17:25:49 -07003820 int count = layout.getChildCount();
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003821 for (int i = 0; i < count; i++) {
Winson Chung3d503fb2011-07-13 17:25:49 -07003822 View child = layout.getChildAt(i);
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003823 if (child.getTag() == tag) {
3824 return child;
3825 }
3826 }
3827 }
3828 return null;
3829 }
3830
Adam Cohendf035382011-04-11 17:22:04 -07003831 void clearDropTargets() {
Michael Jurkaa52570f2012-03-20 03:18:20 -07003832 ArrayList<ShortcutAndWidgetContainer> childrenLayouts =
3833 getAllShortcutAndWidgetContainers();
3834 for (ShortcutAndWidgetContainer layout: childrenLayouts) {
Adam Cohendf035382011-04-11 17:22:04 -07003835 int childCount = layout.getChildCount();
3836 for (int j = 0; j < childCount; j++) {
3837 View v = layout.getChildAt(j);
3838 if (v instanceof DropTarget) {
3839 mDragController.removeDropTarget((DropTarget) v);
3840 }
3841 }
3842 }
3843 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003844
Winson Chung83892cc2013-05-01 16:53:33 -07003845 // Removes ALL items that match a given package name, this is usually called when a package
3846 // has been removed and we want to remove all components (widgets, shortcuts, apps) that
3847 // belong to that package.
3848 void removeItemsByPackageName(final ArrayList<String> packages) {
Winson Chung64359a52013-07-08 17:17:08 -07003849 final HashSet<String> packageNames = new HashSet<String>();
Winson Chungcd810732012-06-18 16:45:43 -07003850 packageNames.addAll(packages);
Joe Onorato64e6be72010-03-05 15:05:52 -05003851
Winson Chung64359a52013-07-08 17:17:08 -07003852 // Filter out all the ItemInfos that this is going to affect
3853 final HashSet<ItemInfo> infos = new HashSet<ItemInfo>();
3854 final HashSet<ComponentName> cns = new HashSet<ComponentName>();
Winson Chung83892cc2013-05-01 16:53:33 -07003855 ArrayList<CellLayout> cellLayouts = getWorkspaceAndHotseatCellLayouts();
3856 for (CellLayout layoutParent : cellLayouts) {
3857 ViewGroup layout = layoutParent.getShortcutsAndWidgets();
3858 int childCount = layout.getChildCount();
3859 for (int i = 0; i < childCount; ++i) {
3860 View view = layout.getChildAt(i);
Winson Chung64359a52013-07-08 17:17:08 -07003861 infos.add((ItemInfo) view.getTag());
Winson Chung83892cc2013-05-01 16:53:33 -07003862 }
3863 }
Winson Chung64359a52013-07-08 17:17:08 -07003864 LauncherModel.ItemInfoFilter filter = new LauncherModel.ItemInfoFilter() {
3865 @Override
3866 public boolean filterItem(ItemInfo parent, ItemInfo info,
3867 ComponentName cn) {
3868 if (packageNames.contains(cn.getPackageName())) {
3869 cns.add(cn);
3870 return true;
3871 }
3872 return false;
3873 }
3874 };
3875 LauncherModel.filterItemInfos(infos, filter);
Winson Chung83892cc2013-05-01 16:53:33 -07003876
Winson Chung64359a52013-07-08 17:17:08 -07003877 // Remove the affected components
Winson Chung83892cc2013-05-01 16:53:33 -07003878 removeItemsByComponentName(cns);
3879 }
3880
3881 // Removes items that match the application info specified, when applications are removed
3882 // as a part of an update, this is called to ensure that other widgets and application
3883 // shortcuts are not removed.
3884 void removeItemsByApplicationInfo(final ArrayList<ApplicationInfo> appInfos) {
3885 // Just create a hash table of all the specific components that this will affect
3886 HashSet<ComponentName> cns = new HashSet<ComponentName>();
3887 for (ApplicationInfo info : appInfos) {
3888 cns.add(info.componentName);
3889 }
3890
3891 // Remove all the things
3892 removeItemsByComponentName(cns);
3893 }
3894
3895 void removeItemsByComponentName(final HashSet<ComponentName> componentNames) {
Winson Chung3d503fb2011-07-13 17:25:49 -07003896 ArrayList<CellLayout> cellLayouts = getWorkspaceAndHotseatCellLayouts();
3897 for (final CellLayout layoutParent: cellLayouts) {
Michael Jurkaa52570f2012-03-20 03:18:20 -07003898 final ViewGroup layout = layoutParent.getShortcutsAndWidgets();
Romain Guy574d20e2009-06-01 15:34:04 -07003899
Winson Chung64359a52013-07-08 17:17:08 -07003900 final HashMap<ItemInfo, View> children = new HashMap<ItemInfo, View>();
3901 for (int j = 0; j < layout.getChildCount(); j++) {
3902 final View view = layout.getChildAt(j);
3903 children.put((ItemInfo) view.getTag(), view);
3904 }
Winson Chungaafa03c2010-06-11 17:34:16 -07003905
Winson Chung64359a52013-07-08 17:17:08 -07003906 final ArrayList<View> childrenToRemove = new ArrayList<View>();
3907 final HashMap<FolderInfo, ArrayList<ShortcutInfo>> folderAppsToRemove =
3908 new HashMap<FolderInfo, ArrayList<ShortcutInfo>>();
3909 LauncherModel.ItemInfoFilter filter = new LauncherModel.ItemInfoFilter() {
3910 @Override
3911 public boolean filterItem(ItemInfo parent, ItemInfo info,
3912 ComponentName cn) {
3913 if (parent instanceof FolderInfo) {
3914 if (componentNames.contains(cn)) {
3915 FolderInfo folder = (FolderInfo) parent;
3916 ArrayList<ShortcutInfo> appsToRemove;
3917 if (folderAppsToRemove.containsKey(folder)) {
3918 appsToRemove = folderAppsToRemove.get(folder);
3919 } else {
3920 appsToRemove = new ArrayList<ShortcutInfo>();
3921 folderAppsToRemove.put(folder, appsToRemove);
Romain Guy629de3e2010-01-13 12:20:59 -08003922 }
Winson Chung64359a52013-07-08 17:17:08 -07003923 appsToRemove.add((ShortcutInfo) info);
3924 return true;
3925 }
3926 } else {
3927 if (componentNames.contains(cn)) {
3928 childrenToRemove.add(children.get(info));
3929 return true;
Romain Guy574d20e2009-06-01 15:34:04 -07003930 }
3931 }
Winson Chung64359a52013-07-08 17:17:08 -07003932 return false;
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003933 }
Winson Chung64359a52013-07-08 17:17:08 -07003934 };
3935 LauncherModel.filterItemInfos(children.keySet(), filter);
3936
3937 // Remove all the apps from their folders
3938 for (FolderInfo folder : folderAppsToRemove.keySet()) {
3939 ArrayList<ShortcutInfo> appsToRemove = folderAppsToRemove.get(folder);
3940 for (ShortcutInfo info : appsToRemove) {
3941 folder.remove(info);
3942 }
3943 }
3944
3945 // Remove all the other children
3946 for (View child : childrenToRemove) {
3947 // Note: We can not remove the view directly from CellLayoutChildren as this
3948 // does not re-mark the spaces as unoccupied.
3949 layoutParent.removeViewInLayout(child);
3950 if (child instanceof DropTarget) {
3951 mDragController.removeDropTarget((DropTarget) child);
3952 }
3953 }
3954
3955 if (childrenToRemove.size() > 0) {
3956 layout.requestLayout();
3957 layout.invalidate();
3958 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003959 }
Winson Chung2efec4e2012-05-03 12:31:48 -07003960
Winson Chung64359a52013-07-08 17:17:08 -07003961 // Strip all the empty screens
3962 stripEmptyScreens();
The Android Open Source Project31dd5032009-03-03 19:32:27 -08003963 }
The Android Open Source Projectf96811c2009-03-18 17:39:48 -07003964
Joe Onorato64e6be72010-03-05 15:05:52 -05003965 void updateShortcuts(ArrayList<ApplicationInfo> apps) {
Michael Jurkaa52570f2012-03-20 03:18:20 -07003966 ArrayList<ShortcutAndWidgetContainer> childrenLayouts = getAllShortcutAndWidgetContainers();
3967 for (ShortcutAndWidgetContainer layout: childrenLayouts) {
The Android Open Source Projectf96811c2009-03-18 17:39:48 -07003968 int childCount = layout.getChildCount();
3969 for (int j = 0; j < childCount; j++) {
3970 final View view = layout.getChildAt(j);
3971 Object tag = view.getTag();
Winson Chung64359a52013-07-08 17:17:08 -07003972
3973 if (LauncherModel.isShortcutInfoUpdateable((ItemInfo) tag)) {
Michael Jurkae384aff2012-03-09 15:59:25 -08003974 ShortcutInfo info = (ShortcutInfo) tag;
Winson Chung64359a52013-07-08 17:17:08 -07003975
The Android Open Source Projectf96811c2009-03-18 17:39:48 -07003976 final Intent intent = info.intent;
3977 final ComponentName name = intent.getComponent();
Winson Chung64359a52013-07-08 17:17:08 -07003978 final int appCount = apps.size();
3979 for (int k = 0; k < appCount; k++) {
3980 ApplicationInfo app = apps.get(k);
3981 if (app.componentName.equals(name)) {
3982 BubbleTextView shortcut = (BubbleTextView) view;
3983 info.updateIcon(mIconCache);
3984 info.title = app.title.toString();
3985 shortcut.applyFromShortcutInfo(info, mIconCache);
Joe Onorato64e6be72010-03-05 15:05:52 -05003986 }
The Android Open Source Projectf96811c2009-03-18 17:39:48 -07003987 }
3988 }
3989 }
3990 }
3991 }
3992
Joe Onorato14f122b2009-11-19 14:06:36 -08003993 void moveToDefaultScreen(boolean animate) {
Winson Chungde1af762011-07-21 16:44:07 -07003994 if (!isSmall()) {
3995 if (animate) {
3996 snapToPage(mDefaultPage);
3997 } else {
3998 setCurrentPage(mDefaultPage);
3999 }
Joe Onoratoc45b1682010-01-11 18:48:40 -05004000 }
Winson Chung64359a52013-07-08 17:17:08 -07004001 View child = getChildAt(mDefaultPage);
4002 if (child != null) {
4003 child.requestFocus();
4004 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -08004005 }
4006
Michael Jurka0142d492010-08-25 17:46:15 -07004007 @Override
Winson Chung82dfe582013-07-26 15:07:49 -07004008 protected int getPageIndicatorMarker(int pageIndex) {
4009 if (getScreenIdForPageIndex(pageIndex) == CUSTOM_CONTENT_SCREEN_ID) {
Winson Chung5f8afe62013-08-12 16:19:28 -07004010 return R.layout.custom_content_page_indicator_marker;
Winson Chung82dfe582013-07-26 15:07:49 -07004011 }
4012 return super.getPageIndicatorMarker(pageIndex);
4013 }
4014
4015 @Override
Michael Jurka0142d492010-08-25 17:46:15 -07004016 public void syncPages() {
The Android Open Source Project31dd5032009-03-03 19:32:27 -08004017 }
Michael Jurka0142d492010-08-25 17:46:15 -07004018
4019 @Override
Winson Chungf314b0e2011-08-16 11:54:27 -07004020 public void syncPageItems(int page, boolean immediate) {
Michael Jurka0142d492010-08-25 17:46:15 -07004021 }
Winson Chung6a0f57d2011-06-29 20:10:49 -07004022
Winson Chung6a0f57d2011-06-29 20:10:49 -07004023 protected String getCurrentPageDescription() {
4024 int page = (mNextPage != INVALID_PAGE) ? mNextPage : mCurrentPage;
Michael Jurka8b805b12012-04-18 14:23:14 -07004025 return String.format(getContext().getString(R.string.workspace_scroll_format),
Winson Chung6a0f57d2011-06-29 20:10:49 -07004026 page + 1, getChildCount());
4027 }
Adam Cohen8dfcba42011-07-07 16:38:18 -07004028
4029 public void getLocationInDragLayer(int[] loc) {
4030 mLauncher.getDragLayer().getLocationInDragLayer(this, loc);
4031 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -08004032}