Workspace.java revision 6c8a5790820dbcb64568fdefc8464a8d971847f0
131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project/*
231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project *
431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * you may not use this file except in compliance with the License.
631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * You may obtain a copy of the License at
731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project *
831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project *
1031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
1131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
1231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * See the License for the specific language governing permissions and
1431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * limitations under the License.
1531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */
1631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
17a5902524d4403885eb4c50360bf3465c6be796efJoe Onoratopackage com.android.launcher2;
1831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
190280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurkaimport android.animation.Animator;
2070fc438583779ef903541bf9ec546a8235a18785Winson Chungimport android.animation.AnimatorSet;
218edd75c8bb0729a10cb39f614183e3e9ae4288e8Michael Jurkaimport android.animation.ObjectAnimator;
22b1254a6bdb11024042fb6c27e179210c1bbd6e1cChet Haaseimport android.animation.TimeInterpolator;
230280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurkaimport android.animation.ValueAnimator;
24cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroyimport android.animation.ValueAnimator.AnimatorUpdateListener;
25cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroyimport android.app.WallpaperManager;
26cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroyimport android.appwidget.AppWidgetHostView;
2768846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chungimport android.appwidget.AppWidgetManager;
288f573952b8729b4319043ae0908997ecd2d68951Dianne Hackbornimport android.appwidget.AppWidgetProviderInfo;
29629de3ef739883c0962423cc0c3a26299f162d3dRomain Guyimport android.content.ClipDescription;
30629de3ef739883c0962423cc0c3a26299f162d3dRomain Guyimport android.content.ComponentName;
31a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chungimport android.content.Context;
32a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chungimport android.content.Intent;
33495f2892288504f4ab87e62957b3f71144dd73c2Adam Powellimport android.content.res.Resources;
3431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.content.res.TypedArray;
3531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.graphics.Bitmap;
367247f6315baf16eacb3286f21bd80321385c1defPatrick Dubroyimport android.graphics.Camera;
3731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.graphics.Canvas;
384be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onoratoimport android.graphics.Matrix;
396b879f0a5885274a85333531e091283405d490ccAdam Lesinskiimport android.graphics.Paint;
4031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.graphics.Point;
41a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurkaimport android.graphics.PointF;
42a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chungimport android.graphics.Rect;
4370fc438583779ef903541bf9ec546a8235a18785Winson Chungimport android.graphics.Region.Op;
4431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.graphics.drawable.Drawable;
45a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chungimport android.os.IBinder;
464be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onoratoimport android.os.Parcelable;
47f96811cdf564469a7a654a0c876288c9fd14f35eThe Android Open Source Projectimport android.util.AttributeSet;
48956091ba7863bd72086275e61084864994dd6fa7Joe Onoratoimport android.util.DisplayMetrics;
49495f2892288504f4ab87e62957b3f71144dd73c2Adam Powellimport android.util.Log;
5031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.util.Pair;
51b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chungimport android.view.Display;
52291ad12232c98e383d44d76ffe09e97e204c61bcDaniel Sandlerimport android.view.DragEvent;
53580e27748137ff08599aa719d106b31215a28353Winson Chungimport android.view.MotionEvent;
54a34abf8c781485b788fddacb352d586bffca886cWinson Chungimport android.view.View;
55a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chungimport android.view.ViewGroup;
5631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.animation.AccelerateInterpolator;
5731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.animation.DecelerateInterpolator;
586e3140865d3f0def2e55934d8b0b2c1503386e54Winson Chungimport android.widget.ImageView;
59cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroyimport android.widget.TextView;
60a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung
61f96811cdf564469a7a654a0c876288c9fd14f35eThe Android Open Source Projectimport com.android.launcher.R;
62a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chungimport com.android.launcher2.FolderIcon.FolderRingAnimator;
6331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport com.android.launcher2.InstallWidgetReceiver.WidgetMimeTypeHandlerData;
646639687cd67bab1aeef2a75e5c6bc458b20dc082Adam Cohenimport com.android.launcher2.LauncherSettings.Favorites;
6519072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen
666639687cd67bab1aeef2a75e5c6bc458b20dc082Adam Cohenimport java.util.ArrayList;
67edcce099c98a6c40d10109ac092ab50f9d2668f3Romain Guyimport java.util.HashSet;
68716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohenimport java.util.List;
69716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
70716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen/**
71716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen * The workspace is a wide area with a wallpaper and a finite number of pages.
7231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Each page contains a number of icons, folders or widgets the user can
730142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka * interact with. A workspace is meant to be used with a fixed width only.
740142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka */
75aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chungpublic class Workspace extends SmoothPagedView
7631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        implements DropTarget, DragSource, DragScroller, View.OnTouchListener,
770142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka        DragController.DragListener, LauncherTransitionable {
78d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka    @SuppressWarnings({"UnusedDeclaration"})
79d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka    private static final String TAG = "Launcher.Workspace";
80e47f55c30b9c24f01f2be861247c92f17fbe4a61Romain Guy
813a8820bdbad90642cf5cda4b00a8c92ecb699159Joe Onorato    // Y rotation to apply to the workspace screens
820142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka    private static final float WORKSPACE_ROTATION = 12.5f;
83f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen    private static final float WORKSPACE_OVERSCROLL_ROTATION = 24f;
84f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen    private static float CAMERA_DISTANCE = 6500;
85a985e598f6071f4caca15ba3cb6b2cd3e38b217dAdam Cohen
86a985e598f6071f4caca15ba3cb6b2cd3e38b217dAdam Cohen    private static final int CHILDREN_OUTLINE_FADE_OUT_DELAY = 0;
87a985e598f6071f4caca15ba3cb6b2cd3e38b217dAdam Cohen    private static final int CHILDREN_OUTLINE_FADE_OUT_DURATION = 375;
881b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen    private static final int CHILDREN_OUTLINE_FADE_IN_DURATION = 100;
89a985e598f6071f4caca15ba3cb6b2cd3e38b217dAdam Cohen
901b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen    private static final int BACKGROUND_FADE_OUT_DURATION = 350;
91a985e598f6071f4caca15ba3cb6b2cd3e38b217dAdam Cohen    private static final int ADJACENT_SCREEN_DROP_DURATION = 300;
9268d739365bf650fe7fecf99cd3bfe63a0d41bd12Adam Cohen    private static final int FLING_THRESHOLD_VELOCITY = 500;
9368d739365bf650fe7fecf99cd3bfe63a0d41bd12Adam Cohen
949171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung    private float mMaxDistanceForFolderCreation = 50.0f;
95f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen
96f135c6c364e92cddb84c1b4a94ed535214b712a6Winson Chung    // These animators are used to fade the children's outlines
979171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung    private ObjectAnimator mChildrenOutlineFadeInAnimation;
989171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung    private ObjectAnimator mChildrenOutlineFadeOutAnimation;
99ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen    private float mChildrenOutlineAlpha = 0;
100ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen
1019171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung    // These properties refer to the background protection gradient used for AllApps and Customize
1029171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung    private ValueAnimator mBackgroundFadeInAnimation;
1039171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung    private ValueAnimator mBackgroundFadeOutAnimation;
1049171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung    private Drawable mBackground;
1059171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung    boolean mDrawBackground = true;
1069171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung    private float mBackgroundAlpha = 0;
107e0f5a61a1f105216b0067124bacac69194c0ef70Michael Jurka    private float mOverScrollMaxBackgroundAlpha = 0.0f;
108e0f5a61a1f105216b0067124bacac69194c0ef70Michael Jurka    private int mOverScrollPageIndex = -1;
1099171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung
11025356e75ebae5d6e0be43f38d2c73b5cb59d05f2Michael Jurka    private float mWallpaperScrollRatio = 1.0f;
111f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen
11268d739365bf650fe7fecf99cd3bfe63a0d41bd12Adam Cohen    private final WallpaperManager mWallpaperManager;
113e0f66b546994a9bdee452851c17a148db02ec300Adam Cohen    private IBinder mWindowToken;
114a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung    private static final float WALLPAPER_SCREENS_SPAN = 2f;
115f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen
116beff8c6a13d5b5ad69f5a85ee0150cecd28e6341Adam Cohen    private int mDefaultPage;
117beff8c6a13d5b5ad69f5a85ee0150cecd28e6341Adam Cohen
1188f573952b8729b4319043ae0908997ecd2d68951Dianne Hackborn    /**
1199c6fbed48783dacd9bc6b4ec5f2cc8e59ec7ee37Michael Jurka     * CellInfo for the cell that is currently being dragged
120aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     */
1210142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka    private CellLayout.CellInfo mDragInfo;
12231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
12331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
12431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * Target drop area calculated during last acceptDrop call.
12531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
12631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private int[] mTargetCell = new int[2];
127aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
12870864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey    /**
12970864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey     * The CellLayout that is currently being dragged over
13070864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey     */
131c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen    private CellLayout mDragTargetLayout = null;
13231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private boolean mDragHasEnteredWorkspace = false;
1336569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
1346569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    private Launcher mLauncher;
1356569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    private IconCache mIconCache;
1366569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    private DragController mDragController;
1376569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
13831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    // These are temporary variables to prevent having to allocate a new object just to
1390589f0f66ce498512c6ee47482c649d88294c9d0Joe Onorato    // return an (x, y) value from helper functions. Do NOT use them to maintain other state.
14000acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    private int[] mTempCell = new int[2];
141aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung    private int[] mTempEstimate = new int[2];
1424516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka    private float[] mDragViewVisualCenter = new float[2];
1434516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka    private float[] mTempDragCoordinates = new float[2];
14431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private float[] mTempCellLayoutCenterCoordinates = new float[2];
14570864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey    private float[] mTempDragBottomRightCoordinates = new float[2];
146e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen    private Matrix mTempInverseMatrix = new Matrix();
147a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka
1484516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka    private SpringLoadedDragController mSpringLoadedDragController;
149a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka    private float mSpringLoadedShrinkFactor;
1500280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
15131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private static final int DEFAULT_CELL_COUNT_X = 4;
152c2f7f4794867cd1b3e97fd0f379ad8ad15958a6cMichael Jurka    private static final int DEFAULT_CELL_COUNT_Y = 4;
153b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung
154d3ef3065ab0941567c45e9aec98783138b623c68Michael Jurka    // State variable that indicates whether the pages are small (ie when you're
155d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen    // in all apps or customize mode)
156d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen
15731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    enum State { NORMAL, SPRING_LOADED, SMALL };
1581262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy    private State mState = State.NORMAL;
159dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    private boolean mIsSwitchingState = false;
160d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka
161d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka    boolean mAnimatingViewIntoPlace = false;
1627777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen    boolean mIsDragOccuring = false;
163d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka    boolean mChildrenLayersEnabled = true;
164d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka
165d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka    /** Is the user is dragging an item near the edge of a page? */
166d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka    private boolean mInScrollArea = false;
167d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka
1687777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen    private final HolographicOutlineHelper mOutlineHelper = new HolographicOutlineHelper();
169d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka    private Bitmap mDragOutline = null;
170d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka    private final Rect mTempRect = new Rect();
171d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka    private final int[] mTempXY = new int[2];
172d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka    private float mOverscrollFade = 0;
173dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    public static final int DRAG_BITMAP_PADDING = 0;
17454fa3b95557c283976e8c1aa8a157b460b0b4513Patrick Dubroy
1751262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy    // Camera and Matrix used to determine the final position of a neighboring CellLayout
1761262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy    private final Matrix mMatrix = new Matrix();
1778e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy    private final Camera mCamera = new Camera();
1784be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato    private final float mTempFloat2[] = new float[2];
1798e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy
1808e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy    enum WallpaperVerticalOffset { TOP, MIDDLE, BOTTOM };
18170fc438583779ef903541bf9ec546a8235a18785Winson Chung    int mWallpaperWidth;
1824be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato    int mWallpaperHeight;
183a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung    WallpaperOffsetInterpolator mWallpaperOffset;
184a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung    boolean mUpdateWallpaperOffsetImmediately = false;
185a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung    private Runnable mDelayedResizeRunnable;
1866b879f0a5885274a85333531e091283405d490ccAdam Lesinski    private int mDisplayWidth;
1876b879f0a5885274a85333531e091283405d490ccAdam Lesinski    private int mDisplayHeight;
1886b879f0a5885274a85333531e091283405d490ccAdam Lesinski    private boolean mIsStaticWallpaper;
1896b879f0a5885274a85333531e091283405d490ccAdam Lesinski    private int mWallpaperTravelWidth;
1906b879f0a5885274a85333531e091283405d490ccAdam Lesinski
191c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka    // Variables relating to the creation of user folders by hovering shortcuts over shortcuts
192c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka    private static final int FOLDER_CREATION_TIMEOUT = 0;
193c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka    private static final int REORDER_TIMEOUT = 250;
194ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka    private final Alarm mFolderCreationAlarm = new Alarm();
195c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka    private final Alarm mReorderAlarm = new Alarm();
19626976d9b53161f80faf822d482ac771b8621cf31Adam Cohen    private FolderRingAnimator mDragFolderRingAnimator = null;
197c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka    private View mLastDragOverView = null;
19819072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen    private boolean mCreateUserFolderOnDrop = false;
199c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen
20019072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen    // Variables relating to touch disambiguation (scrolling workspace vs. scrolling a widget)
20119072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen    private float mXDown;
20219072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen    private float mYDown;
20319072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen    final static float START_DAMPING_TOUCH_SLOP_ANGLE = (float) Math.PI / 6;
204073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen    final static float MAX_SWIPE_ANGLE = (float) Math.PI / 3;
205f8d2823d885ba682140aee1ae0504c1c5e67a24bAdam Cohen    final static float TOUCH_SLOP_DAMPING_FACTOR = 4;
206f8d2823d885ba682140aee1ae0504c1c5e67a24bAdam Cohen
207f8d2823d885ba682140aee1ae0504c1c5e67a24bAdam Cohen    // Relating to the animation of items being dropped externally
208f8d2823d885ba682140aee1ae0504c1c5e67a24bAdam Cohen    public static final int ANIMATE_INTO_POSITION_AND_DISAPPEAR = 0;
209f8d2823d885ba682140aee1ae0504c1c5e67a24bAdam Cohen    public static final int ANIMATE_INTO_POSITION_AND_REMAIN = 1;
210f8d2823d885ba682140aee1ae0504c1c5e67a24bAdam Cohen    public static final int ANIMATE_INTO_POSITION_AND_RESIZE = 2;
211f8d2823d885ba682140aee1ae0504c1c5e67a24bAdam Cohen    public static final int COMPLETE_TWO_STAGE_WIDGET_DROP_ANIMATION = 3;
2124b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen    public static final int CANCEL_TWO_STAGE_WIDGET_DROP_ANIMATION = 4;
213ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen
214ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen    // Related to dragging, folder creation and reordering
215ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen    private static final int DRAG_MODE_NONE = 0;
2164b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen    private static final int DRAG_MODE_CREATE_FOLDER = 1;
2174b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen    private static final int DRAG_MODE_ADD_TO_FOLDER = 2;
2184b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen    private static final int DRAG_MODE_REORDER = 3;
2194b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen    private int mDragMode = DRAG_MODE_NONE;
2204b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen    private int mLastReorderX = -1;
2214b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen    private int mLastReorderY = -1;
2224b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen
2234b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen    // Relating to workspace drag fade out
2244b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen    private float mDragFadeOutAlpha;
2254b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen    private int mDragFadeOutDuration;
2264b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen
2274b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen    // These variables are used for storing the initial and final values during workspace animations
2284b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen    private int mSavedScrollX;
2294b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen    private float mSavedRotationY;
2304b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen    private float mSavedTranslationX;
2314b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen    private float mCurrentScaleX;
2324b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen    private float mCurrentScaleY;
2334b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen    private float mCurrentRotationY;
2344b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen    private float mCurrentTranslationX;
2354b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen    private float mCurrentTranslationY;
2364b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen    private float[] mOldTranslationXs;
2374b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen    private float[] mOldTranslationYs;
2384b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen    private float[] mOldScaleXs;
23931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private float[] mOldScaleYs;
24031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private float[] mOldBackgroundAlphas;
24131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private float[] mOldBackgroundAlphaMultipliers;
24231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private float[] mOldAlphas;
2430142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka    private float[] mOldRotationYs;
24431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private float[] mNewTranslationXs;
24531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private float[] mNewTranslationYs;
24631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private float[] mNewScaleXs;
24731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private float[] mNewScaleYs;
24831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private float[] mNewBackgroundAlphas;
24931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private float[] mNewBackgroundAlphaMultipliers;
25031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private float[] mNewAlphas;
25131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private float[] mNewRotationYs;
25231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private float mTransitionProgress;
2530142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka
25431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
25531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * Used to inflate the Workspace from XML.
25631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     *
25731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param context The application's context.
2580142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka     * @param attrs The attributes set containing the Workspace's customization values.
2595f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka     */
260f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung    public Workspace(Context context, AttributeSet attrs) {
261f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung        this(context, attrs, 0);
262f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung    }
2632b8e44577096a737b97c6687fc8ad1f067ea1e89Winson Chung
2642b8e44577096a737b97c6687fc8ad1f067ea1e89Winson Chung    /**
2658f573952b8729b4319043ae0908997ecd2d68951Dianne Hackborn     * Used to inflate the Workspace from XML.
266aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     *
267f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka     * @param context The application's context.
268f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka     * @param attrs The attributes set containing the Workspace's customization values.
269f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka     * @param defStyle Unused.
270aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     */
271aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung    public Workspace(Context context, AttributeSet attrs, int defStyle) {
272f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka        super(context, attrs, defStyle);
273b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung        mContentIsRefreshable = false;
274f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka
275f61249b79948a4b37b38104cbe81c98086d1f30bMichael Jurka        // With workspace, data is available straight from the get-go
276f61249b79948a4b37b38104cbe81c98086d1f30bMichael Jurka        setDataIsReady();
277f61249b79948a4b37b38104cbe81c98086d1f30bMichael Jurka
278f61249b79948a4b37b38104cbe81c98086d1f30bMichael Jurka        final Resources res = getResources();
279f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka        mFadeInAdjacentScreens = res.getBoolean(R.bool.config_workspaceFadeAdjacentScreens);
280f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka        mDragFadeOutAlpha = res.getInteger(R.integer.config_dragFadeOutAlpha) / 100f;
281f61249b79948a4b37b38104cbe81c98086d1f30bMichael Jurka        mDragFadeOutDuration = res.getInteger(R.integer.config_dragFadeOutDuration);
282f61249b79948a4b37b38104cbe81c98086d1f30bMichael Jurka        mWallpaperManager = WallpaperManager.getInstance(context);
283f61249b79948a4b37b38104cbe81c98086d1f30bMichael Jurka
284f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka        int cellCountX = DEFAULT_CELL_COUNT_X;
285f61249b79948a4b37b38104cbe81c98086d1f30bMichael Jurka        int cellCountY = DEFAULT_CELL_COUNT_Y;
286f61249b79948a4b37b38104cbe81c98086d1f30bMichael Jurka
287f61249b79948a4b37b38104cbe81c98086d1f30bMichael Jurka        TypedArray a = context.obtainStyledAttributes(attrs,
288f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka                R.styleable.Workspace, defStyle, 0);
289f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka
290f61249b79948a4b37b38104cbe81c98086d1f30bMichael Jurka        if (LauncherApplication.isScreenLarge()) {
291f61249b79948a4b37b38104cbe81c98086d1f30bMichael Jurka            // Determine number of rows/columns dynamically
292f61249b79948a4b37b38104cbe81c98086d1f30bMichael Jurka            // TODO: This code currently fails on tablets with an aspect ratio < 1.3.
293f61249b79948a4b37b38104cbe81c98086d1f30bMichael Jurka            // Around that ratio we should make cells the same size in portrait and
294f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka            // landscape
295f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka            TypedArray actionBarSizeTypedArray =
296f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka                context.obtainStyledAttributes(new int[] { android.R.attr.actionBarSize });
297b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung            DisplayMetrics displayMetrics = res.getDisplayMetrics();
298b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung            final float actionBarHeight = actionBarSizeTypedArray.getDimension(0, 0f);
29970fc438583779ef903541bf9ec546a8235a18785Winson Chung            final float systemBarHeight = res.getDimension(R.dimen.status_bar_height);
300b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung            final float smallestScreenDim = res.getConfiguration().smallestScreenWidthDp *
301f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka                    displayMetrics.density;
302f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka
303f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka            cellCountX = 1;
3040142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka            while (CellLayout.widthInPortrait(res, cellCountX + 1) <= smallestScreenDim) {
30531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                cellCountX++;
30631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            }
307d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen
3080d44e9482b95d8f163b28bf20131c4349185b589Joe Onorato            cellCountY = 1;
3090142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka            while (actionBarHeight + CellLayout.heightInLandscape(res, cellCountY + 1)
31031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                <= smallestScreenDim - systemBarHeight) {
311c35afb2c9df8cc56c77bf21ce2eaa213f6f31251Winson Chung                cellCountY++;
312c35afb2c9df8cc56c77bf21ce2eaa213f6f31251Winson Chung            }
313c35afb2c9df8cc56c77bf21ce2eaa213f6f31251Winson Chung        }
31431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
31531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        mSpringLoadedShrinkFactor =
316d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka            res.getInteger(R.integer.config_workspaceSpringLoadShrinkPercentage) / 100.0f;
317d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka
318d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka        // if the value is manually specified, use that instead
31995383fe41dacc45c2aa97e7f47bafebb5b7655d8Adam Cohen        cellCountX = a.getInt(R.styleable.Workspace_cellCountX, cellCountX);
320d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka        cellCountY = a.getInt(R.styleable.Workspace_cellCountY, cellCountY);
321d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka        mDefaultPage = a.getInt(R.styleable.Workspace_defaultScreen, 1);
322d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka        a.recycle();
323d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka
324d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka        LauncherModel.updateWorkspaceLayoutCells(cellCountX, cellCountY);
32595383fe41dacc45c2aa97e7f47bafebb5b7655d8Adam Cohen        setHapticFeedbackEnabled(false);
326d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka
327d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka        mLauncher = (Launcher) context;
32831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        initWorkspace();
32931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
33031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // Disable multitouch across the workspace/all apps/customize tray
3310142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka        setMotionEventSplittingEnabled(true);
3320589f0f66ce498512c6ee47482c649d88294c9d0Joe Onorato    }
3330142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka
3340142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka    // estimate the size of a widget with spans hSpan, vSpan. return MAX_VALUE for each
3350589f0f66ce498512c6ee47482c649d88294c9d0Joe Onorato    // dimension if unsuccessful
3360589f0f66ce498512c6ee47482c649d88294c9d0Joe Onorato    public int[] estimateItemSize(int hSpan, int vSpan,
337a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung            ItemInfo itemInfo, boolean springLoaded) {
338cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy        int[] size = new int[2];
3397777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        if (getChildCount() > 0) {
34031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            CellLayout cl = (CellLayout) mLauncher.getWorkspace().getChildAt(0);
341b4b7fa7c0383b6af58d73d3e024b91d586148cf8Winson Chung            Rect r = estimateItemPosition(cl, itemInfo, 0, 0, hSpan, vSpan);
342b4b7fa7c0383b6af58d73d3e024b91d586148cf8Winson Chung            size[0] = r.width();
343fd3385fe9e0f034b04f99d5d59a58d74fe040da4Winson Chung            size[1] = r.height();
344b4b7fa7c0383b6af58d73d3e024b91d586148cf8Winson Chung            if (springLoaded) {
345b4b7fa7c0383b6af58d73d3e024b91d586148cf8Winson Chung                size[0] *= mSpringLoadedShrinkFactor;
346b4b7fa7c0383b6af58d73d3e024b91d586148cf8Winson Chung                size[1] *= mSpringLoadedShrinkFactor;
3479171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung            }
3487777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen            return size;
3493c4c20fbe682cb4b3ef94f09afe0af09171583f3Michael Jurka        } else {
350c0e8fcae492730210b2b8b6d5bb3d65636bad245Michael Jurka            size[0] = Integer.MAX_VALUE;
351d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka            size[1] = Integer.MAX_VALUE;
352c0e8fcae492730210b2b8b6d5bb3d65636bad245Michael Jurka            return size;
3530bb8563b1381d92b0d7dbb5b0f814ad656c2f9bdMichael Jurka        }
3543c4c20fbe682cb4b3ef94f09afe0af09171583f3Michael Jurka    }
3558edd75c8bb0729a10cb39f614183e3e9ae4288e8Michael Jurka    public Rect estimateItemPosition(CellLayout cl, ItemInfo pendingInfo,
356d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka            int hCell, int vCell, int hSpan, int vSpan) {
357ca5b836e16d320f17057cd1a40a93c382e72501aMichael Jurka        Rect r = new Rect();
35860b7c53ccc6384b65aaca77d97794e8f09e8cfc8Patrick Dubroy        cl.cellToRect(hCell, vCell, hSpan, vSpan, r);
359d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka        return r;
360bea15195346bab3c52b0156e92f2b71f0811b210Michael Jurka    }
361bea15195346bab3c52b0156e92f2b71f0811b210Michael Jurka
3627777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen    public void buildPageHardwareLayers() {
3630142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka        if (getWindowToken() != null) {
364ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka            final int childCount = getChildCount();
36531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            for (int i = 0; i < childCount; i++) {
36631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                CellLayout cl = (CellLayout) getChildAt(i);
36731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                cl.getShortcutsAndWidgets().buildLayer();
368f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen            }
369b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung        }
370f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen    }
371f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen
37208ee77090f1fef565142e9341914369b1aa342d1Michael Jurka    public void onDragStart(DragSource source, Object info, int dragAction) {
37308ee77090f1fef565142e9341914369b1aa342d1Michael Jurka        mIsDragOccuring = true;
37408ee77090f1fef565142e9341914369b1aa342d1Michael Jurka        updateChildrenLayersEnabled();
37531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        mLauncher.lockScreenOrientationOnLargeUI();
37631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
37731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // Fade out the workspace slightly to highlight the currently dragging item
3782801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        int count = getChildCount();
3792801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        for (int i = 0; i < count; i++) {
3802801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            CellLayout cl = (CellLayout) getPageAt(i);
3812801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            cl.getShortcutsAndWidgets().animate().alpha(mDragFadeOutAlpha)
382e5fb0f27bca7afb996258a7163c76ca7390d7bffMichael Jurka                .setInterpolator(new AccelerateInterpolator(1.5f))
3832801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen                .setDuration(mDragFadeOutDuration)
38431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                .start();
38531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
38631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
38731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
388716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    public void onDragEnd() {
3898e776a62c5cc60737f5cdbbeacfec5f958112fa7Adam Cohen        mIsDragOccuring = false;
39031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        updateChildrenLayersEnabled();
3918e776a62c5cc60737f5cdbbeacfec5f958112fa7Adam Cohen        mLauncher.unlockScreenOrientationOnLargeUI();
392aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
393aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        // Fade the workspace back in after we have completed dragging
394aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        int count = getChildCount();
395aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        for (int i = 0; i < count; i++) {
39631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            CellLayout cl = (CellLayout) getPageAt(i);
39731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            cl.getShortcutsAndWidgets().animate().alpha(1f)
39831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                .setInterpolator(new DecelerateInterpolator(1.5f))
39931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                .setDuration(mDragFadeOutDuration)
40031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                .start();
401a0aa0121b91fde17e427ab2763ce312e64cf5d33Patrick Dubroy        }
402a0aa0121b91fde17e427ab2763ce312e64cf5d33Patrick Dubroy    }
40331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
40431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
40531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * Initializes various states for this workspace.
40631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
40731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    protected void initWorkspace() {
40831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        Context context = getContext();
40931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        mCurrentPage = mDefaultPage;
41031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        Launcher.setScreen(mCurrentPage);
41131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        LauncherApplication app = (LauncherApplication)context.getApplicationContext();
41231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        mIconCache = app.getIconCache();
41331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        setWillNotDraw(false);
41431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        setChildrenDrawnWithCacheEnabled(true);
41531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
4163d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        final Resources res = getResources();
4173d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        try {
418aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            mBackground = res.getDrawable(R.drawable.apps_customize_bg);
419aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        } catch (Resources.NotFoundException e) {
42031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            // In this case, we will skip drawing background protection
42131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
42231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
42331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        mWallpaperOffset = new WallpaperOffsetInterpolator();
42431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        Display display = mLauncher.getWindowManager().getDefaultDisplay();
42531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        mDisplayWidth = display.getWidth();
42631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        mDisplayHeight = display.getHeight();
42731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        mWallpaperTravelWidth = (int) (mDisplayWidth *
42831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                wallpaperTravelToScreenWidthRatio(mDisplayWidth, mDisplayHeight));
42931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
43031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        mMaxDistanceForFolderCreation = (0.5f * res.getDimension(R.dimen.app_icon_size));
43131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        mFlingThresholdVelocity = (int) (FLING_THRESHOLD_VELOCITY * mDensity);
4323d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung    }
4333d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung
4343d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung    @Override
4353d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung    protected int getScrollMode() {
4363d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        return SmoothPagedView.X_LARGE_MODE;
4373d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung    }
4383d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung
4393d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung    @Override
4403d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung    protected void onViewAdded(View child) {
4413d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        super.onViewAdded(child);
4423d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        if (!(child instanceof CellLayout)) {
4433d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung            throw new IllegalArgumentException("A Workspace can only have CellLayout children.");
4443d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        }
4454d279d94ade1c0d455404312b3c9cfde0078c547Winson Chung        CellLayout cl = ((CellLayout) child);
4463d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        cl.setOnInterceptTouchListener(this);
447099f60d51f6310e1290687e83958e665b3324504Adam Cohen        cl.setClickable(true);
448099f60d51f6310e1290687e83958e665b3324504Adam Cohen        cl.enableHardwareLayers();
449099f60d51f6310e1290687e83958e665b3324504Adam Cohen    }
450099f60d51f6310e1290687e83958e665b3324504Adam Cohen
451099f60d51f6310e1290687e83958e665b3324504Adam Cohen    /**
4523d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung     * @return The open folder on the current screen, or null if there is none
4533d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung     */
4543d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung    Folder getOpenFolder() {
4553d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        DragLayer dragLayer = mLauncher.getDragLayer();
4563d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        int count = dragLayer.getChildCount();
4573d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        for (int i = 0; i < count; i++) {
4583d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung            View child = dragLayer.getChildAt(i);
4593d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung            if (child instanceof Folder) {
4603d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung                Folder folder = (Folder) child;
461099f60d51f6310e1290687e83958e665b3324504Adam Cohen                if (folder.getInfo().opened)
462099f60d51f6310e1290687e83958e665b3324504Adam Cohen                    return folder;
463099f60d51f6310e1290687e83958e665b3324504Adam Cohen            }
464099f60d51f6310e1290687e83958e665b3324504Adam Cohen        }
465099f60d51f6310e1290687e83958e665b3324504Adam Cohen        return null;
4663d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung    }
4674d279d94ade1c0d455404312b3c9cfde0078c547Winson Chung
46831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    boolean isTouchActive() {
46931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        return mTouchState != TOUCH_STATE_REST;
47031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
47131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
47231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
47331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * Adds the specified child in the specified screen. The position and dimension of
47431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * the child are defined by x, y, spanX and spanY.
47531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     *
47631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param child The child to add in one of the workspace's screens.
47731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param screen The screen in which to add the child.
47831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param x The X position of the child in the screen's grid.
479aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     * @param y The Y position of the child in the screen's grid.
4807f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen     * @param spanX The number of cells spanned horizontally by the child.
4817f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen     * @param spanY The number of cells spanned vertically by the child.
4827f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen     */
4837f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen    void addInScreen(View child, long container, int screen, int x, int y, int spanX, int spanY) {
4846569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        addInScreen(child, container, screen, x, y, spanX, spanY, false);
4853d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung    }
486f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka
4873d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung    /**
488aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     * Adds the specified child in the specified screen. The position and dimension of
489aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     * the child are defined by x, y, spanX and spanY.
4906569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     *
491aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     * @param child The child to add in one of the workspace's screens.
492aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     * @param screen The screen in which to add the child.
493aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     * @param x The X position of the child in the screen's grid.
49431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param y The Y position of the child in the screen's grid.
4950d44e9482b95d8f163b28bf20131c4349185b589Joe Onorato     * @param spanX The number of cells spanned horizontally by the child.
49631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param spanY The number of cells spanned vertically by the child.
49731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param insert When true, the child is inserted at the beginning of the children list.
49800acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato     */
499aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung    void addInScreen(View child, long container, int screen, int x, int y, int spanX, int spanY,
50000acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato            boolean insert) {
50131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        if (container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
50231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            if (screen < 0 || screen >= getChildCount()) {
503d0ce1ec2e21ce3bb0ba3549a01d1d06b440a8e45Patrick Dubroy                Log.e(TAG, "The screen must be >= 0 and < " + getChildCount()
504d0ce1ec2e21ce3bb0ba3549a01d1d06b440a8e45Patrick Dubroy                    + " (was " + screen + "); skipping child");
505d0ce1ec2e21ce3bb0ba3549a01d1d06b440a8e45Patrick Dubroy                return;
506d0ce1ec2e21ce3bb0ba3549a01d1d06b440a8e45Patrick Dubroy            }
507d0ce1ec2e21ce3bb0ba3549a01d1d06b440a8e45Patrick Dubroy        }
508d0ce1ec2e21ce3bb0ba3549a01d1d06b440a8e45Patrick Dubroy
509d0ce1ec2e21ce3bb0ba3549a01d1d06b440a8e45Patrick Dubroy        final CellLayout layout;
510d0ce1ec2e21ce3bb0ba3549a01d1d06b440a8e45Patrick Dubroy        if (container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
511d0ce1ec2e21ce3bb0ba3549a01d1d06b440a8e45Patrick Dubroy            layout = mLauncher.getHotseat().getLayout();
512d0ce1ec2e21ce3bb0ba3549a01d1d06b440a8e45Patrick Dubroy            child.setOnKeyListener(null);
513d0ce1ec2e21ce3bb0ba3549a01d1d06b440a8e45Patrick Dubroy
514d0ce1ec2e21ce3bb0ba3549a01d1d06b440a8e45Patrick Dubroy            // Hide folder title in the hotseat
515d0ce1ec2e21ce3bb0ba3549a01d1d06b440a8e45Patrick Dubroy            if (child instanceof FolderIcon) {
516d0ce1ec2e21ce3bb0ba3549a01d1d06b440a8e45Patrick Dubroy                ((FolderIcon) child).setTextVisible(false);
517d0ce1ec2e21ce3bb0ba3549a01d1d06b440a8e45Patrick Dubroy            }
518d0ce1ec2e21ce3bb0ba3549a01d1d06b440a8e45Patrick Dubroy
519d0ce1ec2e21ce3bb0ba3549a01d1d06b440a8e45Patrick Dubroy            if (screen < 0) {
520d0ce1ec2e21ce3bb0ba3549a01d1d06b440a8e45Patrick Dubroy                screen = mLauncher.getHotseat().getOrderInHotseat(x, y);
521d0ce1ec2e21ce3bb0ba3549a01d1d06b440a8e45Patrick Dubroy            } else {
522d0ce1ec2e21ce3bb0ba3549a01d1d06b440a8e45Patrick Dubroy                // Note: We do this to ensure that the hotseat is always laid out in the orientation
523d0ce1ec2e21ce3bb0ba3549a01d1d06b440a8e45Patrick Dubroy                // of the hotseat in order regardless of which orientation they were added
524d0ce1ec2e21ce3bb0ba3549a01d1d06b440a8e45Patrick Dubroy                x = mLauncher.getHotseat().getCellXFromOrder(screen);
525d0ce1ec2e21ce3bb0ba3549a01d1d06b440a8e45Patrick Dubroy                y = mLauncher.getHotseat().getCellYFromOrder(screen);
526d0ce1ec2e21ce3bb0ba3549a01d1d06b440a8e45Patrick Dubroy            }
527d0ce1ec2e21ce3bb0ba3549a01d1d06b440a8e45Patrick Dubroy        } else {
528d0ce1ec2e21ce3bb0ba3549a01d1d06b440a8e45Patrick Dubroy            // Show folder title if not in the hotseat
529d0ce1ec2e21ce3bb0ba3549a01d1d06b440a8e45Patrick Dubroy            if (child instanceof FolderIcon) {
530d0ce1ec2e21ce3bb0ba3549a01d1d06b440a8e45Patrick Dubroy                ((FolderIcon) child).setTextVisible(true);
531d0ce1ec2e21ce3bb0ba3549a01d1d06b440a8e45Patrick Dubroy            }
532d0ce1ec2e21ce3bb0ba3549a01d1d06b440a8e45Patrick Dubroy
533e708c5249b26978057acb9370cbfb8f6f747f5b8Patrick Dubroy            layout = (CellLayout) getChildAt(screen);
534e708c5249b26978057acb9370cbfb8f6f747f5b8Patrick Dubroy            child.setOnKeyListener(new IconKeyEventListener());
535e708c5249b26978057acb9370cbfb8f6f747f5b8Patrick Dubroy        }
536e708c5249b26978057acb9370cbfb8f6f747f5b8Patrick Dubroy
537e708c5249b26978057acb9370cbfb8f6f747f5b8Patrick Dubroy        LayoutParams genericLp = child.getLayoutParams();
538e708c5249b26978057acb9370cbfb8f6f747f5b8Patrick Dubroy        CellLayout.LayoutParams lp;
539dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka        if (genericLp == null || !(genericLp instanceof CellLayout.LayoutParams)) {
540d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka            lp = new CellLayout.LayoutParams(x, y, spanX, spanY);
541e708c5249b26978057acb9370cbfb8f6f747f5b8Patrick Dubroy        } else {
542e708c5249b26978057acb9370cbfb8f6f747f5b8Patrick Dubroy            lp = (CellLayout.LayoutParams) genericLp;
543fc53cd22c9a78708c78c85946443f23ec8c59502Adam Cohen            lp.cellX = x;
544fc53cd22c9a78708c78c85946443f23ec8c59502Adam Cohen            lp.cellY = y;
545fc53cd22c9a78708c78c85946443f23ec8c59502Adam Cohen            lp.cellHSpan = spanX;
546fc53cd22c9a78708c78c85946443f23ec8c59502Adam Cohen            lp.cellVSpan = spanY;
547ded9f8d8658d0b6601006c0a954cd3bf530e55c1Adam Cohen        }
548ded9f8d8658d0b6601006c0a954cd3bf530e55c1Adam Cohen
549ded9f8d8658d0b6601006c0a954cd3bf530e55c1Adam Cohen        if (spanX < 0 && spanY < 0) {
550ded9f8d8658d0b6601006c0a954cd3bf530e55c1Adam Cohen            lp.isLockedToGrid = false;
5515f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka        }
5525f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka
553d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka        // Get the canonical child id to uniquely represent this view in this screen
5545f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka        int childId = LauncherModel.getCellLayoutChildId(container, screen, x, y, spanX, spanY);
5555f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka        boolean markCellsAsOccupied = !(child instanceof Folder);
5565f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka        if (!layout.addViewToCellLayout(child, insert ? 0 : -1, childId, lp, markCellsAsOccupied)) {
5575f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka            // TODO: This branch occurs when the workspace is adding views
5585f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka            // outside of the defined grid
5595f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka            // maybe we should be deleting these items from the LauncherModel?
5605f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka            Log.w(TAG, "Failed to add to item at (" + lp.cellX + "," + lp.cellY + ") to CellLayout");
5615f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka        }
562d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka
563d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka        if (!(child instanceof Folder)) {
564f8d2823d885ba682140aee1ae0504c1c5e67a24bAdam Cohen            child.setHapticFeedbackEnabled(false);
565f8d2823d885ba682140aee1ae0504c1c5e67a24bAdam Cohen            child.setOnLongClickListener(mLongClickListener);
566d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka        }
567d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka        if (child instanceof DropTarget) {
568d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka            mDragController.addDropTarget((DropTarget) child);
569d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka        }
570d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka    }
571d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka
572d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka    /**
573d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka     * Check if the point (x, y) hits a given page.
574d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka     */
575f8d2823d885ba682140aee1ae0504c1c5e67a24bAdam Cohen    private boolean hitsPage(int index, float x, float y) {
5765f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka        final View page = getChildAt(index);
5775f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka        if (page != null) {
5785f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka            float[] localXY = { x, y };
5791adf5391a3a3d215b226adf3702019c22a99e3b1Michael Jurka            mapPointFromSelfToChild(page, localXY);
5801adf5391a3a3d215b226adf3702019c22a99e3b1Michael Jurka            return (localXY[0] >= 0 && localXY[0] < page.getWidth()
581d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka                    && localXY[1] >= 0 && localXY[1] < page.getHeight());
58269c42da4d30f1cbba5fe1ac8960b4e305e14b807Adam Cohen        }
58369c42da4d30f1cbba5fe1ac8960b4e305e14b807Adam Cohen        return false;
584f8d2823d885ba682140aee1ae0504c1c5e67a24bAdam Cohen    }
58569c42da4d30f1cbba5fe1ac8960b4e305e14b807Adam Cohen
586f8d2823d885ba682140aee1ae0504c1c5e67a24bAdam Cohen    @Override
58769c42da4d30f1cbba5fe1ac8960b4e305e14b807Adam Cohen    protected boolean hitsPreviousPage(float x, float y) {
58869c42da4d30f1cbba5fe1ac8960b4e305e14b807Adam Cohen        // mNextPage is set to INVALID_PAGE whenever we are stationary.
589f8d2823d885ba682140aee1ae0504c1c5e67a24bAdam Cohen        // Calculating "next page" this way ensures that you scroll to whatever page you tap on
59069c42da4d30f1cbba5fe1ac8960b4e305e14b807Adam Cohen        final int current = (mNextPage == INVALID_PAGE) ? mCurrentPage : mNextPage;
59169c42da4d30f1cbba5fe1ac8960b4e305e14b807Adam Cohen
59269c42da4d30f1cbba5fe1ac8960b4e305e14b807Adam Cohen        // Only allow tap to next page on large devices, where there's significant margin outside
593f8d2823d885ba682140aee1ae0504c1c5e67a24bAdam Cohen        // the active workspace
59469c42da4d30f1cbba5fe1ac8960b4e305e14b807Adam Cohen        return LauncherApplication.isScreenLarge() && hitsPage(current - 1, x, y);
59569c42da4d30f1cbba5fe1ac8960b4e305e14b807Adam Cohen    }
59669c42da4d30f1cbba5fe1ac8960b4e305e14b807Adam Cohen
59769c42da4d30f1cbba5fe1ac8960b4e305e14b807Adam Cohen    @Override
59869c42da4d30f1cbba5fe1ac8960b4e305e14b807Adam Cohen    protected boolean hitsNextPage(float x, float y) {
59969c42da4d30f1cbba5fe1ac8960b4e305e14b807Adam Cohen        // mNextPage is set to INVALID_PAGE whenever we are stationary.
60069c42da4d30f1cbba5fe1ac8960b4e305e14b807Adam Cohen        // Calculating "next page" this way ensures that you scroll to whatever page you tap on
60169c42da4d30f1cbba5fe1ac8960b4e305e14b807Adam Cohen        final int current = (mNextPage == INVALID_PAGE) ? mCurrentPage : mNextPage;
60269c42da4d30f1cbba5fe1ac8960b4e305e14b807Adam Cohen
60369c42da4d30f1cbba5fe1ac8960b4e305e14b807Adam Cohen        // Only allow tap to next page on large devices, where there's significant margin outside
60469c42da4d30f1cbba5fe1ac8960b4e305e14b807Adam Cohen        // the active workspace
60569c42da4d30f1cbba5fe1ac8960b4e305e14b807Adam Cohen        return LauncherApplication.isScreenLarge() && hitsPage(current + 1, x, y);
60669c42da4d30f1cbba5fe1ac8960b4e305e14b807Adam Cohen    }
60769c42da4d30f1cbba5fe1ac8960b4e305e14b807Adam Cohen
60869c42da4d30f1cbba5fe1ac8960b4e305e14b807Adam Cohen    /**
60969c42da4d30f1cbba5fe1ac8960b4e305e14b807Adam Cohen     * Called directly from a CellLayout (not by the framework), after we've been added as a
610f8d2823d885ba682140aee1ae0504c1c5e67a24bAdam Cohen     * listener via setOnInterceptTouchEventListener(). This allows us to tell the CellLayout
6111adf5391a3a3d215b226adf3702019c22a99e3b1Michael Jurka     * that it should intercept touch events, which is not something that is normally supported.
6121adf5391a3a3d215b226adf3702019c22a99e3b1Michael Jurka     */
613007c69867d821ea2b271398577a8b3440b3a7046Winson Chung    @Override
614007c69867d821ea2b271398577a8b3440b3a7046Winson Chung    public boolean onTouch(View v, MotionEvent event) {
615d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka        return (isSmall() || !isFinishedSwitchingState());
616007c69867d821ea2b271398577a8b3440b3a7046Winson Chung    }
617007c69867d821ea2b271398577a8b3440b3a7046Winson Chung
6181262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy    public boolean isSwitchingState() {
619007c69867d821ea2b271398577a8b3440b3a7046Winson Chung        return mIsSwitchingState;
620007c69867d821ea2b271398577a8b3440b3a7046Winson Chung    }
621d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka
622d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka    /** This differs from isSwitchingState in that we take into account how far the transition
6230142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka     *  has completed. */
624d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka    public boolean isFinishedSwitchingState() {
625d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka        return !mIsSwitchingState || (mTransitionProgress > 0.5f);
626d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka    }
627d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka
628d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka    protected void onWindowVisibilityChanged (int visibility) {
629d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka        mLauncher.onWindowVisibilityChanged(visibility);
630d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka    }
631d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka
63231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
633007c69867d821ea2b271398577a8b3440b3a7046Winson Chung    public boolean dispatchUnhandledMove(View focused, int direction) {
634007c69867d821ea2b271398577a8b3440b3a7046Winson Chung        if (isSmall() || !isFinishedSwitchingState()) {
635007c69867d821ea2b271398577a8b3440b3a7046Winson Chung            // when the home screens are shrunken, shouldn't allow side-scrolling
636007c69867d821ea2b271398577a8b3440b3a7046Winson Chung            return false;
637007c69867d821ea2b271398577a8b3440b3a7046Winson Chung        }
63831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        return super.dispatchUnhandledMove(focused, direction);
63931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
6401262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy
641007c69867d821ea2b271398577a8b3440b3a7046Winson Chung    @Override
642007c69867d821ea2b271398577a8b3440b3a7046Winson Chung    public boolean onInterceptTouchEvent(MotionEvent ev) {
643d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka        switch (ev.getAction() & MotionEvent.ACTION_MASK) {
644d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka        case MotionEvent.ACTION_DOWN:
645d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka            mXDown = ev.getX();
646d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka            mYDown = ev.getY();
647d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka            break;
648d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka        case MotionEvent.ACTION_POINTER_UP:
6491262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy        case MotionEvent.ACTION_UP:
6501262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy            if (mTouchState == TOUCH_STATE_REST) {
651007c69867d821ea2b271398577a8b3440b3a7046Winson Chung                final CellLayout currentPage = (CellLayout) getChildAt(mCurrentPage);
652007c69867d821ea2b271398577a8b3440b3a7046Winson Chung                if (!currentPage.lastDownOnOccupiedCell()) {
653007c69867d821ea2b271398577a8b3440b3a7046Winson Chung                    onWallpaperTap(ev);
654007c69867d821ea2b271398577a8b3440b3a7046Winson Chung                }
6551262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy            }
65668d739365bf650fe7fecf99cd3bfe63a0d41bd12Adam Cohen        }
657e0f66b546994a9bdee452851c17a148db02ec300Adam Cohen        return super.onInterceptTouchEvent(ev);
65826976d9b53161f80faf822d482ac771b8621cf31Adam Cohen    }
65926976d9b53161f80faf822d482ac771b8621cf31Adam Cohen
66026976d9b53161f80faf822d482ac771b8621cf31Adam Cohen    @Override
66126976d9b53161f80faf822d482ac771b8621cf31Adam Cohen    protected void determineScrollingStart(MotionEvent ev) {
66226976d9b53161f80faf822d482ac771b8621cf31Adam Cohen        if (isSmall()) return;
6630142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka        if (!isFinishedSwitchingState()) return;
6640142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka
6650142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka        float deltaX = Math.abs(ev.getX() - mXDown);
6660142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka        float deltaY = Math.abs(ev.getY() - mYDown);
6670142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka
6680142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka        if (Float.compare(deltaX, 0f) == 0) return;
6690142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka
6700142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka        float slope = deltaY / deltaX;
671c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka        float theta = (float) Math.atan(slope);
672c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka
673c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka        if (deltaX > mTouchSlop || deltaY > mTouchSlop) {
674c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka            cancelCurrentPageLongPress();
675c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka        }
676c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka
677c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka        if (theta > MAX_SWIPE_ANGLE) {
678c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka            // Above MAX_SWIPE_ANGLE, we don't want to ever start scrolling the workspace
679c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka            return;
680c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka        } else if (theta > START_DAMPING_TOUCH_SLOP_ANGLE) {
681c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka            // Above START_DAMPING_TOUCH_SLOP_ANGLE and below MAX_SWIPE_ANGLE, we want to
682c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka            // increase the touch slop to make it harder to begin scrolling the workspace. This
683c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka            // results in vertically scrolling widgets to more easily. The higher the angle, the
684c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka            // more we increase touch slop.
685c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka            theta -= START_DAMPING_TOUCH_SLOP_ANGLE;
686c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka            float extraRatio = (float)
687c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka                    Math.sqrt((theta / (MAX_SWIPE_ANGLE - START_DAMPING_TOUCH_SLOP_ANGLE)));
688c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka            super.determineScrollingStart(ev, 1 + TOUCH_SLOP_DAMPING_FACTOR * extraRatio);
689c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka        } else {
690c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka            // Below START_DAMPING_TOUCH_SLOP_ANGLE, we don't do anything special
691c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka            super.determineScrollingStart(ev);
692c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka        }
693c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka    }
694c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka
695c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka    @Override
696c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka    protected boolean isScrollingIndicatorEnabled() {
697c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka        return mState != State.SPRING_LOADED;
698c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka    }
699c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka
700c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka    protected void onPageBeginMoving() {
701c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka        super.onPageBeginMoving();
702c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka
703c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka        if (isHardwareAccelerated()) {
704c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka            updateChildrenLayersEnabled();
705c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka        } else {
706c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka            if (mNextPage != INVALID_PAGE) {
707c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka                // we're snapping to a particular screen
708c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka                enableChildrenCache(mCurrentPage, mNextPage);
709c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka            } else {
710c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka                // this is when user is actively dragging a particular screen, they might
711201bc828d5a0078f505e8e37152156a0cb43c10aWinson Chung                // swipe it either left or right (but we won't advance by more than one screen)
712201bc828d5a0078f505e8e37152156a0cb43c10aWinson Chung                enableChildrenCache(mCurrentPage - 1, mCurrentPage + 1);
713201bc828d5a0078f505e8e37152156a0cb43c10aWinson Chung            }
714201bc828d5a0078f505e8e37152156a0cb43c10aWinson Chung        }
715c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka
716c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka        // Only show page outlines as we pan if we are on large screen
717c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka        if (LauncherApplication.isScreenLarge()) {
718c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka            showOutlines();
719c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka            mIsStaticWallpaper = mWallpaperManager.getWallpaperInfo() == null;
720f7640c8bba304ba99c99afcd7393893eccc9a0d9Winson Chung        }
721f7640c8bba304ba99c99afcd7393893eccc9a0d9Winson Chung
722f7640c8bba304ba99c99afcd7393893eccc9a0d9Winson Chung        // If we are not fading in adjacent screens, we still need to restore the alpha in case the
723f7640c8bba304ba99c99afcd7393893eccc9a0d9Winson Chung        // user scrolls while we are transitioning (should not affect dispatchDraw optimizations)
724f7640c8bba304ba99c99afcd7393893eccc9a0d9Winson Chung        if (!mFadeInAdjacentScreens) {
725c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka            for (int i = 0; i < getChildCount(); ++i) {
726c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka                ((CellLayout) getPageAt(i)).setShortcutAndWidgetAlpha(1f);
727ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka            }
728ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka        }
729ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka
730ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka        // Show the scroll indicator as you pan the page
731ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka        showScrollingIndicator(false);
732ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka    }
733ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka
734ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka    protected void onPageEndMoving() {
735ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka        super.onPageEndMoving();
736ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka
737ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka        if (isHardwareAccelerated()) {
738c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka            updateChildrenLayersEnabled();
739c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka        } else {
740ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka            clearChildrenCache();
741ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka        }
742f70c78142457b0e9c691f2a20ed87407c7433f5bMichael Jurka
743ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka
744ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka        if (mDragController.isDragging()) {
745ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka            if (isSmall()) {
746ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka                // If we are in springloaded mode, then force an event to check if the current touch
747ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka                // is under a new page (to scroll to)
748f70c78142457b0e9c691f2a20ed87407c7433f5bMichael Jurka                mDragController.forceMoveEvent();
749f70c78142457b0e9c691f2a20ed87407c7433f5bMichael Jurka            }
750f70c78142457b0e9c691f2a20ed87407c7433f5bMichael Jurka        } else {
751ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka            // If we are not mid-dragging, hide the page outlines if we are on a large screen
752ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka            if (LauncherApplication.isScreenLarge()) {
753ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka                hideOutlines();
754ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka            }
755ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka
756ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka            // Hide the scroll indicator as you pan the page
757beff8c6a13d5b5ad69f5a85ee0150cecd28e6341Adam Cohen            if (!mDragController.isDragging()) {
758beff8c6a13d5b5ad69f5a85ee0150cecd28e6341Adam Cohen                hideScrollingIndicator(false);
759beff8c6a13d5b5ad69f5a85ee0150cecd28e6341Adam Cohen            }
760beff8c6a13d5b5ad69f5a85ee0150cecd28e6341Adam Cohen        }
761beff8c6a13d5b5ad69f5a85ee0150cecd28e6341Adam Cohen        mOverScrollMaxBackgroundAlpha = 0.0f;
76209d6eb0f3fb1d81ea59881e6c65512d09d573cc1Michael Jurka        mOverScrollPageIndex = -1;
76309d6eb0f3fb1d81ea59881e6c65512d09d573cc1Michael Jurka
76409d6eb0f3fb1d81ea59881e6c65512d09d573cc1Michael Jurka        if (mDelayedResizeRunnable != null) {
76509d6eb0f3fb1d81ea59881e6c65512d09d573cc1Michael Jurka            mDelayedResizeRunnable.run();
76609d6eb0f3fb1d81ea59881e6c65512d09d573cc1Michael Jurka            mDelayedResizeRunnable = null;
76709d6eb0f3fb1d81ea59881e6c65512d09d573cc1Michael Jurka        }
76809d6eb0f3fb1d81ea59881e6c65512d09d573cc1Michael Jurka    }
76909d6eb0f3fb1d81ea59881e6c65512d09d573cc1Michael Jurka
77009d6eb0f3fb1d81ea59881e6c65512d09d573cc1Michael Jurka    @Override
77109d6eb0f3fb1d81ea59881e6c65512d09d573cc1Michael Jurka    protected void notifyPageSwitchListener() {
77209d6eb0f3fb1d81ea59881e6c65512d09d573cc1Michael Jurka        super.notifyPageSwitchListener();
77309d6eb0f3fb1d81ea59881e6c65512d09d573cc1Michael Jurka        Launcher.setScreen(mCurrentPage);
77409d6eb0f3fb1d81ea59881e6c65512d09d573cc1Michael Jurka    };
775beff8c6a13d5b5ad69f5a85ee0150cecd28e6341Adam Cohen
776beff8c6a13d5b5ad69f5a85ee0150cecd28e6341Adam Cohen    // As a ratio of screen height, the total distance we want the parallax effect to span
777beff8c6a13d5b5ad69f5a85ee0150cecd28e6341Adam Cohen    // horizontally
778beff8c6a13d5b5ad69f5a85ee0150cecd28e6341Adam Cohen    private float wallpaperTravelToScreenWidthRatio(int width, int height) {
779ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka        float aspectRatio = width / (float) height;
780beff8c6a13d5b5ad69f5a85ee0150cecd28e6341Adam Cohen
781ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka        // At an aspect ratio of 16/10, the wallpaper parallax effect should span 1.5 * screen width
782f70c78142457b0e9c691f2a20ed87407c7433f5bMichael Jurka        // At an aspect ratio of 10/16, the wallpaper parallax effect should span 1.2 * screen width
783ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka        // We will use these two data points to extrapolate how much the wallpaper parallax effect
784ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka        // to span (ie travel) at any aspect ratio:
785ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka
786ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka        final float ASPECT_RATIO_LANDSCAPE = 16/10f;
787b46a2d130b3d04df830402d579060b63db559ae3Winson Chung        final float ASPECT_RATIO_PORTRAIT = 10/16f;
788b46a2d130b3d04df830402d579060b63db559ae3Winson Chung        final float WALLPAPER_WIDTH_TO_SCREEN_RATIO_LANDSCAPE = 1.5f;
789ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka        final float WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT = 1.2f;
790c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka
791c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka        // To find out the desired width at different aspect ratios, we use the following two
792c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka        // formulas, where the coefficient on x is the aspect ratio (width/height):
793c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka        //   (16/10)x + y = 1.5
794c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka        //   (10/16)x + y = 1.2
795c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka        // We solve for x and y and end up with a final formula:
796c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka        final float x =
797ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka            (WALLPAPER_WIDTH_TO_SCREEN_RATIO_LANDSCAPE - WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT) /
798ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka            (ASPECT_RATIO_LANDSCAPE - ASPECT_RATIO_PORTRAIT);
799ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka        final float y = WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT - x * ASPECT_RATIO_PORTRAIT;
800ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka        return x * aspectRatio + y;
801ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka    }
802ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka
803ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka    // The range of scroll values for Workspace
804ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka    private int getScrollRange() {
805c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka        return getChildOffset(getChildCount() - 1) - getChildOffset(0);
806ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka    }
807ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka
808ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka    protected void setWallpaperDimension() {
8099c6fbed48783dacd9bc6b4ec5f2cc8e59ec7ee37Michael Jurka        DisplayMetrics displayMetrics = new DisplayMetrics();
8109c6fbed48783dacd9bc6b4ec5f2cc8e59ec7ee37Michael Jurka        mLauncher.getWindowManager().getDefaultDisplay().getRealMetrics(displayMetrics);
811ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka        final int maxDim = Math.max(displayMetrics.widthPixels, displayMetrics.heightPixels);
812ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka        final int minDim = Math.min(displayMetrics.widthPixels, displayMetrics.heightPixels);
813ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka
814ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka        // We need to ensure that there is enough extra space in the wallpaper for the intended
8152763be3150d429d338b9848286e9365b4052c100Michael Jurka        // parallax effects
816956091ba7863bd72086275e61084864994dd6fa7Joe Onorato        if (LauncherApplication.isScreenLarge()) {
817ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka            mWallpaperWidth = (int) (maxDim * wallpaperTravelToScreenWidthRatio(maxDim, minDim));
818ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka            mWallpaperHeight = maxDim;
819beff8c6a13d5b5ad69f5a85ee0150cecd28e6341Adam Cohen        } else {
820beff8c6a13d5b5ad69f5a85ee0150cecd28e6341Adam Cohen            mWallpaperWidth = Math.max((int) (minDim * WALLPAPER_SCREENS_SPAN), maxDim);
821beff8c6a13d5b5ad69f5a85ee0150cecd28e6341Adam Cohen            mWallpaperHeight = maxDim;
8225037a0b02a720ae14cbf673d7d5bb148f5a524c8Adam Cohen        }
823beff8c6a13d5b5ad69f5a85ee0150cecd28e6341Adam Cohen        new Thread("setWallpaperDimension") {
824beff8c6a13d5b5ad69f5a85ee0150cecd28e6341Adam Cohen            public void run() {
825beff8c6a13d5b5ad69f5a85ee0150cecd28e6341Adam Cohen                mWallpaperManager.suggestDesiredDimensions(mWallpaperWidth, mWallpaperHeight);
826beff8c6a13d5b5ad69f5a85ee0150cecd28e6341Adam Cohen            }
827beff8c6a13d5b5ad69f5a85ee0150cecd28e6341Adam Cohen        }.start();
8285037a0b02a720ae14cbf673d7d5bb148f5a524c8Adam Cohen    }
829beff8c6a13d5b5ad69f5a85ee0150cecd28e6341Adam Cohen
830beff8c6a13d5b5ad69f5a85ee0150cecd28e6341Adam Cohen    private float wallpaperOffsetForCurrentScroll() {
8315037a0b02a720ae14cbf673d7d5bb148f5a524c8Adam Cohen        // Set wallpaper offset steps (1 / (number of screens - 1))
832beff8c6a13d5b5ad69f5a85ee0150cecd28e6341Adam Cohen        mWallpaperManager.setWallpaperOffsetSteps(1.0f / (getChildCount() - 1), 1.0f);
833beff8c6a13d5b5ad69f5a85ee0150cecd28e6341Adam Cohen
834beff8c6a13d5b5ad69f5a85ee0150cecd28e6341Adam Cohen        // For the purposes of computing the scrollRange and overScrollOffset, we assume
835beff8c6a13d5b5ad69f5a85ee0150cecd28e6341Adam Cohen        // that mLayoutScale is 1. This means that when we're in spring-loaded mode,
8365037a0b02a720ae14cbf673d7d5bb148f5a524c8Adam Cohen        // there's no discrepancy between the wallpaper offset for a given page.
837beff8c6a13d5b5ad69f5a85ee0150cecd28e6341Adam Cohen        float layoutScale = mLayoutScale;
8385037a0b02a720ae14cbf673d7d5bb148f5a524c8Adam Cohen        mLayoutScale = 1f;
839beff8c6a13d5b5ad69f5a85ee0150cecd28e6341Adam Cohen        int scrollRange = getScrollRange();
840beff8c6a13d5b5ad69f5a85ee0150cecd28e6341Adam Cohen
841beff8c6a13d5b5ad69f5a85ee0150cecd28e6341Adam Cohen        // Again, we adjust the wallpaper offset to be consistent between values of mLayoutScale
842beff8c6a13d5b5ad69f5a85ee0150cecd28e6341Adam Cohen        float adjustedScrollX = Math.max(0, Math.min(mScrollX, mMaxScrollX));
843beff8c6a13d5b5ad69f5a85ee0150cecd28e6341Adam Cohen        adjustedScrollX *= mWallpaperScrollRatio;
844beff8c6a13d5b5ad69f5a85ee0150cecd28e6341Adam Cohen        mLayoutScale = layoutScale;
845beff8c6a13d5b5ad69f5a85ee0150cecd28e6341Adam Cohen
846beff8c6a13d5b5ad69f5a85ee0150cecd28e6341Adam Cohen        float scrollProgress =
847ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka            adjustedScrollX / (float) scrollRange;
848ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka
849ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka        if (LauncherApplication.isScreenLarge() && mIsStaticWallpaper) {
850ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka            // The wallpaper travel width is how far, from left to right, the wallpaper will move
851ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka            // at this orientation. On tablets in portrait mode we don't move all the way to the
852ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka            // edges of the wallpaper, or otherwise the parallax effect would be too strong.
853ca5b836e16d320f17057cd1a40a93c382e72501aMichael Jurka            int wallpaperTravelWidth = Math.min(mWallpaperTravelWidth, mWallpaperWidth);
854ca5b836e16d320f17057cd1a40a93c382e72501aMichael Jurka
855ca5b836e16d320f17057cd1a40a93c382e72501aMichael Jurka            float offsetInDips = wallpaperTravelWidth * scrollProgress +
856ca5b836e16d320f17057cd1a40a93c382e72501aMichael Jurka                (mWallpaperWidth - wallpaperTravelWidth) / 2; // center it
857ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka            float offset = offsetInDips / (float) mWallpaperWidth;
858ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka            return offset;
859ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka        } else {
860ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka            return scrollProgress;
861ca5b836e16d320f17057cd1a40a93c382e72501aMichael Jurka        }
862ca5b836e16d320f17057cd1a40a93c382e72501aMichael Jurka    }
863ca5b836e16d320f17057cd1a40a93c382e72501aMichael Jurka
864ca5b836e16d320f17057cd1a40a93c382e72501aMichael Jurka    private void syncWallpaperOffsetWithScroll() {
865ca5b836e16d320f17057cd1a40a93c382e72501aMichael Jurka        final boolean enableWallpaperEffects = isHardwareAccelerated();
866ca5b836e16d320f17057cd1a40a93c382e72501aMichael Jurka        if (enableWallpaperEffects) {
867ca5b836e16d320f17057cd1a40a93c382e72501aMichael Jurka            mWallpaperOffset.setFinalX(wallpaperOffsetForCurrentScroll());
868ca5b836e16d320f17057cd1a40a93c382e72501aMichael Jurka        }
869ca5b836e16d320f17057cd1a40a93c382e72501aMichael Jurka    }
870ca5b836e16d320f17057cd1a40a93c382e72501aMichael Jurka
871ca5b836e16d320f17057cd1a40a93c382e72501aMichael Jurka    public void updateWallpaperOffsetImmediately() {
872ca5b836e16d320f17057cd1a40a93c382e72501aMichael Jurka        mUpdateWallpaperOffsetImmediately = true;
873ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka    }
874ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka
875ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka    private void updateWallpaperOffsets() {
876ca5b836e16d320f17057cd1a40a93c382e72501aMichael Jurka        boolean updateNow = false;
877ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka        boolean keepUpdating = true;
878ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka        if (mUpdateWallpaperOffsetImmediately) {
879ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka            updateNow = true;
880ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka            keepUpdating = false;
881ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka            mWallpaperOffset.jumpToFinal();
882ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka            mUpdateWallpaperOffsetImmediately = false;
883ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka        } else {
884ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka            updateNow = keepUpdating = mWallpaperOffset.computeScrollOffset();
885ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka        }
886ca5b836e16d320f17057cd1a40a93c382e72501aMichael Jurka        if (updateNow) {
887ca5b836e16d320f17057cd1a40a93c382e72501aMichael Jurka            if (mWindowToken != null) {
888ca5b836e16d320f17057cd1a40a93c382e72501aMichael Jurka                mWallpaperManager.setWallpaperOffsets(mWindowToken,
889ca5b836e16d320f17057cd1a40a93c382e72501aMichael Jurka                        mWallpaperOffset.getCurrX(), mWallpaperOffset.getCurrY());
890ca5b836e16d320f17057cd1a40a93c382e72501aMichael Jurka            }
891ca5b836e16d320f17057cd1a40a93c382e72501aMichael Jurka        }
892ca5b836e16d320f17057cd1a40a93c382e72501aMichael Jurka        if (keepUpdating) {
893ca5b836e16d320f17057cd1a40a93c382e72501aMichael Jurka            invalidate();
894ca5b836e16d320f17057cd1a40a93c382e72501aMichael Jurka        }
895ca5b836e16d320f17057cd1a40a93c382e72501aMichael Jurka    }
896ca5b836e16d320f17057cd1a40a93c382e72501aMichael Jurka
897ca5b836e16d320f17057cd1a40a93c382e72501aMichael Jurka    @Override
898ca5b836e16d320f17057cd1a40a93c382e72501aMichael Jurka    protected void updateCurrentPageScroll() {
899ca5b836e16d320f17057cd1a40a93c382e72501aMichael Jurka        super.updateCurrentPageScroll();
900ca5b836e16d320f17057cd1a40a93c382e72501aMichael Jurka        computeWallpaperScrollRatio(mCurrentPage);
901ca5b836e16d320f17057cd1a40a93c382e72501aMichael Jurka    }
902ca5b836e16d320f17057cd1a40a93c382e72501aMichael Jurka
903ca5b836e16d320f17057cd1a40a93c382e72501aMichael Jurka    @Override
904ca5b836e16d320f17057cd1a40a93c382e72501aMichael Jurka    protected void snapToPage(int whichPage) {
905ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka        super.snapToPage(whichPage);
906ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka        computeWallpaperScrollRatio(whichPage);
907ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka    }
908ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka
909ca5b836e16d320f17057cd1a40a93c382e72501aMichael Jurka    private void computeWallpaperScrollRatio(int page) {
910ca5b836e16d320f17057cd1a40a93c382e72501aMichael Jurka        // Here, we determine what the desired scroll would be with and without a layout scale,
911ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka        // and compute a ratio between the two. This allows us to adjust the wallpaper offset
912ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka        // as though there is no layout scale.
913ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka        float layoutScale = mLayoutScale;
914ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka        int scaled = getChildOffset(page) - getRelativeChildOffset(page);
915ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka        mLayoutScale = 1.0f;
916ca5b836e16d320f17057cd1a40a93c382e72501aMichael Jurka        float unscaled = getChildOffset(page) - getRelativeChildOffset(page);
917ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka        mLayoutScale = layoutScale;
918ca5b836e16d320f17057cd1a40a93c382e72501aMichael Jurka        if (scaled > 0) {
919ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka            mWallpaperScrollRatio = (1.0f * unscaled) / scaled;
920ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka        } else {
921ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka            mWallpaperScrollRatio = 1f;
922ca5b836e16d320f17057cd1a40a93c382e72501aMichael Jurka        }
923ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka    }
924ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka
925ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka    class WallpaperOffsetInterpolator {
926ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka        float mFinalHorizontalWallpaperOffset = 0.0f;
927ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka        float mFinalVerticalWallpaperOffset = 0.5f;
928ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka        float mHorizontalWallpaperOffset = 0.0f;
929ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka        float mVerticalWallpaperOffset = 0.5f;
930ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka        long mLastWallpaperOffsetUpdateTime;
931ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka        boolean mIsMovingFast;
932ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka        boolean mOverrideHorizontalCatchupConstant;
933ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka        float mHorizontalCatchupConstant = 0.35f;
934ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka        float mVerticalCatchupConstant = 0.35f;
935ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka
936ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka        public WallpaperOffsetInterpolator() {
937ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka        }
938ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka
939ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka        public void setOverrideHorizontalCatchupConstant(boolean override) {
940ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka            mOverrideHorizontalCatchupConstant = override;
941ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka        }
942ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka
943ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka        public void setHorizontalCatchupConstant(float f) {
944ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka            mHorizontalCatchupConstant = f;
945ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka        }
946ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka
947ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka        public void setVerticalCatchupConstant(float f) {
948ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka            mVerticalCatchupConstant = f;
949ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka        }
950ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka
951ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka        public boolean computeScrollOffset() {
952ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka            if (Float.compare(mHorizontalWallpaperOffset, mFinalHorizontalWallpaperOffset) == 0 &&
953ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka                    Float.compare(mVerticalWallpaperOffset, mFinalVerticalWallpaperOffset) == 0) {
954ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka                mIsMovingFast = false;
9558f573952b8729b4319043ae0908997ecd2d68951Dianne Hackborn                return false;
956aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            }
957340c5f3a708efa280a120708594247952ca65182Michael Jurka            boolean isLandscape = mDisplayWidth > mDisplayHeight;
958340c5f3a708efa280a120708594247952ca65182Michael Jurka
959340c5f3a708efa280a120708594247952ca65182Michael Jurka            long currentTime = System.currentTimeMillis();
960beff8c6a13d5b5ad69f5a85ee0150cecd28e6341Adam Cohen            long timeSinceLastUpdate = currentTime - mLastWallpaperOffsetUpdateTime;
961340c5f3a708efa280a120708594247952ca65182Michael Jurka            timeSinceLastUpdate = Math.min((long) (1000/30f), timeSinceLastUpdate);
962340c5f3a708efa280a120708594247952ca65182Michael Jurka            timeSinceLastUpdate = Math.max(1L, timeSinceLastUpdate);
96394f78a5c44c08b258f59b2c78ff6694e5eaca827Patrick Dubroy
964d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka            float xdiff = Math.abs(mFinalHorizontalWallpaperOffset - mHorizontalWallpaperOffset);
9659171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung            if (!mIsMovingFast && xdiff > 0.07) {
9669171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung                mIsMovingFast = true;
9679171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung            }
9689171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung
9699171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung            float fractionToCatchUpIn1MsHorizontal;
9703e7c7634531302271270c8cf418abc959d621cbcMichael Jurka            if (mOverrideHorizontalCatchupConstant) {
971f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen                fractionToCatchUpIn1MsHorizontal = mHorizontalCatchupConstant;
972f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen            } else if (mIsMovingFast) {
97394f78a5c44c08b258f59b2c78ff6694e5eaca827Patrick Dubroy                fractionToCatchUpIn1MsHorizontal = isLandscape ? 0.5f : 0.75f;
974d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka            } else {
9759171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung                // slow
9769171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung                fractionToCatchUpIn1MsHorizontal = isLandscape ? 0.27f : 0.5f;
9779171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung            }
9789171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung            float fractionToCatchUpIn1MsVertical = mVerticalCatchupConstant;
9799171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung
9809171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung            fractionToCatchUpIn1MsHorizontal /= 33f;
9813e7c7634531302271270c8cf418abc959d621cbcMichael Jurka            fractionToCatchUpIn1MsVertical /= 33f;
982f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen
983f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen            final float UPDATE_THRESHOLD = 0.00001f;
98494f78a5c44c08b258f59b2c78ff6694e5eaca827Patrick Dubroy            float hOffsetDelta = mFinalHorizontalWallpaperOffset - mHorizontalWallpaperOffset;
98594f78a5c44c08b258f59b2c78ff6694e5eaca827Patrick Dubroy            float vOffsetDelta = mFinalVerticalWallpaperOffset - mVerticalWallpaperOffset;
98694f78a5c44c08b258f59b2c78ff6694e5eaca827Patrick Dubroy            boolean jumpToFinalValue = Math.abs(hOffsetDelta) < UPDATE_THRESHOLD &&
98794f78a5c44c08b258f59b2c78ff6694e5eaca827Patrick Dubroy                Math.abs(vOffsetDelta) < UPDATE_THRESHOLD;
98894f78a5c44c08b258f59b2c78ff6694e5eaca827Patrick Dubroy
98994f78a5c44c08b258f59b2c78ff6694e5eaca827Patrick Dubroy            // Don't have any lag between workspace and wallpaper on non-large devices
9909171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung            if (!LauncherApplication.isScreenLarge() || jumpToFinalValue) {
9919171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung                mHorizontalWallpaperOffset = mFinalHorizontalWallpaperOffset;
992f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen                mVerticalWallpaperOffset = mFinalVerticalWallpaperOffset;
993f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen            } else {
994f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen                float percentToCatchUpVertical =
995f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen                    Math.min(1.0f, timeSinceLastUpdate * fractionToCatchUpIn1MsVertical);
996f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen                float percentToCatchUpHorizontal =
997f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen                    Math.min(1.0f, timeSinceLastUpdate * fractionToCatchUpIn1MsHorizontal);
9989171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung                mHorizontalWallpaperOffset += percentToCatchUpHorizontal * hOffsetDelta;
9999171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung                mVerticalWallpaperOffset += percentToCatchUpVertical * vOffsetDelta;
10009171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung            }
10019171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung
10029c6fbed48783dacd9bc6b4ec5f2cc8e59ec7ee37Michael Jurka            mLastWallpaperOffsetUpdateTime = System.currentTimeMillis();
10039c6fbed48783dacd9bc6b4ec5f2cc8e59ec7ee37Michael Jurka            return true;
10049c6fbed48783dacd9bc6b4ec5f2cc8e59ec7ee37Michael Jurka        }
10059c6fbed48783dacd9bc6b4ec5f2cc8e59ec7ee37Michael Jurka
10069c6fbed48783dacd9bc6b4ec5f2cc8e59ec7ee37Michael Jurka        public float getCurrX() {
10079c6fbed48783dacd9bc6b4ec5f2cc8e59ec7ee37Michael Jurka            return mHorizontalWallpaperOffset;
10089c6fbed48783dacd9bc6b4ec5f2cc8e59ec7ee37Michael Jurka        }
10097bdb25a9894970da74248c9cdc606d0e1ba05c99Michael Jurka
1010b4b7fa7c0383b6af58d73d3e024b91d586148cf8Winson Chung        public float getFinalX() {
1011b9e14974ae5c03bd996bc102ed23a24126449990Michael Jurka            return mFinalHorizontalWallpaperOffset;
1012b9e14974ae5c03bd996bc102ed23a24126449990Michael Jurka        }
1013b9e14974ae5c03bd996bc102ed23a24126449990Michael Jurka
1014b9e14974ae5c03bd996bc102ed23a24126449990Michael Jurka        public float getCurrY() {
1015b9e14974ae5c03bd996bc102ed23a24126449990Michael Jurka            return mVerticalWallpaperOffset;
1016b9e14974ae5c03bd996bc102ed23a24126449990Michael Jurka        }
1017b9e14974ae5c03bd996bc102ed23a24126449990Michael Jurka
1018b9e14974ae5c03bd996bc102ed23a24126449990Michael Jurka        public float getFinalY() {
10197bdb25a9894970da74248c9cdc606d0e1ba05c99Michael Jurka            return mFinalVerticalWallpaperOffset;
10207bdb25a9894970da74248c9cdc606d0e1ba05c99Michael Jurka        }
10217bdb25a9894970da74248c9cdc606d0e1ba05c99Michael Jurka
10227bdb25a9894970da74248c9cdc606d0e1ba05c99Michael Jurka        public void setFinalX(float x) {
10237bdb25a9894970da74248c9cdc606d0e1ba05c99Michael Jurka            mFinalHorizontalWallpaperOffset = Math.max(0f, Math.min(x, 1.0f));
10247bdb25a9894970da74248c9cdc606d0e1ba05c99Michael Jurka        }
10257bdb25a9894970da74248c9cdc606d0e1ba05c99Michael Jurka
10267bdb25a9894970da74248c9cdc606d0e1ba05c99Michael Jurka        public void setFinalY(float y) {
10277bdb25a9894970da74248c9cdc606d0e1ba05c99Michael Jurka            mFinalVerticalWallpaperOffset = Math.max(0f, Math.min(y, 1.0f));
10287bdb25a9894970da74248c9cdc606d0e1ba05c99Michael Jurka        }
10297bdb25a9894970da74248c9cdc606d0e1ba05c99Michael Jurka
10307bdb25a9894970da74248c9cdc606d0e1ba05c99Michael Jurka        public void jumpToFinal() {
10317bdb25a9894970da74248c9cdc606d0e1ba05c99Michael Jurka            mHorizontalWallpaperOffset = mFinalHorizontalWallpaperOffset;
10327bdb25a9894970da74248c9cdc606d0e1ba05c99Michael Jurka            mVerticalWallpaperOffset = mFinalVerticalWallpaperOffset;
10337bdb25a9894970da74248c9cdc606d0e1ba05c99Michael Jurka        }
1034b9e14974ae5c03bd996bc102ed23a24126449990Michael Jurka    }
10359171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung
10369171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung    @Override
10379171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung    public void computeScroll() {
10389c6fbed48783dacd9bc6b4ec5f2cc8e59ec7ee37Michael Jurka        super.computeScroll();
10399c6fbed48783dacd9bc6b4ec5f2cc8e59ec7ee37Michael Jurka        syncWallpaperOffsetWithScroll();
10409c6fbed48783dacd9bc6b4ec5f2cc8e59ec7ee37Michael Jurka    }
10419c6fbed48783dacd9bc6b4ec5f2cc8e59ec7ee37Michael Jurka
10429171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung    void showOutlines() {
10439171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung        if (!isSmall() && !mIsSwitchingState) {
1044f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen            if (mChildrenOutlineFadeOutAnimation != null) mChildrenOutlineFadeOutAnimation.cancel();
1045f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen            if (mChildrenOutlineFadeInAnimation != null) mChildrenOutlineFadeInAnimation.cancel();
1046f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen            mChildrenOutlineFadeInAnimation = ObjectAnimator.ofFloat(this, "childrenOutlineAlpha", 1.0f);
1047f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen            mChildrenOutlineFadeInAnimation.setDuration(CHILDREN_OUTLINE_FADE_IN_DURATION);
10486b879f0a5885274a85333531e091283405d490ccAdam Lesinski            mChildrenOutlineFadeInAnimation.start();
10496b879f0a5885274a85333531e091283405d490ccAdam Lesinski        }
10506b879f0a5885274a85333531e091283405d490ccAdam Lesinski    }
10516b879f0a5885274a85333531e091283405d490ccAdam Lesinski
10526b879f0a5885274a85333531e091283405d490ccAdam Lesinski    void hideOutlines() {
10536b879f0a5885274a85333531e091283405d490ccAdam Lesinski        if (!isSmall() && !mIsSwitchingState) {
10546b879f0a5885274a85333531e091283405d490ccAdam Lesinski            if (mChildrenOutlineFadeInAnimation != null) mChildrenOutlineFadeInAnimation.cancel();
10556b879f0a5885274a85333531e091283405d490ccAdam Lesinski            if (mChildrenOutlineFadeOutAnimation != null) mChildrenOutlineFadeOutAnimation.cancel();
10566b879f0a5885274a85333531e091283405d490ccAdam Lesinski            mChildrenOutlineFadeOutAnimation = ObjectAnimator.ofFloat(this, "childrenOutlineAlpha", 0.0f);
10576b879f0a5885274a85333531e091283405d490ccAdam Lesinski            mChildrenOutlineFadeOutAnimation.setDuration(CHILDREN_OUTLINE_FADE_OUT_DURATION);
10586b879f0a5885274a85333531e091283405d490ccAdam Lesinski            mChildrenOutlineFadeOutAnimation.setStartDelay(CHILDREN_OUTLINE_FADE_OUT_DELAY);
10596b879f0a5885274a85333531e091283405d490ccAdam Lesinski            mChildrenOutlineFadeOutAnimation.start();
10606b879f0a5885274a85333531e091283405d490ccAdam Lesinski        }
10616b879f0a5885274a85333531e091283405d490ccAdam Lesinski    }
10626b879f0a5885274a85333531e091283405d490ccAdam Lesinski
10636b879f0a5885274a85333531e091283405d490ccAdam Lesinski    public void showOutlinesTemporarily() {
10646b879f0a5885274a85333531e091283405d490ccAdam Lesinski        if (!mIsPageMoving && !isTouchActive()) {
10656b879f0a5885274a85333531e091283405d490ccAdam Lesinski            snapToPage(mCurrentPage);
10666b879f0a5885274a85333531e091283405d490ccAdam Lesinski        }
10676b879f0a5885274a85333531e091283405d490ccAdam Lesinski    }
10686b879f0a5885274a85333531e091283405d490ccAdam Lesinski
10696b879f0a5885274a85333531e091283405d490ccAdam Lesinski    public void setChildrenOutlineAlpha(float alpha) {
10706b879f0a5885274a85333531e091283405d490ccAdam Lesinski        mChildrenOutlineAlpha = alpha;
10716b879f0a5885274a85333531e091283405d490ccAdam Lesinski        for (int i = 0; i < getChildCount(); i++) {
10726b879f0a5885274a85333531e091283405d490ccAdam Lesinski            CellLayout cl = (CellLayout) getChildAt(i);
107368d739365bf650fe7fecf99cd3bfe63a0d41bd12Adam Cohen            cl.setBackgroundAlpha(alpha);
107468d739365bf650fe7fecf99cd3bfe63a0d41bd12Adam Cohen        }
107568d739365bf650fe7fecf99cd3bfe63a0d41bd12Adam Cohen    }
107668d739365bf650fe7fecf99cd3bfe63a0d41bd12Adam Cohen
107768d739365bf650fe7fecf99cd3bfe63a0d41bd12Adam Cohen    public float getChildrenOutlineAlpha() {
107868d739365bf650fe7fecf99cd3bfe63a0d41bd12Adam Cohen        return mChildrenOutlineAlpha;
107968d739365bf650fe7fecf99cd3bfe63a0d41bd12Adam Cohen    }
108068d739365bf650fe7fecf99cd3bfe63a0d41bd12Adam Cohen
108168d739365bf650fe7fecf99cd3bfe63a0d41bd12Adam Cohen    void disableBackground() {
108268d739365bf650fe7fecf99cd3bfe63a0d41bd12Adam Cohen        mDrawBackground = false;
108368d739365bf650fe7fecf99cd3bfe63a0d41bd12Adam Cohen    }
108468d739365bf650fe7fecf99cd3bfe63a0d41bd12Adam Cohen    void enableBackground() {
108568d739365bf650fe7fecf99cd3bfe63a0d41bd12Adam Cohen        mDrawBackground = true;
1086e0f66b546994a9bdee452851c17a148db02ec300Adam Cohen    }
108768d739365bf650fe7fecf99cd3bfe63a0d41bd12Adam Cohen
108868d739365bf650fe7fecf99cd3bfe63a0d41bd12Adam Cohen    private void animateBackgroundGradient(float finalAlpha, boolean animated) {
108968d739365bf650fe7fecf99cd3bfe63a0d41bd12Adam Cohen        if (mBackground == null) return;
109068d739365bf650fe7fecf99cd3bfe63a0d41bd12Adam Cohen        if (mBackgroundFadeInAnimation != null) {
109168d739365bf650fe7fecf99cd3bfe63a0d41bd12Adam Cohen            mBackgroundFadeInAnimation.cancel();
109268d739365bf650fe7fecf99cd3bfe63a0d41bd12Adam Cohen            mBackgroundFadeInAnimation = null;
109368d739365bf650fe7fecf99cd3bfe63a0d41bd12Adam Cohen        }
109468d739365bf650fe7fecf99cd3bfe63a0d41bd12Adam Cohen        if (mBackgroundFadeOutAnimation != null) {
109568d739365bf650fe7fecf99cd3bfe63a0d41bd12Adam Cohen            mBackgroundFadeOutAnimation.cancel();
109668d739365bf650fe7fecf99cd3bfe63a0d41bd12Adam Cohen            mBackgroundFadeOutAnimation = null;
1097f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen        }
1098f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen        float startAlpha = getBackgroundAlpha();
1099007c69867d821ea2b271398577a8b3440b3a7046Winson Chung        if (finalAlpha != startAlpha) {
1100007c69867d821ea2b271398577a8b3440b3a7046Winson Chung            if (animated) {
1101c3bc26031cc5b36328bd7cdbcf04ff269dea11a5Adam Cohen                mBackgroundFadeOutAnimation = ValueAnimator.ofFloat(startAlpha, finalAlpha);
1102785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung                mBackgroundFadeOutAnimation.addUpdateListener(new AnimatorUpdateListener() {
1103785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung                    public void onAnimationUpdate(ValueAnimator animation) {
1104a2eb17095dcffa75c1e9681fdc318fe6e0564321Michael Jurka                        setBackgroundAlpha(((Float) animation.getAnimatedValue()).floatValue());
1105c3bc26031cc5b36328bd7cdbcf04ff269dea11a5Adam Cohen                    }
110621f12b52a54d2658ed14fcf7bb1ca17a198f62beAdam Cohen                });
110768d739365bf650fe7fecf99cd3bfe63a0d41bd12Adam Cohen                mBackgroundFadeOutAnimation.setInterpolator(new DecelerateInterpolator(1.5f));
110821f12b52a54d2658ed14fcf7bb1ca17a198f62beAdam Cohen                mBackgroundFadeOutAnimation.setDuration(BACKGROUND_FADE_OUT_DURATION);
11091b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen                mBackgroundFadeOutAnimation.start();
11101b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen            } else {
1111d3ef3065ab0941567c45e9aec98783138b623c68Michael Jurka                setBackgroundAlpha(finalAlpha);
111221f12b52a54d2658ed14fcf7bb1ca17a198f62beAdam Cohen            }
111321f12b52a54d2658ed14fcf7bb1ca17a198f62beAdam Cohen        }
1114f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen    }
1115ddb821981e0919bbd3b4c9a2b6aa1811d6c86bb6Adam Cohen
111621f12b52a54d2658ed14fcf7bb1ca17a198f62beAdam Cohen    public void setBackgroundAlpha(float alpha) {
111721f12b52a54d2658ed14fcf7bb1ca17a198f62beAdam Cohen        if (alpha != mBackgroundAlpha) {
1118f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen            mBackgroundAlpha = alpha;
11197777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen            invalidate();
11207cfc2825c3a1029f962d2fc387ae2eaa85b51798Michael Jurka        }
11217cfc2825c3a1029f962d2fc387ae2eaa85b51798Michael Jurka    }
11227cfc2825c3a1029f962d2fc387ae2eaa85b51798Michael Jurka
11237cfc2825c3a1029f962d2fc387ae2eaa85b51798Michael Jurka    public float getBackgroundAlpha() {
11247cfc2825c3a1029f962d2fc387ae2eaa85b51798Michael Jurka        return mBackgroundAlpha;
11257cfc2825c3a1029f962d2fc387ae2eaa85b51798Michael Jurka    }
11267cfc2825c3a1029f962d2fc387ae2eaa85b51798Michael Jurka
11277cfc2825c3a1029f962d2fc387ae2eaa85b51798Michael Jurka    /**
11287cfc2825c3a1029f962d2fc387ae2eaa85b51798Michael Jurka     * Due to 3D transformations, if two CellLayouts are theoretically touching each other,
11297cfc2825c3a1029f962d2fc387ae2eaa85b51798Michael Jurka     * on the xy plane, when one is rotated along the y-axis, the gap between them is perceived
11307cfc2825c3a1029f962d2fc387ae2eaa85b51798Michael Jurka     * as being larger. This method computes what offset the rotated view should be translated
1131e0f66b546994a9bdee452851c17a148db02ec300Adam Cohen     * in order to minimize this perceived gap.
11321b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen     * @param degrees Angle of the view
113321f12b52a54d2658ed14fcf7bb1ca17a198f62beAdam Cohen     * @param width Width of the view
11346b879f0a5885274a85333531e091283405d490ccAdam Lesinski     * @param height Height of the view
11356b879f0a5885274a85333531e091283405d490ccAdam Lesinski     * @return Offset to be used in a View.setTranslationX() call
113668d739365bf650fe7fecf99cd3bfe63a0d41bd12Adam Cohen     */
11371b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen    private float getOffsetXForRotation(float degrees, int width, int height) {
1138f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen        mMatrix.reset();
1139f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen        mCamera.save();
1140f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen        mCamera.rotateY(Math.abs(degrees));
1141f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen        mCamera.getMatrix(mMatrix);
114200acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        mCamera.restore();
114300acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
11449c6fbed48783dacd9bc6b4ec5f2cc8e59ec7ee37Michael Jurka        mMatrix.preTranslate(-width * 0.5f, -height * 0.5f);
1145956091ba7863bd72086275e61084864994dd6fa7Joe Onorato        mMatrix.postTranslate(width * 0.5f, height * 0.5f);
11469c6fbed48783dacd9bc6b4ec5f2cc8e59ec7ee37Michael Jurka        mTempFloat2[0] = width;
11479c6fbed48783dacd9bc6b4ec5f2cc8e59ec7ee37Michael Jurka        mTempFloat2[1] = height;
11489c6fbed48783dacd9bc6b4ec5f2cc8e59ec7ee37Michael Jurka        mMatrix.mapPoints(mTempFloat2);
11499c6fbed48783dacd9bc6b4ec5f2cc8e59ec7ee37Michael Jurka        return (width - mTempFloat2[0]) * (degrees > 0.0f ? 1.0f : -1.0f);
11509c6fbed48783dacd9bc6b4ec5f2cc8e59ec7ee37Michael Jurka    }
115100acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato
115200acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato    float backgroundAlphaInterpolator(float r) {
115331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        float pivotA = 0.1f;
115428750fba6a2d141eb9a1e566718c17236030b815Michael Jurka        float pivotB = 0.4f;
1155c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka        if (r < pivotA) {
1156c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka            return 0;
1157c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka        } else if (r > pivotB) {
11580142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka            return 1.0f;
1159aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        } else {
116079212d81361d1ad8c941c48f8323eb526643ca68Michael Jurka            return (r - pivotA)/(pivotB - pivotA);
116179212d81361d1ad8c941c48f8323eb526643ca68Michael Jurka        }
1162d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka    }
1163d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka
1164696a67969d657d38eff33996633f08da0e21841fAdam Cohen    float overScrollBackgroundAlphaInterpolator(float r) {
1165696a67969d657d38eff33996633f08da0e21841fAdam Cohen        float threshold = 0.08f;
1166696a67969d657d38eff33996633f08da0e21841fAdam Cohen
1167696a67969d657d38eff33996633f08da0e21841fAdam Cohen        if (r > mOverScrollMaxBackgroundAlpha) {
11687777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen            mOverScrollMaxBackgroundAlpha = r;
1169696a67969d657d38eff33996633f08da0e21841fAdam Cohen        } else if (r < mOverScrollMaxBackgroundAlpha) {
1170696a67969d657d38eff33996633f08da0e21841fAdam Cohen            r = mOverScrollMaxBackgroundAlpha;
117179212d81361d1ad8c941c48f8323eb526643ca68Michael Jurka        }
117231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
117331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        return Math.min(r / threshold, 1.0f);
117431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
11759171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung
1176ab1983f46ce0ee0c94ea1170d21a67eb4e3c7967Michael Jurka    private void screenScrolledLargeUI(int screenCenter) {
1177c5b262ccf639fedac2aff5bb8238342f95396338Michael Jurka        if (isSwitchingState()) return;
11789171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung        boolean isInOverscroll = false;
11799c6fbed48783dacd9bc6b4ec5f2cc8e59ec7ee37Michael Jurka        for (int i = 0; i < getChildCount(); i++) {
11808d006d5e144ae33e509ea42e0b9760ef6c5bc884Winson Chung            CellLayout cl = (CellLayout) getChildAt(i);
1181f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung            if (cl != null) {
1182f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung                float scrollProgress = getScrollProgress(screenCenter, cl, i);
1183f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung                float rotation = WORKSPACE_ROTATION * scrollProgress;
1184f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung                float translationX = getOffsetXForRotation(rotation, cl.getWidth(), cl.getHeight());
11859171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung
1186073a46ff635d089cbcb15d939d1de42dd2b86c97Adam Cohen                // If the current page (i) is being over scrolled, we use a different
11879171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung                // set of rules for setting the background alpha multiplier.
11889171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung                if (!isSmall()) {
11899171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung                    if ((mOverScrollX < 0 && i == 0) || (mOverScrollX > mMaxScrollX &&
11909171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung                            i == getChildCount() -1)) {
11910142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka                        isInOverscroll = true;
1192557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung                        rotation *= -1;
1193557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung                        cl.setBackgroundAlphaMultiplier(
1194557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung                                overScrollBackgroundAlphaInterpolator(Math.abs(scrollProgress)));
1195557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung                        mOverScrollPageIndex = i;
1196557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung                        cl.setOverScrollAmount(Math.abs(scrollProgress), i == 0);
1197557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung                        cl.setPivotX(cl.getMeasuredWidth() * (i == 0 ? 0.75f : 0.25f));
1198557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung                        cl.setPivotY(cl.getMeasuredHeight() * 0.5f);
1199557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung                        cl.setOverscrollTransformsDirty(true);
1200557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung                    } else if (mOverScrollPageIndex != i) {
1201557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung                        cl.setBackgroundAlphaMultiplier(
1202557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung                                backgroundAlphaInterpolator(Math.abs(scrollProgress)));
1203557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung                    }
1204557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung                }
1205557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung                cl.setTranslationX(translationX);
1206557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung                cl.setRotationY(rotation);
1207557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung                if (mFadeInAdjacentScreens && !isSmall()) {
1208557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung                    float alpha = 1 - Math.abs(scrollProgress);
1209557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung                    cl.setShortcutAndWidgetAlpha(alpha);
1210557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung                }
1211557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung            }
1212557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung        }
12130207c522472d7252f146f4d39efa456ca5248c6bPatrick Dubroy        if (!isSwitchingState() && !isInOverscroll) {
121431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            ((CellLayout) getChildAt(0)).resetOverscrollTransforms();
121531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            ((CellLayout) getChildAt(getChildCount() - 1)).resetOverscrollTransforms();
121631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
121731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        invalidate();
121831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
1219678862186af4ea70d9b4012c9bc127e7fea5e607Joe Onorato
122031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private void screenScrolledStandardUI(int screenCenter) {
122131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        if (mOverScrollX < 0 || mOverScrollX > mMaxScrollX) {
122231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            int index = mOverScrollX < 0 ? 0 : getChildCount() - 1;
122331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            CellLayout cl = (CellLayout) getChildAt(index);
12240142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka            float scrollProgress = getScrollProgress(screenCenter, cl, index);
122531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            cl.setOverScrollAmount(Math.abs(scrollProgress), index == 0);
122631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            float rotation = - WORKSPACE_OVERSCROLL_ROTATION * scrollProgress;
122731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            cl.setCameraDistance(mDensity * CAMERA_DISTANCE);
122831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            cl.setPivotX(cl.getMeasuredWidth() * (index == 0 ? 0.75f : 0.25f));
122931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            cl.setPivotY(cl.getMeasuredHeight() * 0.5f);
123031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            cl.setRotationY(rotation);
123197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            cl.setOverscrollTransformsDirty(true);
1232d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka            setFadeForOverScroll(Math.abs(scrollProgress));
123397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        } else {
123497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            if (mOverscrollFade != 0) {
123597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                setFadeForOverScroll(0);
123697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            }
123797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            // We don't want to mess with the translations during transitions
123897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            if (!isSwitchingState()) {
1239c2e24c0a37ddeab930f731c062705d435e477f75Romain Guy                ((CellLayout) getChildAt(0)).resetOverscrollTransforms();
1240678862186af4ea70d9b4012c9bc127e7fea5e607Joe Onorato                ((CellLayout) getChildAt(getChildCount() - 1)).resetOverscrollTransforms();
124131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            }
12420142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka        }
124331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
12440142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka
12450142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka    @Override
124631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    protected void screenScrolled(int screenCenter) {
124731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        if (LauncherApplication.isScreenLarge()) {
124831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            // We don't call super.screenScrolled() here because we handle the adjacent pages alpha
124931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            // ourselves (for efficiency), and there are no scrolling indicators to update.
1250d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka            screenScrolledLargeUI(screenCenter);
12513384c7be3cf735f68a90d835627350fa48b94d48Adam Cohen        } else {
1252d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka            super.screenScrolled(screenCenter);
1253d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka            screenScrolledStandardUI(screenCenter);
12540142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka        }
12550142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka    }
12560142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka
12570142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka    @Override
12580142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka    protected void overScroll(float amount) {
12593a2b3f2be58843d26549fb0ec6c6533627c7cd19Mike Cleron        if (LauncherApplication.isScreenLarge()) {
1260aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            dampedOverScroll(amount);
1261dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka        } else {
1262fea5d0250767ab938f623a404e6292a32dd2fdf5Adam Powell            acceleratedOverScroll(amount);
12630142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka        }
12640142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka    }
1265fea5d0250767ab938f623a404e6292a32dd2fdf5Adam Powell
12660142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka    protected void onAttachedToWindow() {
126731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        super.onAttachedToWindow();
126831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        mWindowToken = getWindowToken();
126931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        computeScroll();
127031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        mDragController.setWindowToken(mWindowToken);
127131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
127231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
127331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    protected void onDetachedFromWindow() {
1274dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka        mWindowToken = null;
1275dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    }
127631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
127731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
12788182e5bc3c2d1a0140df345599b89369d457bb4aAdam Cohen    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
12798182e5bc3c2d1a0140df345599b89369d457bb4aAdam Cohen        if (mFirstLayout && mCurrentPage >= 0 && mCurrentPage < getChildCount()) {
12808182e5bc3c2d1a0140df345599b89369d457bb4aAdam Cohen            mUpdateWallpaperOffsetImmediately = true;
12818182e5bc3c2d1a0140df345599b89369d457bb4aAdam Cohen        }
128231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        super.onLayout(changed, left, top, right, bottom);
128331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
128431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
1285d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka    @Override
12867777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen    protected void onDraw(Canvas canvas) {
1287d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka        updateWallpaperOffsets();
1288d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka
1289d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka        // Draw the background gradient if necessary
1290d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka        if (mBackground != null && mBackgroundAlpha > 0.0f && mDrawBackground) {
1291d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka            int alpha = (int) (mBackgroundAlpha * 255);
1292d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka            mBackground.setAlpha(alpha);
1293d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka            mBackground.setBounds(mScrollX, 0, mScrollX + getMeasuredWidth(),
1294d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka                    getMeasuredHeight());
1295ce7e05fbe8abd5f25ec47e0e05b5cc76ceb39d2eMichael Jurka            mBackground.draw(canvas);
1296ce7e05fbe8abd5f25ec47e0e05b5cc76ceb39d2eMichael Jurka        }
1297ce7e05fbe8abd5f25ec47e0e05b5cc76ceb39d2eMichael Jurka
12981d0867c8de6a889bccde9b7e768daef182a25e5cJeff Brown        super.onDraw(canvas);
12991d0867c8de6a889bccde9b7e768daef182a25e5cJeff Brown    }
13001d0867c8de6a889bccde9b7e768daef182a25e5cJeff Brown
13011d0867c8de6a889bccde9b7e768daef182a25e5cJeff Brown    boolean isDrawingBackgroundGradient() {
13021d0867c8de6a889bccde9b7e768daef182a25e5cJeff Brown        return (mBackground != null && mBackgroundAlpha > 0.0f && mDrawBackground);
13031d0867c8de6a889bccde9b7e768daef182a25e5cJeff Brown    }
13041d0867c8de6a889bccde9b7e768daef182a25e5cJeff Brown
13051d0867c8de6a889bccde9b7e768daef182a25e5cJeff Brown    @Override
13061d0867c8de6a889bccde9b7e768daef182a25e5cJeff Brown    protected void dispatchDraw(Canvas canvas) {
13071d0867c8de6a889bccde9b7e768daef182a25e5cJeff Brown        super.dispatchDraw(canvas);
13081d0867c8de6a889bccde9b7e768daef182a25e5cJeff Brown
13091d0867c8de6a889bccde9b7e768daef182a25e5cJeff Brown        if (mInScrollArea && !LauncherApplication.isScreenLarge()) {
13101d0867c8de6a889bccde9b7e768daef182a25e5cJeff Brown            final int width = getWidth();
13111d0867c8de6a889bccde9b7e768daef182a25e5cJeff Brown            final int height = getHeight();
1312c1a036b5ebacdeb564502bacc740fd85803a7638Michael Jurka            final int pageHeight = getChildAt(0).getHeight();
1313c1a036b5ebacdeb564502bacc740fd85803a7638Michael Jurka
1314c1a036b5ebacdeb564502bacc740fd85803a7638Michael Jurka            // Set the height of the outline to be the height of the page
1315c1a036b5ebacdeb564502bacc740fd85803a7638Michael Jurka            final int offset = (height - pageHeight - mPaddingTop - mPaddingBottom) / 2;
1316c1a036b5ebacdeb564502bacc740fd85803a7638Michael Jurka            final int paddingTop = mPaddingTop + offset;
1317c1a036b5ebacdeb564502bacc740fd85803a7638Michael Jurka            final int paddingBottom = mPaddingBottom + offset;
1318c1a036b5ebacdeb564502bacc740fd85803a7638Michael Jurka
131961033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen            final int page = (mNextPage != INVALID_PAGE ? mNextPage : mCurrentPage);
132061033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen            final CellLayout leftPage = (CellLayout) getChildAt(page - 1);
132161033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen            final CellLayout rightPage = (CellLayout) getChildAt(page + 1);
132261033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen
132361033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen            if (leftPage != null && leftPage.getIsDragOverlapping()) {
132461033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen                final Drawable d = getResources().getDrawable(R.drawable.page_hover_left_holo);
132561033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen                d.setBounds(mScrollX, paddingTop, mScrollX + d.getIntrinsicWidth(),
132661033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen                        height - paddingBottom);
132761033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen                d.draw(canvas);
132861033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen            } else if (rightPage != null && rightPage.getIsDragOverlapping()) {
132961033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen                final Drawable d = getResources().getDrawable(R.drawable.page_hover_right_holo);
133061033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen                d.setBounds(mScrollX + width - d.getIntrinsicWidth(), paddingTop, mScrollX + width,
133161033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen                        height - paddingBottom);
1332eed565d5126cb40b2a7ecdf5f6e8ac7a7464007bAdam Cohen                d.draw(canvas);
1333eed565d5126cb40b2a7ecdf5f6e8ac7a7464007bAdam Cohen            }
133461033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen        }
1335cbbaf9862aa160c5e397cb49b554de20981a35feAdam Cohen    }
1336cbbaf9862aa160c5e397cb49b554de20981a35feAdam Cohen
1337cbbaf9862aa160c5e397cb49b554de20981a35feAdam Cohen    @Override
133861033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen    protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
133961033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen        if (!mLauncher.isAllAppsVisible()) {
134061033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen            final Folder openFolder = getOpenFolder();
134161033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen            if (openFolder != null) {
134261033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen                return openFolder.requestFocus(direction, previouslyFocusedRect);
134361033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen            } else {
134461033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen                return super.onRequestFocusInDescendants(direction, previouslyFocusedRect);
134561033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen            }
1346cbbaf9862aa160c5e397cb49b554de20981a35feAdam Cohen        }
134761033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen        return false;
1348cbbaf9862aa160c5e397cb49b554de20981a35feAdam Cohen    }
1349cbbaf9862aa160c5e397cb49b554de20981a35feAdam Cohen
1350cbbaf9862aa160c5e397cb49b554de20981a35feAdam Cohen    @Override
135161033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen    public int getDescendantFocusability() {
135261033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen        if (isSmall()) {
135361033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen            return ViewGroup.FOCUS_BLOCK_DESCENDANTS;
135461033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen        }
135561033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen        return super.getDescendantFocusability();
1356ea57348cc8f4647f6bc35a42cd45662ddb828b92Michael Jurka    }
135761033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen
135861033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen    @Override
135961033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen    public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
136061033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen        if (!mLauncher.isAllAppsVisible()) {
136161033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen            final Folder openFolder = getOpenFolder();
136261033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen            if (openFolder != null) {
136361033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen                openFolder.addFocusables(views, direction);
136461033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen            } else {
136561033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen                super.addFocusables(views, direction, focusableMode);
136661033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen            }
136761033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen        }
136861033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen    }
136961033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen
137061033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen    public boolean isSmall() {
137161033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen        return mState == State.SMALL || mState == State.SPRING_LOADED;
137261033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen    }
137361033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen
137461033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen    void enableChildrenCache(int fromPage, int toPage) {
137561033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen        if (fromPage > toPage) {
13763e7c7634531302271270c8cf418abc959d621cbcMichael Jurka            final int temp = fromPage;
13773e7c7634531302271270c8cf418abc959d621cbcMichael Jurka            fromPage = toPage;
13786639687cd67bab1aeef2a75e5c6bc458b20dc082Adam Cohen            toPage = temp;
13796639687cd67bab1aeef2a75e5c6bc458b20dc082Adam Cohen        }
13806639687cd67bab1aeef2a75e5c6bc458b20dc082Adam Cohen
13816639687cd67bab1aeef2a75e5c6bc458b20dc082Adam Cohen        final int screenCount = getChildCount();
13826639687cd67bab1aeef2a75e5c6bc458b20dc082Adam Cohen
13836639687cd67bab1aeef2a75e5c6bc458b20dc082Adam Cohen        fromPage = Math.max(fromPage, 0);
13846639687cd67bab1aeef2a75e5c6bc458b20dc082Adam Cohen        toPage = Math.min(toPage, screenCount - 1);
13856639687cd67bab1aeef2a75e5c6bc458b20dc082Adam Cohen
13866639687cd67bab1aeef2a75e5c6bc458b20dc082Adam Cohen        for (int i = fromPage; i <= toPage; i++) {
13876639687cd67bab1aeef2a75e5c6bc458b20dc082Adam Cohen            final CellLayout layout = (CellLayout) getChildAt(i);
13886639687cd67bab1aeef2a75e5c6bc458b20dc082Adam Cohen            layout.setChildrenDrawnWithCacheEnabled(true);
13896639687cd67bab1aeef2a75e5c6bc458b20dc082Adam Cohen            layout.setChildrenDrawingCacheEnabled(true);
13906639687cd67bab1aeef2a75e5c6bc458b20dc082Adam Cohen        }
13916639687cd67bab1aeef2a75e5c6bc458b20dc082Adam Cohen    }
13926639687cd67bab1aeef2a75e5c6bc458b20dc082Adam Cohen
13936639687cd67bab1aeef2a75e5c6bc458b20dc082Adam Cohen    void clearChildrenCache() {
13946639687cd67bab1aeef2a75e5c6bc458b20dc082Adam Cohen        final int screenCount = getChildCount();
13956639687cd67bab1aeef2a75e5c6bc458b20dc082Adam Cohen        for (int i = 0; i < screenCount; i++) {
1396d3ef3065ab0941567c45e9aec98783138b623c68Michael Jurka            final CellLayout layout = (CellLayout) getChildAt(i);
1397d3ef3065ab0941567c45e9aec98783138b623c68Michael Jurka            layout.setChildrenDrawnWithCacheEnabled(false);
13983e7c7634531302271270c8cf418abc959d621cbcMichael Jurka            // In software mode, we don't want the items to continue to be drawn into bitmaps
1399d3ef3065ab0941567c45e9aec98783138b623c68Michael Jurka            if (!isHardwareAccelerated()) {
140038b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka                layout.setChildrenDrawingCacheEnabled(false);
1401d3ef3065ab0941567c45e9aec98783138b623c68Michael Jurka            }
1402f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka        }
14036639687cd67bab1aeef2a75e5c6bc458b20dc082Adam Cohen    }
14046639687cd67bab1aeef2a75e5c6bc458b20dc082Adam Cohen
14056639687cd67bab1aeef2a75e5c6bc458b20dc082Adam Cohen    private void updateChildrenLayersEnabled() {
1406d3ef3065ab0941567c45e9aec98783138b623c68Michael Jurka        boolean small = isSmall() || mIsSwitchingState;
14076639687cd67bab1aeef2a75e5c6bc458b20dc082Adam Cohen        boolean dragging = mAnimatingViewIntoPlace || mIsDragOccuring;
14083e7c7634531302271270c8cf418abc959d621cbcMichael Jurka        boolean enableChildrenLayers = small || dragging || isPageMoving();
14093e7c7634531302271270c8cf418abc959d621cbcMichael Jurka
14103e7c7634531302271270c8cf418abc959d621cbcMichael Jurka        if (enableChildrenLayers != mChildrenLayersEnabled) {
14113e7c7634531302271270c8cf418abc959d621cbcMichael Jurka            mChildrenLayersEnabled = enableChildrenLayers;
14127bccb42f88cbbaf8cf180a876e8c5d5e306ce62aPatrick Dubroy            for (int i = 0; i < getPageCount(); i++) {
14137bccb42f88cbbaf8cf180a876e8c5d5e306ce62aPatrick Dubroy                ((ViewGroup)getChildAt(i)).setChildrenLayersEnabled(mChildrenLayersEnabled);
14147bccb42f88cbbaf8cf180a876e8c5d5e306ce62aPatrick Dubroy            }
1415c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        }
14167bccb42f88cbbaf8cf180a876e8c5d5e306ce62aPatrick Dubroy    }
14173e7c7634531302271270c8cf418abc959d621cbcMichael Jurka
14183e7c7634531302271270c8cf418abc959d621cbcMichael Jurka    protected void onWallpaperTap(MotionEvent ev) {
1419758a9239f045ff4eb85c421a2f67a720b5b3c621Patrick Dubroy        final int[] position = mTempCell;
1420716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen        getLocationOnScreen(position);
14216788269814a678af976dfc7d6135993e172ce586Adam Cohen
1422758a9239f045ff4eb85c421a2f67a720b5b3c621Patrick Dubroy        int pointerIndex = ev.getActionIndex();
1423758a9239f045ff4eb85c421a2f67a720b5b3c621Patrick Dubroy        position[0] += (int) ev.getX(pointerIndex);
14244b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen        position[1] += (int) ev.getY(pointerIndex);
14254b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen
14264b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen        mWallpaperManager.sendWallpaperCommand(getWindowToken(),
14274b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen                ev.getAction() == MotionEvent.ACTION_UP
14284b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen                        ? WallpaperManager.COMMAND_TAP : WallpaperManager.COMMAND_SECONDARY_TAP,
14294b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen                position[0], position[1], 0, null);
14304b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen    }
14314b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen
14324b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen    /*
14334b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen     * This interpolator emulates the rate at which the perceived scale of an object changes
14344b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen     * as its distance from a camera increases. When this interpolator is applied to a scale
14354b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen     * animation on a view, it evokes the sense that the object is shrinking due to moving away
14364b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen     * from the camera.
14374b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen     */
14384b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen    static class ZInterpolator implements TimeInterpolator {
14394b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen        private float focalLength;
14404b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen
14414b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen        public ZInterpolator(float foc) {
14424b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen            focalLength = foc;
14434b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen        }
14444b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen
14457777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        public float getInterpolation(float input) {
14467777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen            return (1.0f - focalLength / (focalLength + input)) /
14477777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen                (1.0f - focalLength / (focalLength + 1.0f));
14487777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        }
14497777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen    }
145099633da90012dc732cbc12a96b33e17abcecb464Michael Jurka
145199633da90012dc732cbc12a96b33e17abcecb464Michael Jurka    /*
145299633da90012dc732cbc12a96b33e17abcecb464Michael Jurka     * The exact reverse of ZInterpolator.
145399633da90012dc732cbc12a96b33e17abcecb464Michael Jurka     */
14547777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen    static class InverseZInterpolator implements TimeInterpolator {
145599633da90012dc732cbc12a96b33e17abcecb464Michael Jurka        private ZInterpolator zInterpolator;
145699633da90012dc732cbc12a96b33e17abcecb464Michael Jurka        public InverseZInterpolator(float foc) {
145799633da90012dc732cbc12a96b33e17abcecb464Michael Jurka            zInterpolator = new ZInterpolator(foc);
14587777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        }
14597777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        public float getInterpolation(float input) {
14607777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen            return 1 - zInterpolator.getInterpolation(1 - input);
14617777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        }
14627777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen    }
14637777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen
14647777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen    /*
14657777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen     * ZInterpolator compounded with an ease-out.
14667777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen     */
14677777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen    static class ZoomOutInterpolator implements TimeInterpolator {
14687777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        private final DecelerateInterpolator decelerate = new DecelerateInterpolator(0.75f);
14697777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        private final ZInterpolator zInterpolator = new ZInterpolator(0.13f);
14707777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen
1471beff8c6a13d5b5ad69f5a85ee0150cecd28e6341Adam Cohen        public float getInterpolation(float input) {
14727777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen            return decelerate.getInterpolation(zInterpolator.getInterpolation(input));
14737777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        }
14747777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen    }
14757777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen
14767777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen    /*
14777777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen     * InvereZInterpolator compounded with an ease-out.
14787777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen     */
14797777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen    static class ZoomInInterpolator implements TimeInterpolator {
14807777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        private final InverseZInterpolator inverseZInterpolator = new InverseZInterpolator(0.35f);
14817777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        private final DecelerateInterpolator decelerate = new DecelerateInterpolator(3.0f);
1482d3ef3065ab0941567c45e9aec98783138b623c68Michael Jurka
14837777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        public float getInterpolation(float input) {
14843c4c20fbe682cb4b3ef94f09afe0af09171583f3Michael Jurka            return decelerate.getInterpolation(inverseZInterpolator.getInterpolation(input));
14857777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        }
14867777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen    }
14877777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen
14887777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen    private final ZoomInInterpolator mZoomInInterpolator = new ZoomInInterpolator();
14896b879f0a5885274a85333531e091283405d490ccAdam Lesinski
14907777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen    /*
14917777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen    *
1492de1af7661548692d370518528ff91c7422b9c8aeWinson Chung    * We call these methods (onDragStartedWithItemSpans/onDragStartedWithSize) whenever we
14937777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen    * start a drag in Launcher, regardless of whether the drag has ever entered the Workspace
14944cb3724a2c1e5f278e1531d643accc40fcd8e219Michael Jurka    *
14957777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen    * These methods mark the appropriate pages as accepting drops (which alters their visual
14967777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen    * appearance).
1497785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung    *
14987777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen    */
14997777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen    public void onDragStartedWithItem(View v) {
15007777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        final Canvas canvas = new Canvas();
15017777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen
15027777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        // The outline is used to visualize where the item will land if dropped
15037777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        mDragOutline = createDragOutline(v, canvas, DRAG_BITMAP_PADDING);
15047777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen    }
15057777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen
15067777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen    public void onDragStartedWithItem(PendingAddItemInfo info, Bitmap b, Paint alphaClipPaint) {
15077777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        final Canvas canvas = new Canvas();
15087777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen
15097777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        int[] size = estimateItemSize(info.spanX, info.spanY, info, false);
15107777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen
15117777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        // The outline is used to visualize where the item will land if dropped
15127777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        mDragOutline = createDragOutline(b, canvas, DRAG_BITMAP_PADDING, size[0],
15137777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen                size[1], alphaClipPaint);
15144afe9b31f51022538b30646fe83780e83bf22490Winson Chung    }
15157777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen
15167777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen    // we call this method whenever a drag and drop in Launcher finishes, even if Workspace was
15177777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen    // never dragged over
15187777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen    public void onDragStopped(boolean success) {
15197777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        // In the success case, DragController has already called onDragExit()
1520785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung        if (!success) {
15217777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen            doDragExit(null);
1522f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen        }
15237777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen    }
15247777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen
15257777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen    public void exitWidgetResizeMode() {
15267777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        DragLayer dragLayer = mLauncher.getDragLayer();
15277777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        dragLayer.clearAllResizeFrames();
15287777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen    }
15297777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen
153063257c110a4ee54d5e8872c471cce254cf613c7aWinson Chung    private void initAnimationArrays() {
15317777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        final int childCount = getChildCount();
15327777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        if (mOldTranslationXs != null) return;
15337777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        mOldTranslationXs = new float[childCount];
15347777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        mOldTranslationYs = new float[childCount];
15357777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        mOldScaleXs = new float[childCount];
15367777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        mOldScaleYs = new float[childCount];
15377777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        mOldBackgroundAlphas = new float[childCount];
15387777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        mOldBackgroundAlphaMultipliers = new float[childCount];
15397777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        mOldAlphas = new float[childCount];
15407777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        mOldRotationYs = new float[childCount];
1541cbbaf9862aa160c5e397cb49b554de20981a35feAdam Cohen        mNewTranslationXs = new float[childCount];
15427777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        mNewTranslationYs = new float[childCount];
15437777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        mNewScaleXs = new float[childCount];
15447777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        mNewScaleYs = new float[childCount];
15457777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        mNewBackgroundAlphas = new float[childCount];
15467777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        mNewBackgroundAlphaMultipliers = new float[childCount];
15477777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        mNewAlphas = new float[childCount];
15487777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        mNewRotationYs = new float[childCount];
15497777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen    }
15507777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen
15517777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen    Animator getChangeStateAnimation(final State state, boolean animated) {
15527777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        return getChangeStateAnimation(state, animated, 0);
15537777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen    }
15547777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen
15557777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen    Animator getChangeStateAnimation(final State state, boolean animated, int delay) {
15567777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        if (mState == state) {
15577777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen            return null;
15587777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        }
1559b0f28bd9a52fa4e343c8299d1c3e225d8e01c1e9Michael Jurka
15607777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        // Initialize animation arrays for the first time if necessary
15611c4cf4a11f3f7f24bbf65f958fdd22295d0bbd55Winson Chung        initAnimationArrays();
15627777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen
15637777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        AnimatorSet anim = animated ? new AnimatorSet() : null;
15647777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen
15651c4cf4a11f3f7f24bbf65f958fdd22295d0bbd55Winson Chung        // Stop any scrolling, move to the current page right away
15667777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        setCurrentPage((mNextPage != INVALID_PAGE) ? mNextPage : mCurrentPage);
1567742574b15b2b5298a2328443176f2890fb8ebe98Michael Jurka
15687777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        final State oldState = mState;
1569742574b15b2b5298a2328443176f2890fb8ebe98Michael Jurka        final boolean oldStateIsNormal = (oldState == State.NORMAL);
15707777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        final boolean oldStateIsSmall = (oldState == State.SMALL);
15717777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        mState = state;
15727777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        final boolean stateIsNormal = (state == State.NORMAL);
15737777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        final boolean stateIsSpringLoaded = (state == State.SPRING_LOADED);
15747777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        final boolean stateIsSmall = (state == State.SMALL);
15757777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        float finalScaleFactor = 1.0f;
1576742574b15b2b5298a2328443176f2890fb8ebe98Michael Jurka        float finalBackgroundAlpha = stateIsSpringLoaded ? 1.0f : 0f;
15777777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        float translationX = 0;
15787777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        float translationY = 0;
15797777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        boolean zoomIn = true;
15807777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen
15817777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        if (state != State.NORMAL) {
15827777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen            finalScaleFactor = mSpringLoadedShrinkFactor - (stateIsSmall ? 0.1f : 0);
15837777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen            if (oldStateIsNormal && stateIsSmall) {
15847777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen                zoomIn = false;
15857777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen                setLayoutScale(finalScaleFactor);
15867777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen                updateChildrenLayersEnabled();
15877777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen            } else {
15887777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen                finalBackgroundAlpha = 1.0f;
15897777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen                setLayoutScale(finalScaleFactor);
1590742574b15b2b5298a2328443176f2890fb8ebe98Michael Jurka            }
15917777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        } else {
15927777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen            setLayoutScale(1.0f);
15936b879f0a5885274a85333531e091283405d490ccAdam Lesinski        }
15947777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen
15957777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        final int duration = zoomIn ?
15967777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen                getResources().getInteger(R.integer.config_workspaceUnshrinkTime) :
15977777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen                getResources().getInteger(R.integer.config_appsCustomizeWorkspaceShrinkTime);
15987777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen        for (int i = 0; i < getChildCount(); i++) {
15997777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen            final CellLayout cl = (CellLayout) getChildAt(i);
16007777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen            float rotation = 0f;
16017777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen            float initialAlpha = cl.getAlpha();
16027777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen            float finalAlphaMultiplierValue = 1f;
16037777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen            float finalAlpha = (!mFadeInAdjacentScreens || stateIsSpringLoaded ||
16047777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen                    (i == mCurrentPage)) ? 1f : 0f;
16057777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen
16067777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen            // Determine the pages alpha during the state transition
1607b46a2d130b3d04df830402d579060b63db559ae3Winson Chung            if ((oldStateIsSmall && stateIsNormal) ||
16087777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen                (oldStateIsNormal && stateIsSmall)) {
16097777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen                // To/from workspace - only show the current page unless the transition is not
16107777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen                //                     animated and the animation end callback below doesn't run
16117777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen                if (i == mCurrentPage || !animated) {
16127777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen                    finalAlpha = 1f;
16137777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen                    finalAlphaMultiplierValue = 0f;
16147777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen                } else {
1615dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka                    initialAlpha = 0f;
16168d006d5e144ae33e509ea42e0b9760ef6c5bc884Winson Chung                    finalAlpha = 0f;
16177777d967a60ecfd34ad2d94141d598fca4021058Adam Cohen                }
16187bdb25a9894970da74248c9cdc606d0e1ba05c99Michael Jurka            }
16197bdb25a9894970da74248c9cdc606d0e1ba05c99Michael Jurka
16207bdb25a9894970da74248c9cdc606d0e1ba05c99Michael Jurka            // Update the rotation of the screen (don't apply rotation on Phone UI)
16217bdb25a9894970da74248c9cdc606d0e1ba05c99Michael Jurka            if (LauncherApplication.isScreenLarge()) {
16227bdb25a9894970da74248c9cdc606d0e1ba05c99Michael Jurka                if (i < mCurrentPage) {
16237bdb25a9894970da74248c9cdc606d0e1ba05c99Michael Jurka                    rotation = WORKSPACE_ROTATION;
16247bdb25a9894970da74248c9cdc606d0e1ba05c99Michael Jurka                } else if (i > mCurrentPage) {
16257bdb25a9894970da74248c9cdc606d0e1ba05c99Michael Jurka                    rotation = -WORKSPACE_ROTATION;
16267bdb25a9894970da74248c9cdc606d0e1ba05c99Michael Jurka                }
1627dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka            }
1628dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka
16294be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            // If the screen is not xlarge, then don't rotate the CellLayouts
16304be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            // NOTE: If we don't update the side pages alpha, then we should not hide the side
16314be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            //       pages. see unshrink().
16324be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            if (LauncherApplication.isScreenLarge()) {
16334be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                translationX = getOffsetXForRotation(rotation, cl.getWidth(), cl.getHeight());
16344be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            }
16354be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato
1636ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen            mOldAlphas[i] = initialAlpha;
16374be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            mNewAlphas[i] = finalAlpha;
16384be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            if (animated) {
16394be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                mOldTranslationXs[i] = cl.getTranslationX();
1640099f60d51f6310e1290687e83958e665b3324504Adam Cohen                mOldTranslationYs[i] = cl.getTranslationY();
1641099f60d51f6310e1290687e83958e665b3324504Adam Cohen                mOldScaleXs[i] = cl.getScaleX();
1642ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen                mOldScaleYs[i] = cl.getScaleY();
1643ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen                mOldBackgroundAlphas[i] = cl.getBackgroundAlpha();
1644ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen                mOldBackgroundAlphaMultipliers[i] = cl.getBackgroundAlphaMultiplier();
1645ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen                mOldRotationYs[i] = cl.getRotationY();
1646ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen
1647ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen                mNewTranslationXs[i] = translationX;
1648ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen                mNewTranslationYs[i] = translationY;
1649ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen                mNewScaleXs[i] = finalScaleFactor;
1650099f60d51f6310e1290687e83958e665b3324504Adam Cohen                mNewScaleYs[i] = finalScaleFactor;
1651099f60d51f6310e1290687e83958e665b3324504Adam Cohen                mNewBackgroundAlphas[i] = finalBackgroundAlpha;
1652099f60d51f6310e1290687e83958e665b3324504Adam Cohen                mNewBackgroundAlphaMultipliers[i] = finalAlphaMultiplierValue;
1653099f60d51f6310e1290687e83958e665b3324504Adam Cohen                mNewRotationYs[i] = rotation;
1654099f60d51f6310e1290687e83958e665b3324504Adam Cohen            } else {
1655099f60d51f6310e1290687e83958e665b3324504Adam Cohen                cl.setTranslationX(translationX);
1656ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen                cl.setTranslationY(translationY);
1657ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen                cl.setScaleX(finalScaleFactor);
1658ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen                cl.setScaleY(finalScaleFactor);
1659ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen                cl.setBackgroundAlpha(finalBackgroundAlpha);
1660ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen                cl.setBackgroundAlphaMultiplier(finalAlphaMultiplierValue);
1661ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen                cl.setShortcutAndWidgetAlpha(finalAlpha);
1662ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen                cl.setRotationY(rotation);
1663ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen            }
1664ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        }
1665ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen
1666ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        if (animated) {
1667ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen            for (int index = 0; index < getChildCount(); index++) {
1668099f60d51f6310e1290687e83958e665b3324504Adam Cohen                final int i = index;
1669099f60d51f6310e1290687e83958e665b3324504Adam Cohen                final CellLayout cl = (CellLayout) getChildAt(i);
1670099f60d51f6310e1290687e83958e665b3324504Adam Cohen                if (mOldAlphas[i] == 0 && mNewAlphas[i] == 0) {
1671099f60d51f6310e1290687e83958e665b3324504Adam Cohen                    cl.setTranslationX(mNewTranslationXs[i]);
1672099f60d51f6310e1290687e83958e665b3324504Adam Cohen                    cl.setTranslationY(mNewTranslationYs[i]);
16734be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    cl.setScaleX(mNewScaleXs[i]);
1674ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen                    cl.setScaleY(mNewScaleYs[i]);
1675ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen                    cl.setBackgroundAlpha(mNewBackgroundAlphas[i]);
16764be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    cl.setBackgroundAlphaMultiplier(mNewBackgroundAlphaMultipliers[i]);
1677ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen                    cl.setShortcutAndWidgetAlpha(mNewAlphas[i]);
1678ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen                    cl.setRotationY(mNewRotationYs[i]);
1679ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen                } else {
1680ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen                    LauncherViewPropertyAnimator a = new LauncherViewPropertyAnimator(cl);
1681ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen                    a.translationX(mNewTranslationXs[i])
1682ea359c6aee44c0fe3bb94f7002c3b49208b32b7fWinson Chung                        .translationY(mNewTranslationYs[i])
1683ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen                        .scaleX(mNewScaleXs[i])
16844be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                        .scaleY(mNewScaleYs[i])
1685ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen                        .setDuration(duration)
1686ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen                        .setInterpolator(mZoomInInterpolator);
1687ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen                    anim.play(a);
1688ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen
1689ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen                    if (mOldAlphas[i] != mNewAlphas[i]) {
1690ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen                        LauncherViewPropertyAnimator alphaAnim =
1691ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen                            new LauncherViewPropertyAnimator(cl.getShortcutsAndWidgets());
1692ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen                        alphaAnim.alpha(mNewAlphas[i])
1693ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen                            .setDuration(duration)
1694ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen                            .setInterpolator(mZoomInInterpolator);
1695ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen                        anim.play(alphaAnim);
1696ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen                    }
169770fc438583779ef903541bf9ec546a8235a18785Winson Chung                    if (mOldRotationYs[i] != 0 || mNewRotationYs[i] != 0) {
1698aaf473c2bb6329b3b09ed2e19de6aae26077050cAdam Cohen                        ValueAnimator rotate = ValueAnimator.ofFloat(0f, 1f).setDuration(duration);
1699ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen                        rotate.setInterpolator(new DecelerateInterpolator(2.0f));
1700ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen                        rotate.addUpdateListener(new LauncherAnimatorUpdateListener() {
17014be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                                public void onAnimationUpdate(float a, float b) {
17024be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                                    cl.setRotationY(a * mOldRotationYs[i] + b * mNewRotationYs[i]);
17034be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                                }
17044be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                            });
17054be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                        anim.play(rotate);
17064be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    }
17074be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    if (mOldBackgroundAlphas[i] != 0 ||
1708ea359c6aee44c0fe3bb94f7002c3b49208b32b7fWinson Chung                        mNewBackgroundAlphas[i] != 0 ||
17094be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                        mOldBackgroundAlphaMultipliers[i] != 0 ||
17104be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                        mNewBackgroundAlphaMultipliers[i] != 0) {
17114be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                        ValueAnimator bgAnim = ValueAnimator.ofFloat(0f, 1f).setDuration(duration);
17124be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                        bgAnim.setInterpolator(mZoomInInterpolator);
1713ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen                        bgAnim.addUpdateListener(new LauncherAnimatorUpdateListener() {
17145bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen                                public void onAnimationUpdate(float a, float b) {
1715aaf473c2bb6329b3b09ed2e19de6aae26077050cAdam Cohen                                    cl.setBackgroundAlpha(
17164be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                                            a * mOldBackgroundAlphas[i] +
17174be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                                            b * mNewBackgroundAlphas[i]);
17184be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                                    cl.setBackgroundAlphaMultiplier(
17194be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                                            a * mOldBackgroundAlphaMultipliers[i] +
1720d3ef3065ab0941567c45e9aec98783138b623c68Michael Jurka                                            b * mNewBackgroundAlphaMultipliers[i]);
1721d3ef3065ab0941567c45e9aec98783138b623c68Michael Jurka                                }
1722d3ef3065ab0941567c45e9aec98783138b623c68Michael Jurka                            });
1723f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka                        anim.play(bgAnim);
1724ea359c6aee44c0fe3bb94f7002c3b49208b32b7fWinson Chung                    }
1725f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka                }
1726d3ef3065ab0941567c45e9aec98783138b623c68Michael Jurka            }
1727f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka            anim.setStartDelay(delay);
1728f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka        }
1729f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka
1730f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka        if (stateIsSpringLoaded) {
1731f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka            // Right now we're covered by Apps Customize
1732f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka            // Show the background gradient immediately, so the gradient will
1733f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka            // be showing once AppsCustomize disappears
1734f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka            animateBackgroundGradient(getResources().getInteger(
1735f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka                    R.integer.config_appsCustomizeSpringLoadedBgAlpha) / 100f, false);
1736f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka        } else {
1737f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka            // Fade the background gradient away
1738f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka            animateBackgroundGradient(0f, true);
1739f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka        }
1740f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka        return anim;
1741d3ef3065ab0941567c45e9aec98783138b623c68Michael Jurka    }
1742aaf473c2bb6329b3b09ed2e19de6aae26077050cAdam Cohen
1743d3ef3065ab0941567c45e9aec98783138b623c68Michael Jurka    @Override
1744d3ef3065ab0941567c45e9aec98783138b623c68Michael Jurka    public void onLauncherTransitionStart(Launcher l, boolean animated, boolean toWorkspace) {
1745d3ef3065ab0941567c45e9aec98783138b623c68Michael Jurka        mIsSwitchingState = true;
1746d3ef3065ab0941567c45e9aec98783138b623c68Michael Jurka    }
1747d3ef3065ab0941567c45e9aec98783138b623c68Michael Jurka
1748a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung    @Override
1749a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung    public void onLauncherTransitionStep(Launcher l, float t) {
1750a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung        mTransitionProgress = t;
1751a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung    }
1752a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung
1753a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung    @Override
1754ea359c6aee44c0fe3bb94f7002c3b49208b32b7fWinson Chung    public void onLauncherTransitionEnd(Launcher l, boolean animated, boolean toWorkspace) {
1755a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung        mIsSwitchingState = false;
1756a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung        mWallpaperOffset.setOverrideHorizontalCatchupConstant(false);
1757a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung        updateChildrenLayersEnabled();
1758a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung        // The code in getChangeStateAnimation to determine initialAlpha and finalAlpha will ensure
1759a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung        // ensure that only the current page is visible during (and subsequently, after) the
1760a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung        // transition animation.  If fade adjacent pages is disabled, then re-enable the page
1761a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung        // visibility after the transition animation.
1762a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung        if (!mFadeInAdjacentScreens) {
1763a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung            for (int i = 0; i < getChildCount(); i++) {
1764a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung                final CellLayout cl = (CellLayout) getChildAt(i);
17655bb50bdb13f5fc22f5febd9480e78222b26c6fe7Adam Cohen                cl.setShortcutAndWidgetAlpha(1f);
1766aaf473c2bb6329b3b09ed2e19de6aae26077050cAdam Cohen            }
1767a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung        }
1768a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung    }
1769a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung
177031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
177131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public View getContent() {
1772aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        return this;
177331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
17747984c9496bcaeca23ee7fdecc4d4f1bb2467e0f2Bjorn Bringert
177531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
177631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * Draw the View v into the given Canvas.
1777aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     *
177831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param v the view to draw
1779fc53cd22c9a78708c78c85946443f23ec8c59502Adam Cohen     * @param destCanvas the canvas to draw on
17804be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato     * @param padding the horizontal and vertical padding to use when drawing
17814be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato     */
17824be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato    private void drawDragView(View v, Canvas destCanvas, int padding, boolean pruneToDrawable) {
17834be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        final Rect clipRect = mTempRect;
17844be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        v.getDrawingRect(clipRect);
17854be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato
17868e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy        boolean textVisible = false;
178738b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka
17888e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy        destCanvas.save();
17894be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        if (v instanceof TextView && pruneToDrawable) {
17908e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy            Drawable d = ((TextView) v).getCompoundDrawables()[1];
1791ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen            clipRect.set(0, 0, d.getIntrinsicWidth() + padding, d.getIntrinsicHeight() + padding);
1792ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen            destCanvas.translate(padding / 2, padding / 2);
1793ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen            d.draw(destCanvas);
1794ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen        } else {
1795ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen            if (v instanceof FolderIcon) {
1796ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen                // For FolderIcons the text can bleed into the icon area, and so we need to
17974be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                // hide the text completely (which can't be achieved by clipping).
17984be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                if (((FolderIcon) v).getTextVisible()) {
1799ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen                    ((FolderIcon) v).setTextVisible(false);
18004be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    textVisible = true;
18014be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                }
1802e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen            } else if (v instanceof BubbleTextView) {
18038dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                final BubbleTextView tv = (BubbleTextView) v;
18048dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                clipRect.bottom = tv.getExtendedPaddingTop() - (int) BubbleTextView.PADDING_V +
1805fc53cd22c9a78708c78c85946443f23ec8c59502Adam Cohen                        tv.getLayout().getLineTop(0);
1806e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen            } else if (v instanceof TextView) {
1807e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen                final TextView tv = (TextView) v;
18080e4857c302da6adbd45231d7a8bae0289fa33250Adam Cohen                clipRect.bottom = tv.getExtendedPaddingTop() - tv.getCompoundDrawablePadding() +
1809e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen                        tv.getLayout().getLineTop(0);
1810e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen            }
1811e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen            destCanvas.translate(-v.getScrollX() + padding / 2, -v.getScrollY() + padding / 2);
1812e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen            destCanvas.clipRect(clipRect, Op.REPLACE);
1813e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen            v.draw(destCanvas);
1814fc53cd22c9a78708c78c85946443f23ec8c59502Adam Cohen
1815e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen            // Restore text visibility of FolderIcon if necessary
18160e4857c302da6adbd45231d7a8bae0289fa33250Adam Cohen            if (textVisible) {
18170e4857c302da6adbd45231d7a8bae0289fa33250Adam Cohen                ((FolderIcon) v).setTextVisible(true);
18180e4857c302da6adbd45231d7a8bae0289fa33250Adam Cohen            }
1819e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        }
1820e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        destCanvas.restore();
1821ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen    }
1822e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen
18234be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato    /**
182431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * Returns a new bitmap to show when the given View is being dragged around.
182531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * Responsibility for the bitmap is transferred to the caller.
18263d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung     */
18273d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung    public Bitmap createDragBitmap(View v, Canvas canvas, int padding) {
18283d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        final int outlineColor = getResources().getColor(android.R.color.holo_blue_light);
182931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        Bitmap b;
18300280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
18313d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        if (v instanceof TextView) {
18323d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung            Drawable d = ((TextView) v).getCompoundDrawables()[1];
18333d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung            b = Bitmap.createBitmap(d.getIntrinsicWidth() + padding,
18343d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung                    d.getIntrinsicHeight() + padding, Bitmap.Config.ARGB_8888);
183531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        } else {
183631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            b = Bitmap.createBitmap(
18374b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen                    v.getWidth() + padding, v.getHeight() + padding, Bitmap.Config.ARGB_8888);
18384b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen        }
18394b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen
18404b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen        canvas.setBitmap(b);
1841cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy        drawDragView(v, canvas, padding, true);
1842cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy        canvas.setBitmap(null);
1843cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy
1844cb3382b1bfe1a534b1b44f5c4def9b2db605ac90Adam Cohen        return b;
1845cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy    }
1846cb3382b1bfe1a534b1b44f5c4def9b2db605ac90Adam Cohen
1847cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy    /**
1848a65beeea13c18c443f15f8d51c4c6e153a6c4ef9Adam Cohen     * Returns a new bitmap to be used as the object outline, e.g. to visualize the drop location.
1849cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy     * Responsibility for the bitmap is transferred to the caller.
1850cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy     */
18514b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen    private Bitmap createDragOutline(View v, Canvas canvas, int padding) {
1852cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy        final int outlineColor = getResources().getColor(android.R.color.holo_blue_light);
1853a65beeea13c18c443f15f8d51c4c6e153a6c4ef9Adam Cohen        final Bitmap b = Bitmap.createBitmap(
1854a65beeea13c18c443f15f8d51c4c6e153a6c4ef9Adam Cohen                v.getWidth() + padding, v.getHeight() + padding, Bitmap.Config.ARGB_8888);
1855a65beeea13c18c443f15f8d51c4c6e153a6c4ef9Adam Cohen
18562e9f4fb38e833b18fe403da17b00f830d6a5e86cAdam Cohen        canvas.setBitmap(b);
18572e9f4fb38e833b18fe403da17b00f830d6a5e86cAdam Cohen        drawDragView(v, canvas, padding, true);
18582e9f4fb38e833b18fe403da17b00f830d6a5e86cAdam Cohen        mOutlineHelper.applyMediumExpensiveOutlineWithBlur(b, canvas, outlineColor, outlineColor);
18592e9f4fb38e833b18fe403da17b00f830d6a5e86cAdam Cohen        canvas.setBitmap(null);
18602e9f4fb38e833b18fe403da17b00f830d6a5e86cAdam Cohen        return b;
18612e9f4fb38e833b18fe403da17b00f830d6a5e86cAdam Cohen    }
18622e9f4fb38e833b18fe403da17b00f830d6a5e86cAdam Cohen
1863557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung    /**
1864557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung     * Returns a new bitmap to be used as the object outline, e.g. to visualize the drop location.
1865557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung     * Responsibility for the bitmap is transferred to the caller.
1866557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung     */
1867557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung    private Bitmap createDragOutline(Bitmap orig, Canvas canvas, int padding, int w, int h,
1868557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung            Paint alphaClipPaint) {
1869557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung        final int outlineColor = getResources().getColor(android.R.color.holo_blue_light);
1870557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung        final Bitmap b = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
1871557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung        canvas.setBitmap(b);
1872557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung
1873557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung        Rect src = new Rect(0, 0, orig.getWidth(), orig.getHeight());
1874557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung        float scaleFactor = Math.min((w - padding) / (float) orig.getWidth(),
1875557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung                (h - padding) / (float) orig.getHeight());
1876cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy        int scaledWidth = (int) (scaleFactor * orig.getWidth());
1877a65beeea13c18c443f15f8d51c4c6e153a6c4ef9Adam Cohen        int scaledHeight = (int) (scaleFactor * orig.getHeight());
1878a65beeea13c18c443f15f8d51c4c6e153a6c4ef9Adam Cohen        Rect dst = new Rect(0, 0, scaledWidth, scaledHeight);
1879a65beeea13c18c443f15f8d51c4c6e153a6c4ef9Adam Cohen
1880a65beeea13c18c443f15f8d51c4c6e153a6c4ef9Adam Cohen        // center the image
1881a65beeea13c18c443f15f8d51c4c6e153a6c4ef9Adam Cohen        dst.offset((w - scaledWidth) / 2, (h - scaledHeight) / 2);
1882a65beeea13c18c443f15f8d51c4c6e153a6c4ef9Adam Cohen
1883a65beeea13c18c443f15f8d51c4c6e153a6c4ef9Adam Cohen        canvas.drawBitmap(orig, src, dst, null);
1884a65beeea13c18c443f15f8d51c4c6e153a6c4ef9Adam Cohen        mOutlineHelper.applyMediumExpensiveOutlineWithBlur(b, canvas, outlineColor, outlineColor,
1885a65beeea13c18c443f15f8d51c4c6e153a6c4ef9Adam Cohen                alphaClipPaint);
1886a65beeea13c18c443f15f8d51c4c6e153a6c4ef9Adam Cohen        canvas.setBitmap(null);
1887cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy
1888cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy        return b;
1889cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy    }
1890cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy
1891cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy    void startDrag(CellLayout.CellInfo cellInfo) {
1892cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy        View child = cellInfo.cell;
1893cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy
1894cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy        // Make sure the drag was started by a long press as opposed to a long click.
1895cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy        if (!child.isInTouchMode()) {
1896cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy            return;
1897a65beeea13c18c443f15f8d51c4c6e153a6c4ef9Adam Cohen        }
1898a65beeea13c18c443f15f8d51c4c6e153a6c4ef9Adam Cohen
1899a65beeea13c18c443f15f8d51c4c6e153a6c4ef9Adam Cohen        mDragInfo = cellInfo;
1900a65beeea13c18c443f15f8d51c4c6e153a6c4ef9Adam Cohen        child.setVisibility(INVISIBLE);
19013d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        CellLayout layout = (CellLayout) child.getParent().getParent();
19023d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        layout.prepareChildForDrag(child);
19033d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung
19043d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        child.clearFocus();
19053d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        child.setPressed(false);
19063d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung
1907e0310965022e7a1adb7ad489505d404186608689Adam Cohen        final Canvas canvas = new Canvas();
1908a65beeea13c18c443f15f8d51c4c6e153a6c4ef9Adam Cohen
1909a65beeea13c18c443f15f8d51c4c6e153a6c4ef9Adam Cohen        // The outline is used to visualize where the item will land if dropped
1910a65beeea13c18c443f15f8d51c4c6e153a6c4ef9Adam Cohen        mDragOutline = createDragOutline(child, canvas, DRAG_BITMAP_PADDING);
1911e0310965022e7a1adb7ad489505d404186608689Adam Cohen        beginDragShared(child, this);
1912a65beeea13c18c443f15f8d51c4c6e153a6c4ef9Adam Cohen    }
1913e0310965022e7a1adb7ad489505d404186608689Adam Cohen
1914c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen    public void beginDragShared(View child, DragSource source) {
1915c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        Resources r = getResources();
1916e0310965022e7a1adb7ad489505d404186608689Adam Cohen
1917e0310965022e7a1adb7ad489505d404186608689Adam Cohen        // The drag bitmap follows the touch point around on the screen
1918e0310965022e7a1adb7ad489505d404186608689Adam Cohen        final Bitmap b = createDragBitmap(child, new Canvas(), DRAG_BITMAP_PADDING);
1919e0310965022e7a1adb7ad489505d404186608689Adam Cohen
1920a65beeea13c18c443f15f8d51c4c6e153a6c4ef9Adam Cohen        final int bmpWidth = b.getWidth();
1921a65beeea13c18c443f15f8d51c4c6e153a6c4ef9Adam Cohen        final int bmpHeight = b.getHeight();
1922a65beeea13c18c443f15f8d51c4c6e153a6c4ef9Adam Cohen
1923a65beeea13c18c443f15f8d51c4c6e153a6c4ef9Adam Cohen        mLauncher.getDragLayer().getLocationInDragLayer(child, mTempXY);
1924a65beeea13c18c443f15f8d51c4c6e153a6c4ef9Adam Cohen        int dragLayerX =
1925a65beeea13c18c443f15f8d51c4c6e153a6c4ef9Adam Cohen                Math.round(mTempXY[0] - (bmpWidth - child.getScaleX() * child.getWidth()) / 2);
1926a65beeea13c18c443f15f8d51c4c6e153a6c4ef9Adam Cohen        int dragLayerY =
1927a65beeea13c18c443f15f8d51c4c6e153a6c4ef9Adam Cohen                Math.round(mTempXY[1] - (bmpHeight - child.getScaleY() * bmpHeight) / 2
1928a65beeea13c18c443f15f8d51c4c6e153a6c4ef9Adam Cohen                        - DRAG_BITMAP_PADDING / 2);
1929a65beeea13c18c443f15f8d51c4c6e153a6c4ef9Adam Cohen
1930a65beeea13c18c443f15f8d51c4c6e153a6c4ef9Adam Cohen        Point dragVisualizeOffset = null;
19313d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        Rect dragRect = null;
1932557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung        if (child instanceof BubbleTextView || child instanceof PagedViewIcon) {
1933c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            int iconSize = r.getDimensionPixelSize(R.dimen.app_icon_size);
1934ec9a0a4ca5458e65ba2498e4f7eab0ae6e91964aWinson Chung            int iconPaddingTop = r.getDimensionPixelSize(R.dimen.app_icon_padding_top);
1935ec9a0a4ca5458e65ba2498e4f7eab0ae6e91964aWinson Chung            int top = child.getPaddingTop();
1936ec9a0a4ca5458e65ba2498e4f7eab0ae6e91964aWinson Chung            int left = (bmpWidth - iconSize) / 2;
1937ec9a0a4ca5458e65ba2498e4f7eab0ae6e91964aWinson Chung            int right = left + iconSize;
1938ec9a0a4ca5458e65ba2498e4f7eab0ae6e91964aWinson Chung            int bottom = top + iconSize;
1939ec9a0a4ca5458e65ba2498e4f7eab0ae6e91964aWinson Chung            dragLayerY += top;
194010b1737910ea7890ca95bbbe5363fd5aa513b856Adam Cohen            // Note: The drag region is used to calculate drag layer offsets, but the
194119072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen            // dragVisualizeOffset in addition to the dragRect (the size) to position the outline.
194219072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen            dragVisualizeOffset = new Point(-DRAG_BITMAP_PADDING / 2,
1943c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen                    iconPaddingTop - DRAG_BITMAP_PADDING / 2);
194410b1737910ea7890ca95bbbe5363fd5aa513b856Adam Cohen            dragRect = new Rect(left, top, right, bottom);
194510b1737910ea7890ca95bbbe5363fd5aa513b856Adam Cohen        } else if (child instanceof FolderIcon) {
194610b1737910ea7890ca95bbbe5363fd5aa513b856Adam Cohen            int previewSize = r.getDimensionPixelSize(R.dimen.folder_preview_size);
194710b1737910ea7890ca95bbbe5363fd5aa513b856Adam Cohen            dragRect = new Rect(0, 0, child.getWidth(), previewSize);
194810b1737910ea7890ca95bbbe5363fd5aa513b856Adam Cohen        }
194910b1737910ea7890ca95bbbe5363fd5aa513b856Adam Cohen
195010b1737910ea7890ca95bbbe5363fd5aa513b856Adam Cohen        // Clear the pressed state if necessary
195110b1737910ea7890ca95bbbe5363fd5aa513b856Adam Cohen        if (child instanceof BubbleTextView) {
195210b1737910ea7890ca95bbbe5363fd5aa513b856Adam Cohen            BubbleTextView icon = (BubbleTextView) child;
19533d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung            icon.clearPressedOrFocusedBackground();
195410b1737910ea7890ca95bbbe5363fd5aa513b856Adam Cohen        }
195510b1737910ea7890ca95bbbe5363fd5aa513b856Adam Cohen
1956d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        mDragController.startDrag(b, dragLayerX, dragLayerY, source, child.getTag(),
1957ac8c87687b8e063c981f28cb31bab2cc110f26ccAdam Cohen                DragController.DRAG_ACTION_MOVE, dragVisualizeOffset, dragRect, child.getScaleX());
195810b1737910ea7890ca95bbbe5363fd5aa513b856Adam Cohen        b.recycle();
1959d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen
19603d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        // Show the scrolling indicator when you pick up an item
19613d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        showScrollingIndicator(false);
1962a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen    }
1963a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen
1964a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen    void addApplicationShortcut(ShortcutInfo info, CellLayout target, long container, int screen,
1965a9cf38f533d1e86269868f1e6a806ccffd4a78fcAdam Cohen            int cellX, int cellY, boolean insertAtFirst, int intersectX, int intersectY) {
1966d044526d82e7938cf35b296978d9d5302f98b4afAdam Cohen        View view = mLauncher.createShortcut(R.layout.application, target, (ShortcutInfo) info);
1967558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen
1968558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen        final int[] cellXY = new int[2];
1969558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen        target.findCellForSpanThatIntersects(cellXY, 1, 1, intersectX, intersectY);
1970558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen        addInScreen(view, container, screen, cellXY[0], cellXY[1], 1, 1, insertAtFirst);
1971558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen        LauncherModel.addOrMoveItemInDatabase(mLauncher, info, container, screen, cellXY[0],
1972558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                cellXY[1]);
1973558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen    }
1974558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen
1975558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen    public boolean transitionStateShouldAllowDrop() {
197610b1737910ea7890ca95bbbe5363fd5aa513b856Adam Cohen        return ((!isSwitchingState() || mTransitionProgress > 0.5f) && mState != State.SMALL);
197710b1737910ea7890ca95bbbe5363fd5aa513b856Adam Cohen    }
197810b1737910ea7890ca95bbbe5363fd5aa513b856Adam Cohen
197910b1737910ea7890ca95bbbe5363fd5aa513b856Adam Cohen    /**
198010b1737910ea7890ca95bbbe5363fd5aa513b856Adam Cohen     * {@inheritDoc}
1981a65beeea13c18c443f15f8d51c4c6e153a6c4ef9Adam Cohen     */
19823e8f811f31a2275e778244427271f77f4116c08bAdam Cohen    public boolean acceptDrop(DragObject d) {
1983a65beeea13c18c443f15f8d51c4c6e153a6c4ef9Adam Cohen        // If it's an external drop (e.g. from All Apps), check if it should be accepted
1984c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        if (d.dragSource != this) {
1985c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            // Don't accept the drop if we're not over a screen at time of drop
19863e8f811f31a2275e778244427271f77f4116c08bAdam Cohen            if (mDragTargetLayout == null) {
19873e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                return false;
1988c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            }
1989c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            if (!transitionStateShouldAllowDrop()) return false;
1990c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen
19913d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung            mDragViewVisualCenter = getDragViewVisualCenter(d.x, d.y, d.xOffset, d.yOffset,
1992c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen                    d.dragView, mDragViewVisualCenter);
1993c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen
1994c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            // We want the point to be mapped to the dragTarget.
1995c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            if (mLauncher.isHotseatLayout(mDragTargetLayout)) {
1996c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen                mapPointFromSelfToSibling(mLauncher.getHotseat(), mDragViewVisualCenter);
1997c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            } else {
1998c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen                mapPointFromSelfToChild(mDragTargetLayout, mDragViewVisualCenter, null);
1999cb3382b1bfe1a534b1b44f5c4def9b2db605ac90Adam Cohen            }
2000cb3382b1bfe1a534b1b44f5c4def9b2db605ac90Adam Cohen
2001e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen            int spanX = 1;
2002e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen            int spanY = 1;
2003e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen            View ignoreView = null;
2004ba781611b3e2fb1c42daa7167c1079b90b100efaAdam Cohen            if (mDragInfo != null) {
20053d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung                final CellLayout.CellInfo dragCellInfo = mDragInfo;
20063d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung                spanX = dragCellInfo.spanX;
20073d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung                spanY = dragCellInfo.spanY;
20083d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung                ignoreView = dragCellInfo.cell;
20093d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung            } else {
2010ba781611b3e2fb1c42daa7167c1079b90b100efaAdam Cohen                final ItemInfo dragInfo = (ItemInfo) d.dragInfo;
2011c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka                spanX = dragInfo.spanX;
201276078c4ef35b6e95fb6d8129a32cf52a36625e28Adam Cohen                spanY = dragInfo.spanY;
2013b09cac5a738b679038cbeaec80041637100b65d9Michael Jurka            }
2014ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen
2015cb3382b1bfe1a534b1b44f5c4def9b2db605ac90Adam Cohen            int minSpanX = spanX;
2016e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen            int minSpanY = spanY;
2017e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen            if (d.dragInfo instanceof PendingAddWidgetInfo) {
20183e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                minSpanX = ((PendingAddWidgetInfo) d.dragInfo).minSpanX;
2019ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy                minSpanY = ((PendingAddWidgetInfo) d.dragInfo).minSpanY;
2020ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy            }
202154fa3b95557c283976e8c1aa8a157b460b0b4513Patrick Dubroy
2022ea359c6aee44c0fe3bb94f7002c3b49208b32b7fWinson Chung            mTargetCell = findNearestArea((int) mDragViewVisualCenter[0],
2023cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy                    (int) mDragViewVisualCenter[1], minSpanX, minSpanY, mDragTargetLayout,
202440e882bf19a837ee62ec328c5748b75be7960d39Winson Chung                    mTargetCell);
202540e882bf19a837ee62ec328c5748b75be7960d39Winson Chung            float distance = mDragTargetLayout.getDistanceFromCell(mDragViewVisualCenter[0],
202640e882bf19a837ee62ec328c5748b75be7960d39Winson Chung                    mDragViewVisualCenter[1], mTargetCell);
20273d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung            if (willCreateUserFolder((ItemInfo) d.dragInfo, mDragTargetLayout,
20283d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung                    mTargetCell, distance, true)) {
20293d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung                return true;
203054fa3b95557c283976e8c1aa8a157b460b0b4513Patrick Dubroy            }
2031c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            if (willAddToExistingUserFolder((ItemInfo) d.dragInfo, mDragTargetLayout,
2032c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen                    mTargetCell, distance)) {
2033c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen                return true;
2034c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            }
2035c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen
2036c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            int[] resultSpan = new int[2];
2037c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            mTargetCell = mDragTargetLayout.createArea((int) mDragViewVisualCenter[0],
203876078c4ef35b6e95fb6d8129a32cf52a36625e28Adam Cohen                    (int) mDragViewVisualCenter[1], minSpanX, minSpanY, spanX, spanY,
20391c4cf4a11f3f7f24bbf65f958fdd22295d0bbd55Winson Chung                    null, mTargetCell, resultSpan, CellLayout.MODE_ACCEPT_DROP);
20403d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung            boolean foundCell = mTargetCell[0] >= 0 && mTargetCell[1] >= 0;
2041c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen
2042c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            // Don't accept the drop if there's no room for the item
2043c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            if (!foundCell) {
20443e8f811f31a2275e778244427271f77f4116c08bAdam Cohen                // Don't show the message if we are dropping on the AllApps button and the hotseat
2045df0353815c629fc678824b07a234b89a1ff94208Adam Cohen                // is full
2046df0353815c629fc678824b07a234b89a1ff94208Adam Cohen                if (mTargetCell != null && mLauncher.isHotseatLayout(mDragTargetLayout)) {
2047df0353815c629fc678824b07a234b89a1ff94208Adam Cohen                    Hotseat hotseat = mLauncher.getHotseat();
2048df0353815c629fc678824b07a234b89a1ff94208Adam Cohen                    if (hotseat.isAllAppsButtonRank(
2049df0353815c629fc678824b07a234b89a1ff94208Adam Cohen                            hotseat.getOrderInHotseat(mTargetCell[0], mTargetCell[1]))) {
2050e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen                        return false;
2051e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen                    }
2052e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen                }
2053df0353815c629fc678824b07a234b89a1ff94208Adam Cohen
20547cfc2825c3a1029f962d2fc387ae2eaa85b51798Michael Jurka                mLauncher.showOutOfSpaceMessage();
2055ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen                return false;
205654fa3b95557c283976e8c1aa8a157b460b0b4513Patrick Dubroy            }
205754fa3b95557c283976e8c1aa8a157b460b0b4513Patrick Dubroy        }
205854fa3b95557c283976e8c1aa8a157b460b0b4513Patrick Dubroy        return true;
2059c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen    }
206040e882bf19a837ee62ec328c5748b75be7960d39Winson Chung
20619438336724b4f8b54c7cdc49c5f01dd9568926ebPatrick Dubroy    boolean willCreateUserFolder(ItemInfo info, CellLayout target, int[] targetCell, float
20623d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung            distance, boolean considerTimeout) {
20633d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        if (distance > mMaxDistanceForFolderCreation) return false;
20643d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung
20659438336724b4f8b54c7cdc49c5f01dd9568926ebPatrick Dubroy        View dropOverView = target.getChildAt(targetCell[0], targetCell[1]);
2066cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy
20679438336724b4f8b54c7cdc49c5f01dd9568926ebPatrick Dubroy        boolean hasntMoved = false;
20689438336724b4f8b54c7cdc49c5f01dd9568926ebPatrick Dubroy        if (mDragInfo != null) {
20699438336724b4f8b54c7cdc49c5f01dd9568926ebPatrick Dubroy            hasntMoved = dropOverView == mDragInfo.cell;
207054fa3b95557c283976e8c1aa8a157b460b0b4513Patrick Dubroy        }
20719438336724b4f8b54c7cdc49c5f01dd9568926ebPatrick Dubroy
20729438336724b4f8b54c7cdc49c5f01dd9568926ebPatrick Dubroy        if (dropOverView == null || hasntMoved || (considerTimeout && !mCreateUserFolderOnDrop)) {
20733d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung            return false;
20749438336724b4f8b54c7cdc49c5f01dd9568926ebPatrick Dubroy        }
20759438336724b4f8b54c7cdc49c5f01dd9568926ebPatrick Dubroy
20763d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        boolean aboveShortcut = (dropOverView.getTag() instanceof ShortcutInfo);
20773d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        boolean willBecomeShortcut =
2078d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
2079d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                info.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT);
2080d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
2081d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        return (aboveShortcut && willBecomeShortcut);
2082d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    }
2083d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
208427c09b05d3ed2a4ce9d53140216aba998727a569Adam Cohen    boolean willAddToExistingUserFolder(Object dragInfo, CellLayout target, int[] targetCell,
208526976d9b53161f80faf822d482ac771b8621cf31Adam Cohen            float distance) {
2086d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        if (distance > mMaxDistanceForFolderCreation) return false;
2087716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen
2088c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        View dropOverView = target.getChildAt(targetCell[0], targetCell[1]);
2089d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        if (dropOverView instanceof FolderIcon) {
209026976d9b53161f80faf822d482ac771b8621cf31Adam Cohen            FolderIcon fi = (FolderIcon) dropOverView;
209126976d9b53161f80faf822d482ac771b8621cf31Adam Cohen            if (fi.acceptDrop(dragInfo)) {
209226976d9b53161f80faf822d482ac771b8621cf31Adam Cohen                return true;
209326976d9b53161f80faf822d482ac771b8621cf31Adam Cohen            }
209426976d9b53161f80faf822d482ac771b8621cf31Adam Cohen        }
209526976d9b53161f80faf822d482ac771b8621cf31Adam Cohen        return false;
209626976d9b53161f80faf822d482ac771b8621cf31Adam Cohen    }
209726976d9b53161f80faf822d482ac771b8621cf31Adam Cohen
209826976d9b53161f80faf822d482ac771b8621cf31Adam Cohen    boolean createUserFolderIfNecessary(View newView, long container, CellLayout target,
2099d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            int[] targetCell, float distance, boolean external, DragView dragView,
2100d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            Runnable postAnimationRunnable) {
2101d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        if (distance > mMaxDistanceForFolderCreation) return false;
2102d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        View v = target.getChildAt(targetCell[0], targetCell[1]);
21033d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        boolean hasntMoved = false;
21043d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        if (mDragInfo != null) {
21059438336724b4f8b54c7cdc49c5f01dd9568926ebPatrick Dubroy            CellLayout cellParent = getParentCellLayoutForView(mDragInfo.cell);
210631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            hasntMoved = (mDragInfo.cellX == targetCell[0] &&
2107cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy                    mDragInfo.cellY == targetCell[1]) && (cellParent == target);
21088c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka        }
2109ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy
2110ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy        if (v == null || hasntMoved || !mCreateUserFolderOnDrop) return false;
2111ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy        mCreateUserFolderOnDrop = false;
2112d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka        final int screen = (targetCell == null) ? mDragInfo.screen : indexOfChild(target);
2113d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka
2114d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka        boolean aboveShortcut = (v.getTag() instanceof ShortcutInfo);
2115d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka        boolean willBecomeShortcut = (newView.getTag() instanceof ShortcutInfo);
2116d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka
2117d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka        if (aboveShortcut && willBecomeShortcut) {
2118d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka            ShortcutInfo sourceInfo = (ShortcutInfo) newView.getTag();
2119d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka            ShortcutInfo destInfo = (ShortcutInfo) v.getTag();
2120fc53cd22c9a78708c78c85946443f23ec8c59502Adam Cohen            // if the drag started here, we need to remove it from the workspace
2121ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen            if (!external) {
2122ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen                getParentCellLayoutForView(mDragInfo.cell).removeView(mDragInfo.cell);
2123ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen            }
2124fc53cd22c9a78708c78c85946443f23ec8c59502Adam Cohen
2125ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen            Rect folderLocation = new Rect();
2126fc53cd22c9a78708c78c85946443f23ec8c59502Adam Cohen            float scale = mLauncher.getDragLayer().getDescendantRectRelativeToSelf(v, folderLocation);
2127fc53cd22c9a78708c78c85946443f23ec8c59502Adam Cohen            target.removeView(v);
2128fc53cd22c9a78708c78c85946443f23ec8c59502Adam Cohen
2129716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen            FolderIcon fi =
213031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                mLauncher.addFolder(target, container, screen, targetCell[0], targetCell[1]);
213131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            destInfo.cellX = -1;
213231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            destInfo.cellY = -1;
2133ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen            sourceInfo.cellX = -1;
2134ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen            sourceInfo.cellY = -1;
2135ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen
2136ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen            // If the dragView is null, we can't animate
2137ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen            boolean animate = dragView != null;
2138ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen            if (animate) {
2139ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen                fi.performCreateAnimation(destInfo, v, sourceInfo, dragView, folderLocation, scale,
2140ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen                        postAnimationRunnable);
2141ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen            } else {
2142ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen                fi.addItem(destInfo);
2143ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen                fi.addItem(sourceInfo);
2144ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen            }
2145ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen            return true;
2146ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen        }
2147ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen        return false;
2148ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen    }
2149ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen
2150ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen    boolean addToExistingFolderIfNecessary(View newView, CellLayout target, int[] targetCell,
2151ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen            float distance, DragObject d, boolean external) {
2152ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen        if (distance > mMaxDistanceForFolderCreation) return false;
2153ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen
2154ed51cc9a12c50d12e7d30ed209a49f1a40858043Adam Cohen        View dropOverView = target.getChildAt(targetCell[0], targetCell[1]);
215576078c4ef35b6e95fb6d8129a32cf52a36625e28Adam Cohen        if (dropOverView instanceof FolderIcon) {
21568dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            FolderIcon fi = (FolderIcon) dropOverView;
2157e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen            if (fi.acceptDrop(d.dragInfo)) {
2158e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen                fi.onDrop(d);
2159e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen
21608dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                // if the drag started here, we need to remove it from the workspace
2161e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen                if (!external) {
2162e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen                    getParentCellLayoutForView(mDragInfo.cell).removeView(mDragInfo.cell);
2163e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen                }
2164e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen                return true;
2165e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen            }
2166e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        }
2167e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        return false;
2168cb3382b1bfe1a534b1b44f5c4def9b2db605ac90Adam Cohen    }
2169b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung
2170c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung    public void onDrop(final DragObject d) {
2171b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung        mDragViewVisualCenter = getDragViewVisualCenter(d.x, d.y, d.xOffset, d.yOffset, d.dragView,
2172b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung                mDragViewVisualCenter);
2173c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung
2174c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung        // We want the point to be mapped to the dragTarget.
2175c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung        if (mDragTargetLayout != null) {
2176c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung            if (mLauncher.isHotseatLayout(mDragTargetLayout)) {
2177c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung                mapPointFromSelfToSibling(mLauncher.getHotseat(), mDragViewVisualCenter);
2178c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung            } else {
2179c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung                mapPointFromSelfToChild(mDragTargetLayout, mDragViewVisualCenter, null);
2180c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung            }
2181c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung        }
2182c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung
2183b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung        CellLayout dropTargetLayout = mDragTargetLayout;
2184c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung
2185c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung        int snapScreen = -1;
2186c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung        boolean resizeOnDrop = false;
2187fd3385fe9e0f034b04f99d5d59a58d74fe040da4Winson Chung        if (d.dragSource != this) {
2188c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung            final int[] touchXY = new int[] { (int) mDragViewVisualCenter[0],
2189c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung                    (int) mDragViewVisualCenter[1] };
2190c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung            onDropExternal(touchXY, d.dragInfo, dropTargetLayout, false, d);
2191c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung        } else if (mDragInfo != null) {
2192c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung            final View cell = mDragInfo.cell;
2193c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung
2194d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka            Runnable resizeRunnable = null;
2195c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung            if (dropTargetLayout != null) {
2196c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung                // Move internally
2197c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung                boolean hasMovedLayouts = (getParentCellLayoutForView(cell) != dropTargetLayout);
2198c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung                boolean hasMovedIntoHotseat = mLauncher.isHotseatLayout(dropTargetLayout);
2199c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung                long container = hasMovedIntoHotseat ?
2200c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung                        LauncherSettings.Favorites.CONTAINER_HOTSEAT :
2201c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung                        LauncherSettings.Favorites.CONTAINER_DESKTOP;
2202c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung                int screen = (mTargetCell[0] < 0) ?
2203c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung                        mDragInfo.screen : indexOfChild(dropTargetLayout);
220431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                int spanX = mDragInfo != null ? mDragInfo.spanX : 1;
220531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                int spanY = mDragInfo != null ? mDragInfo.spanY : 1;
2206cb3382b1bfe1a534b1b44f5c4def9b2db605ac90Adam Cohen                // First we find the cell nearest to point at which the item is
2207440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy                // dropped, without any consideration to whether there is an item there.
2208440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy
22096569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy                mTargetCell = findNearestArea((int) mDragViewVisualCenter[0], (int)
2210a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung                        mDragViewVisualCenter[1], spanX, spanY, dropTargetLayout, mTargetCell);
2211580e27748137ff08599aa719d106b31215a28353Winson Chung                float distance = dropTargetLayout.getDistanceFromCell(mDragViewVisualCenter[0],
2212580e27748137ff08599aa719d106b31215a28353Winson Chung                        mDragViewVisualCenter[1], mTargetCell);
2213580e27748137ff08599aa719d106b31215a28353Winson Chung
2214580e27748137ff08599aa719d106b31215a28353Winson Chung                // If the item being dropped is a shortcut and the nearest drop
2215580e27748137ff08599aa719d106b31215a28353Winson Chung                // cell also contains a shortcut, then create a folder with the two shortcuts.
2216580e27748137ff08599aa719d106b31215a28353Winson Chung                if (!mInScrollArea && createUserFolderIfNecessary(cell, container,
2217580e27748137ff08599aa719d106b31215a28353Winson Chung                        dropTargetLayout, mTargetCell, distance, false, d.dragView, null)) {
2218580e27748137ff08599aa719d106b31215a28353Winson Chung                    return;
2219580e27748137ff08599aa719d106b31215a28353Winson Chung                }
2220580e27748137ff08599aa719d106b31215a28353Winson Chung
2221580e27748137ff08599aa719d106b31215a28353Winson Chung                if (addToExistingFolderIfNecessary(cell, dropTargetLayout, mTargetCell,
2222580e27748137ff08599aa719d106b31215a28353Winson Chung                        distance, d, false)) {
2223580e27748137ff08599aa719d106b31215a28353Winson Chung                    return;
2224580e27748137ff08599aa719d106b31215a28353Winson Chung                }
2225580e27748137ff08599aa719d106b31215a28353Winson Chung
2226580e27748137ff08599aa719d106b31215a28353Winson Chung                // Aside from the special case where we're dropping a shortcut onto a shortcut,
2227580e27748137ff08599aa719d106b31215a28353Winson Chung                // we need to find the nearest cell location that is vacant
2228580e27748137ff08599aa719d106b31215a28353Winson Chung                ItemInfo item = (ItemInfo) d.dragInfo;
2229580e27748137ff08599aa719d106b31215a28353Winson Chung                int minSpanX = item.spanX;
2230580e27748137ff08599aa719d106b31215a28353Winson Chung                int minSpanY = item.spanY;
2231580e27748137ff08599aa719d106b31215a28353Winson Chung                if (item.minSpanX > 0 && item.minSpanY > 0) {
2232580e27748137ff08599aa719d106b31215a28353Winson Chung                    minSpanX = item.minSpanX;
2233580e27748137ff08599aa719d106b31215a28353Winson Chung                    minSpanY = item.minSpanY;
2234580e27748137ff08599aa719d106b31215a28353Winson Chung                }
2235a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung
2236a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung                int[] resultSpan = new int[2];
2237a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung                mTargetCell = mDragTargetLayout.createArea((int) mDragViewVisualCenter[0],
2238a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung                        (int) mDragViewVisualCenter[1], minSpanX, minSpanY, spanX, spanY, cell,
223968846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung                        mTargetCell, resultSpan, CellLayout.MODE_ON_DROP);
2240a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung
2241a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung                boolean foundCell = mTargetCell[0] >= 0 && mTargetCell[1] >= 0;
2242a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung                if (foundCell && (resultSpan[0] != item.spanX || resultSpan[1] != item.spanY)) {
2243a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung                    resizeOnDrop = true;
2244a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung                    item.spanX = resultSpan[0];
2245a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung                    item.spanY = resultSpan[1];
2246a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung                }
2247a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung
2248580e27748137ff08599aa719d106b31215a28353Winson Chung                if (mCurrentPage != screen && !hasMovedIntoHotseat) {
2249580e27748137ff08599aa719d106b31215a28353Winson Chung                    snapScreen = screen;
2250580e27748137ff08599aa719d106b31215a28353Winson Chung                    snapToPage(screen);
2251580e27748137ff08599aa719d106b31215a28353Winson Chung                }
2252580e27748137ff08599aa719d106b31215a28353Winson Chung
2253580e27748137ff08599aa719d106b31215a28353Winson Chung                if (foundCell) {
2254580e27748137ff08599aa719d106b31215a28353Winson Chung                    final ItemInfo info = (ItemInfo) cell.getTag();
2255580e27748137ff08599aa719d106b31215a28353Winson Chung                    if (hasMovedLayouts) {
2256557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung                        // Reparent the view
2257580e27748137ff08599aa719d106b31215a28353Winson Chung                        getParentCellLayoutForView(cell).removeView(cell);
2258580e27748137ff08599aa719d106b31215a28353Winson Chung                        addInScreen(cell, container, screen, mTargetCell[0], mTargetCell[1],
2259580e27748137ff08599aa719d106b31215a28353Winson Chung                                info.spanX, info.spanY);
2260580e27748137ff08599aa719d106b31215a28353Winson Chung                    }
2261580e27748137ff08599aa719d106b31215a28353Winson Chung
2262580e27748137ff08599aa719d106b31215a28353Winson Chung                    // update the item's position after drop
2263a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung                    CellLayout.LayoutParams lp = (CellLayout.LayoutParams) cell.getLayoutParams();
2264a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung                    lp.cellX = mTargetCell[0];
2265a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung                    lp.cellY = mTargetCell[1];
2266a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung                    lp.cellHSpan = item.spanX;
226768846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung                    lp.cellVSpan = item.spanY;
226868846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung                    cell.setId(LauncherModel.getCellLayoutChildId(container, mDragInfo.screen,
226968846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung                            mTargetCell[0], mTargetCell[1], mDragInfo.spanX, mDragInfo.spanY));
227038b4f7c5eab773ad36048b5ab8713750dcaaf748Michael Jurka
227168846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung                    if (container != LauncherSettings.Favorites.CONTAINER_HOTSEAT &&
2272a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung                            cell instanceof LauncherAppWidgetHostView) {
227368846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung                        final CellLayout cellLayout = dropTargetLayout;
227468846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung                        // We post this call so that the widget has a chance to be placed
227533945b21544bc98381df17726a3537c292d8c985Michael Jurka                        // in its final location
227668846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung
227768846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung                        final LauncherAppWidgetHostView hostView = (LauncherAppWidgetHostView) cell;
2278a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung                        AppWidgetProviderInfo pinfo = hostView.getAppWidgetInfo();
227968846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung                        if (pinfo.resizeMode != AppWidgetProviderInfo.RESIZE_NONE) {
2280580e27748137ff08599aa719d106b31215a28353Winson Chung                            final Runnable addResizeFrame = new Runnable() {
2281a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung                                public void run() {
2282a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung                                    DragLayer dragLayer = mLauncher.getDragLayer();
2283a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung                                    dragLayer.addResizeFrame(info, hostView, cellLayout);
2284a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung                                }
2285580e27748137ff08599aa719d106b31215a28353Winson Chung                            };
2286a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung                            resizeRunnable = (new Runnable() {
2287a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung                                public void run() {
2288a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung                                    if (!isPageMoving()) {
228955cef262f97749300c2f6e764da0b00cbcb78879Winson Chung                                        addResizeFrame.run();
229068846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung                                    } else {
229168846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung                                        mDelayedResizeRunnable = addResizeFrame;
229268846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung                                    }
229368846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung                                }
229468846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung                            });
229568846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung                        }
2296580e27748137ff08599aa719d106b31215a28353Winson Chung                    }
2297580e27748137ff08599aa719d106b31215a28353Winson Chung
2298580e27748137ff08599aa719d106b31215a28353Winson Chung                    LauncherModel.moveItemInDatabase(mLauncher, info, container, screen, lp.cellX,
2299580e27748137ff08599aa719d106b31215a28353Winson Chung                            lp.cellY);
2300580e27748137ff08599aa719d106b31215a28353Winson Chung                } else {
2301580e27748137ff08599aa719d106b31215a28353Winson Chung                    // If we can't find a drop location, we return the item to its original position
2302580e27748137ff08599aa719d106b31215a28353Winson Chung                    CellLayout.LayoutParams lp = (CellLayout.LayoutParams) cell.getLayoutParams();
23030d5aad7edbed3ed5c13904cc13ec8842ffe8837bDianne Hackborn                    mTargetCell[0] = lp.cellX;
230468846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung                    mTargetCell[1] = lp.cellY;
2305c4e772e4b3f21bde342e475ebc49b5b76b8f74e8Michael Jurka                }
230668846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung            }
2307580e27748137ff08599aa719d106b31215a28353Winson Chung
230868846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung            final CellLayout parent = (CellLayout) cell.getParent().getParent();
230968846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung            final Runnable finalResizeRunnable = resizeRunnable;
231068846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung            // Prepare it to be animated into its new position
231168846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung            // This must be called after the view has been re-parented
2312c9d95c5897fc5ebbf53903d4ab18ad13d196f643Michael Jurka            final Runnable onCompleteRunnable = new Runnable() {
23133d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung                @Override
23143d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung                public void run() {
2315580e27748137ff08599aa719d106b31215a28353Winson Chung                    mAnimatingViewIntoPlace = false;
231668846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung                    updateChildrenLayersEnabled();
231768846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung                    if (finalResizeRunnable != null) {
231868846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung                        finalResizeRunnable.run();
231968846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung                    }
232068846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung                }
232168846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung            };
232268846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung            mAnimatingViewIntoPlace = true;
232368846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung            if (d.dragView.hasDrawn()) {
232468846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung                final ItemInfo info = (ItemInfo) cell.getTag();
232568846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung                if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET) {
232668846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung                    int animationType = resizeOnDrop ? ANIMATE_INTO_POSITION_AND_RESIZE :
232768846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung                            ANIMATE_INTO_POSITION_AND_DISAPPEAR;
232868846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung                    animateWidgetDrop(info, parent, d.dragView,
232955cef262f97749300c2f6e764da0b00cbcb78879Winson Chung                            onCompleteRunnable, animationType, cell, false);
2330a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung                } else {
2331a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung                    int duration = snapScreen < 0 ? -1 : ADJACENT_SCREEN_DROP_DURATION;
2332a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung                    mLauncher.getDragLayer().animateViewIntoPosition(d.dragView, cell, duration,
2333580e27748137ff08599aa719d106b31215a28353Winson Chung                            onCompleteRunnable, this);
2334a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung                }
2335a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung            } else {
233633945b21544bc98381df17726a3537c292d8c985Michael Jurka                d.deferDragViewCleanupPostAnimation = false;
2337a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung                cell.setVisibility(VISIBLE);
2338a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung            }
2339a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung            parent.onDropChild(cell);
2340a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung        }
2341a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung    }
2342a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung
2343a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung    public void onFlingToDelete(DragObject d, int x, int y, PointF vec) {
23444516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka        // Do nothing
23454516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka    }
23464516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka
23474516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka    public void setFinalScrollForPageChange(int screen) {
23484516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka        if (screen >= 0) {
23494516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka            mSavedScrollX = getScrollX();
23504516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka            CellLayout cl = (CellLayout) getChildAt(screen);
23514516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka            mSavedTranslationX = cl.getTranslationX();
23524516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka            mSavedRotationY = cl.getRotationY();
23534516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka            final int newX = getChildOffset(screen) - getRelativeChildOffset(screen);
23544516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka            setScrollX(newX);
23554516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka            cl.setTranslationX(0f);
23564516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka            cl.setRotationY(0f);
23574516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka        }
23584516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka    }
23594516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka
2360d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka    public void resetFinalScrollForPageChange(int screen) {
23614516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka        if (screen >= 0) {
23624516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka            CellLayout cl = (CellLayout) getChildAt(screen);
23634516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka            setScrollX(mSavedScrollX);
23644516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka            cl.setTranslationX(mSavedTranslationX);
23654516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka            cl.setRotationY(mSavedRotationY);
23664516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka        }
23674516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka    }
23684516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka
23694516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka    public void getViewLocationRelativeToSelf(View v, int[] location) {
23704516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka        getLocationInWindow(location);
23714516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka        int x = location[0];
23724516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka        int y = location[1];
23734516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka
23744516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka        v.getLocationInWindow(location);
23753d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        int vX = location[0];
23763d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        int vY = location[1];
23773d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung
23783d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        location[0] = vX - x;
23793d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        location[1] = vY - y;
23803d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung    }
23813d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung
23823d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung    public void onDragEnter(DragObject d) {
23833d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        mDragHasEnteredWorkspace = true;
23844516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka        if (mDragTargetLayout != null) {
23854516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka            mDragTargetLayout.setIsDragOverlapping(false);
23864516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka            mDragTargetLayout.onDragExit();
23874516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka        }
23884516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka        mDragTargetLayout = getCurrentDropLayout();
23894516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka        mDragTargetLayout.setIsDragOverlapping(true);
23904516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka        mDragTargetLayout.onDragEnter();
23914516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka
23924516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka        // Because we don't have space in the Phone UI (the CellLayouts run to the edge) we
23934516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka        // don't need to show the outlines
23944516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka        if (LauncherApplication.isScreenLarge()) {
2395e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen            showOutlines();
23964516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka        }
23974516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka    }
23984516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka
2399e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen    private void doDragExit(DragObject d) {
24000280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        // Clean up folders
24014516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka        cleanupFolderCreation(d);
24024516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka
24034516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka        // Clean up reorder
24044516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka        if (mReorderAlarm != null) {
24054516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka            mReorderAlarm.cancelAlarm();
24064516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka            mLastReorderX = -1;
24074516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka            mLastReorderY = -1;
24084516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka        }
24094516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka
2410f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka        // Reset the scroll area and previous drag target
2411f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka        onResetScrollArea();
24124516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka
2413f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka        if (mDragTargetLayout != null) {
2414f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka            mDragTargetLayout.setIsDragOverlapping(false);
24154516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka            mDragTargetLayout.onDragExit();
24164516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka        }
24174516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka        mLastDragOverView = null;
24184516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka        mDragMode = DRAG_MODE_NONE;
24194516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka        mSpringLoadedDragController.cancel();
24204516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka
24214516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka        if (!mIsPageMoving) {
24224516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka            hideOutlines();
24234516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka        }
24244516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka    }
24254516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka
24264516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka    public void onDragExit(DragObject d) {
24274516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka        mDragHasEnteredWorkspace = false;
24284516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka        doDragExit(d);
24294516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka    }
24304516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka
24314516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka    public DropTarget getDropTargetDelegate(DragObject d) {
24324516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka        return null;
24334516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka    }
24344516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka
24354516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka    /**
24364516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka     * Tests to see if the drop will be accepted by Launcher, and if so, includes additional data
24374516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka     * in the returned structure related to the widgets that match the drop (or a null list if it is
24384516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka     * a shortcut drop).  If the drop is not accepted then a null structure is returned.
2439a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka     */
24404516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka    private Pair<Integer, List<WidgetMimeTypeHandlerData>> validateDrag(DragEvent event) {
24414516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka        final LauncherModel model = mLauncher.getModel();
24424516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka        final ClipDescription desc = event.getClipDescription();
24434516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka        final int mimeTypeCount = desc.getMimeTypeCount();
24444516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka        for (int i = 0; i < mimeTypeCount; ++i) {
24454516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka            final String mimeType = desc.getMimeType(i);
24464516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka            if (mimeType.equals(InstallShortcutReceiver.SHORTCUT_MIMETYPE)) {
24474516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka                return new Pair<Integer, List<WidgetMimeTypeHandlerData>>(i, null);
24484516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka            } else {
24494516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka                final List<WidgetMimeTypeHandlerData> widgets =
245000618753e9f0ad941c13efb0b6804e4a06ecb076Adam Cohen                    model.resolveWidgetsForMimeType(mContext, mimeType);
24514516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka                if (widgets.size() > 0) {
24524516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka                    return new Pair<Integer, List<WidgetMimeTypeHandlerData>>(i, widgets);
2453a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka                }
2454a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka            }
24550280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        }
24564516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka        return null;
2457a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka    }
24583d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung
2459a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka    /*
246000618753e9f0ad941c13efb0b6804e4a06ecb076Adam Cohen    *
24614516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka    * Convert the 2D coordinate xy from the parent View's coordinate space to this CellLayout's
24624516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka    * coordinate space. The argument xy is modified with the return result.
24630280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    *
24644516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka    */
24654516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka   void mapPointFromSelfToChild(View v, float[] xy) {
24664516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka       mapPointFromSelfToChild(v, xy, null);
24674516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka   }
24684516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka
24694516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka   /*
24704516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka    *
247100618753e9f0ad941c13efb0b6804e4a06ecb076Adam Cohen    * Convert the 2D coordinate xy from the parent View's coordinate space to this CellLayout's
24724516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka    * coordinate space. The argument xy is modified with the return result.
24734516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka    *
24744516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka    * if cachedInverseMatrix is not null, this method will just use that matrix instead of
24754516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka    * computing it itself; we use this to avoid redundant matrix inversions in
24764516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka    * findMatchingPageForDragOver
24774516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka    *
247800618753e9f0ad941c13efb0b6804e4a06ecb076Adam Cohen    */
247900618753e9f0ad941c13efb0b6804e4a06ecb076Adam Cohen   void mapPointFromSelfToChild(View v, float[] xy, Matrix cachedInverseMatrix) {
24804516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka       if (cachedInverseMatrix == null) {
24814516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka           v.getMatrix().invert(mTempInverseMatrix);
24824516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka           cachedInverseMatrix = mTempInverseMatrix;
24834516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka       }
24844516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka       int scrollX = mScrollX;
24854516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka       if (mNextPage != INVALID_PAGE) {
24860280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka           scrollX = mScroller.getFinalX();
2487a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka       }
2488a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka       xy[0] = xy[0] + scrollX - v.getLeft();
24894516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka       xy[1] = xy[1] + mScrollY - v.getTop();
2490a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka       cachedInverseMatrix.mapPoints(xy);
2491a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka   }
2492a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka
2493a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka   /*
2494e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen    * Maps a point from the Workspace's coordinate system to another sibling view's. (Workspace
2495e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen    * covers the full screen)
2496e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen    */
2497e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen   void mapPointFromSelfToSibling(View v, float[] xy) {
2498e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen       xy[0] = xy[0] - v.getLeft();
2499e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen       xy[1] = xy[1] - v.getTop();
2500e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen   }
2501e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen
2502e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen   /*
2503e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen    *
2504e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen    * Convert the 2D coordinate xy from this CellLayout's coordinate space to
2505e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen    * the parent View's coordinate space. The argument xy is modified with the return result.
2506e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen    *
2507e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen    */
2508e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen   void mapPointFromChildToSelf(View v, float[] xy) {
2509e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen       v.getMatrix().mapPoints(xy);
2510e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen       int scrollX = mScrollX;
2511e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen       if (mNextPage != INVALID_PAGE) {
2512e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen           scrollX = mScroller.getFinalX();
2513e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen       }
2514e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen       xy[0] -= (scrollX - v.getLeft());
2515e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen       xy[1] -= (mScrollY - v.getTop());
2516e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen   }
2517e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen
2518e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen   static private float squaredDistance(float[] point1, float[] point2) {
2519e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        float distanceX = point1[0] - point2[0];
2520e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        float distanceY = point2[1] - point2[1];
2521e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        return distanceX * distanceX + distanceY * distanceY;
2522e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen   }
2523e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen
2524e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen    /*
2525e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen     *
2526ea359c6aee44c0fe3bb94f7002c3b49208b32b7fWinson Chung     * Returns true if the passed CellLayout cl overlaps with dragView
2527ea359c6aee44c0fe3bb94f7002c3b49208b32b7fWinson Chung     *
2528ea359c6aee44c0fe3bb94f7002c3b49208b32b7fWinson Chung     */
2529ea359c6aee44c0fe3bb94f7002c3b49208b32b7fWinson Chung    boolean overlaps(CellLayout cl, DragView dragView,
2530ea359c6aee44c0fe3bb94f7002c3b49208b32b7fWinson Chung            int dragViewX, int dragViewY, Matrix cachedInverseMatrix) {
2531ea359c6aee44c0fe3bb94f7002c3b49208b32b7fWinson Chung        // Transform the coordinates of the item being dragged to the CellLayout's coordinates
2532ea359c6aee44c0fe3bb94f7002c3b49208b32b7fWinson Chung        final float[] draggedItemTopLeft = mTempDragCoordinates;
2533ea359c6aee44c0fe3bb94f7002c3b49208b32b7fWinson Chung        draggedItemTopLeft[0] = dragViewX;
2534cb3382b1bfe1a534b1b44f5c4def9b2db605ac90Adam Cohen        draggedItemTopLeft[1] = dragViewY;
2535c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung        final float[] draggedItemBottomRight = mTempDragBottomRightCoordinates;
2536c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung        draggedItemBottomRight[0] = draggedItemTopLeft[0] + dragView.getDragRegionWidth();
2537d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka        draggedItemBottomRight[1] = draggedItemTopLeft[1] + dragView.getDragRegionHeight();
2538c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung
25394afe9b31f51022538b30646fe83780e83bf22490Winson Chung        // Transform the dragged item's top left coordinates
25403d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        // to the CellLayout's local coordinates
2541c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung        mapPointFromSelfToChild(cl, draggedItemTopLeft, cachedInverseMatrix);
2542c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung        float overlapRegionLeft = Math.max(0f, draggedItemTopLeft[0]);
2543c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung        float overlapRegionTop = Math.max(0f, draggedItemTopLeft[1]);
2544c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung
254500618753e9f0ad941c13efb0b6804e4a06ecb076Adam Cohen        if (overlapRegionLeft <= cl.getWidth() && overlapRegionTop >= 0) {
25464afe9b31f51022538b30646fe83780e83bf22490Winson Chung            // Transform the dragged item's bottom right coordinates
254700618753e9f0ad941c13efb0b6804e4a06ecb076Adam Cohen            // to the CellLayout's local coordinates
2548c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung            mapPointFromSelfToChild(cl, draggedItemBottomRight, cachedInverseMatrix);
2549d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka            float overlapRegionRight = Math.min(cl.getWidth(), draggedItemBottomRight[0]);
2550ea359c6aee44c0fe3bb94f7002c3b49208b32b7fWinson Chung            float overlapRegionBottom = Math.min(cl.getHeight(), draggedItemBottomRight[1]);
25514afe9b31f51022538b30646fe83780e83bf22490Winson Chung
25524afe9b31f51022538b30646fe83780e83bf22490Winson Chung            if (overlapRegionRight >= 0 && overlapRegionBottom <= cl.getHeight()) {
25534afe9b31f51022538b30646fe83780e83bf22490Winson Chung                float overlap = (overlapRegionRight - overlapRegionLeft) *
25544afe9b31f51022538b30646fe83780e83bf22490Winson Chung                         (overlapRegionBottom - overlapRegionTop);
25554afe9b31f51022538b30646fe83780e83bf22490Winson Chung                if (overlap > 0) {
25564afe9b31f51022538b30646fe83780e83bf22490Winson Chung                    return true;
2557c7da555dc5b252042dff0a6920efb1bfeb4a0c9aWinson Chung                }
25584afe9b31f51022538b30646fe83780e83bf22490Winson Chung             }
2559c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung        }
2560c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung        return false;
2561c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung    }
2562e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen
2563c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung    /*
2564c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung     *
2565c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung     * This method returns the CellLayout that is currently being dragged to. In order to drag
2566d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka     * to a CellLayout, either the touch point must be directly over the CellLayout, or as a second
2567c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung     * strategy, we see if the dragView is overlapping any CellLayout and choose the closest one
2568c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung     *
2569c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung     * Return null if no CellLayout is currently being dragged over
2570c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung     *
2571c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung     */
2572c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung    private CellLayout findMatchingPageForDragOver(
2573c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung            DragView dragView, float originX, float originY, boolean exact) {
2574c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung        // We loop through all the screens (ie CellLayouts) and see which ones overlap
2575d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka        // with the item being dragged and then choose the one that's closest to the touch point
2576c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung        final int screenCount = getChildCount();
25774afe9b31f51022538b30646fe83780e83bf22490Winson Chung        CellLayout bestMatchingScreen = null;
25784afe9b31f51022538b30646fe83780e83bf22490Winson Chung        float smallestDistSoFar = Float.MAX_VALUE;
25794afe9b31f51022538b30646fe83780e83bf22490Winson Chung
25804afe9b31f51022538b30646fe83780e83bf22490Winson Chung        for (int i = 0; i < screenCount; i++) {
25814afe9b31f51022538b30646fe83780e83bf22490Winson Chung            CellLayout cl = (CellLayout) getChildAt(i);
2582d3ef3065ab0941567c45e9aec98783138b623c68Michael Jurka
2583d3ef3065ab0941567c45e9aec98783138b623c68Michael Jurka            final float[] touchXy = {originX, originY};
2584c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung            // Transform the touch coordinates to the CellLayout's local coordinates
25853d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung            // If the touch point is within the bounds of the cell layout, we can return immediately
2586ea359c6aee44c0fe3bb94f7002c3b49208b32b7fWinson Chung            cl.getMatrix().invert(mTempInverseMatrix);
25873d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung            mapPointFromSelfToChild(cl, touchXy, mTempInverseMatrix);
25883d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung
25893d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung            if (touchXy[0] >= 0 && touchXy[0] <= cl.getWidth() &&
25903d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung                    touchXy[1] >= 0 && touchXy[1] <= cl.getHeight()) {
25913d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung                return cl;
25923d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung            }
25933d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung
25943d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung            if (!exact) {
2595c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung                // Get the center of the cell layout in screen coordinates
2596c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung                final float[] cellLayoutCenter = mTempCellLayoutCenterCoordinates;
2597c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung                cellLayoutCenter[0] = cl.getWidth()/2;
2598c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung                cellLayoutCenter[1] = cl.getHeight()/2;
2599d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka                mapPointFromChildToSelf(cl, cellLayoutCenter);
2600c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung
2601c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung                touchXy[0] = originX;
2602c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung                touchXy[1] = originY;
2603c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung
2604c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung                // Calculate the distance between the center of the CellLayout
2605a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka                // and the touch point
2606c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung                float dist = squaredDistance(touchXy, cellLayoutCenter);
2607c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung
2608c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung                if (dist < smallestDistSoFar) {
260919072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen                    smallestDistSoFar = dist;
2610c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung                    bestMatchingScreen = cl;
26113d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung                }
26123d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung            }
26133d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        }
26143d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        return bestMatchingScreen;
26153d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung    }
2616c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung
261719072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen    // This is used to compute the visual center of the dragView. This point is then
2618c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung    // used to visualize drop locations and determine where to drop an item. The idea is that
2619c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung    // the visual center represents the user's interpretation of where the item is, and hence
2620c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung    // is the appropriate point to use when determining drop location.
2621c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung    private float[] getDragViewVisualCenter(int x, int y, int xOffset, int yOffset,
2622c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung            DragView dragView, float[] recycle) {
2623c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung        float res[];
2624c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung        if (recycle == null) {
2625c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung            res = new float[2];
2626c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung        } else {
2627c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung            res = recycle;
2628c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung        }
2629c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung
2630d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka        // First off, the drag view has been shifted in a way that is not represented in the
26311262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy        // x and y values or the x/yOffsets. Here we account for that shift.
2632c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung        x += getResources().getDimensionPixelSize(R.dimen.dragViewOffsetX);
2633c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung        y += getResources().getDimensionPixelSize(R.dimen.dragViewOffsetY);
2634c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung
2635c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung        // These represent the visual top and left of drag view if a dragRect was provided.
2636c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung        // If a dragRect was not provided, then they correspond to the actual view left and
2637c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung        // top, as the dragRect is in that case taken to be the entire dragView.
2638c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung        // R.dimen.dragViewOffsetY.
2639c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung        int left = x - xOffset;
2640c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung        int top = y - yOffset;
2641c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung
2642c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung        // In order to find the visual center, we shift by half the dragRect
2643c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung        res[0] = left + dragView.getDragRegion().width() / 2;
2644c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung        res[1] = top + dragView.getDragRegion().height() / 2;
2645c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung
2646c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung        return res;
2647c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung    }
2648c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung
2649c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung    private boolean isDragWidget(DragObject d) {
2650c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung        return (d.dragInfo instanceof LauncherAppWidgetInfo ||
2651c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung                d.dragInfo instanceof PendingAddWidgetInfo);
2652c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung    }
2653c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung    private boolean isExternalDragWidget(DragObject d) {
2654c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung        return d.dragSource != this && isDragWidget(d);
2655c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung    }
2656c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung
2657c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung    public void onDragOver(DragObject d) {
2658c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung        // Skip drag over events while we are dragging over side pages
2659c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung        if (mInScrollArea || mIsSwitchingState || mState == State.SMALL) return;
2660c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung
2661c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung        Rect r = new Rect();
2662c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung        CellLayout layout = null;
2663976ebec9e31643d3513f9f0de2b433d9aa186ce9Patrick Dubroy        ItemInfo item = (ItemInfo) d.dragInfo;
2664c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung
266531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // Ensure that we have proper spans for the item that we are dropping
266631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        if (item.spanX < 0 || item.spanY < 0) throw new RuntimeException("Improper spans found");
2667c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        mDragViewVisualCenter = getDragViewVisualCenter(d.x, d.y, d.xOffset, d.yOffset,
2668c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            d.dragView, mDragViewVisualCenter);
2669c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen
2670c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        final View child = (mDragInfo == null) ? null : mDragInfo.cell;
2671c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        // Identify whether we have dragged over a side page
2672c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        if (isSmall()) {
2673c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            if (mLauncher.getHotseat() != null && !isExternalDragWidget(d)) {
2674c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen                mLauncher.getHotseat().getHitRect(r);
267519072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen                if (r.contains(d.x, d.y)) {
267669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen                    layout = mLauncher.getHotseat().getLayout();
267769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen                }
267869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            }
267919072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen            if (layout == null) {
268069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen                layout = findMatchingPageForDragOver(d.dragView, d.x, d.y, false);
268169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            }
268269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            if (layout != mDragTargetLayout) {
268369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen                // Cancel all intermediate folder states
268419072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen                cleanupFolderCreation(d);
268519072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen
268619072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen                if (mDragTargetLayout != null) {
268719072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen                    mDragTargetLayout.setIsDragOverlapping(false);
268819072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen                    mDragTargetLayout.onDragExit();
268919072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen                }
269069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen                mDragTargetLayout = layout;
269169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen                if (mDragTargetLayout != null) {
269219072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen                    mDragTargetLayout.setIsDragOverlapping(true);
269369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen                    mDragTargetLayout.onDragEnter();
269469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen                } else {
269519072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen                    mLastDragOverView = null;
269619072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen                    mDragMode = DRAG_MODE_NONE;
269719072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen                }
269819072da7441e07d5e90026d9e9e1b38f11245e44Adam Cohen
2699a34abf8c781485b788fddacb352d586bffca886cWinson Chung                boolean isInSpringLoadedMode = (mState == State.SPRING_LOADED);
2700a34abf8c781485b788fddacb352d586bffca886cWinson Chung                if (isInSpringLoadedMode) {
2701a34abf8c781485b788fddacb352d586bffca886cWinson Chung                    if (mLauncher.isHotseatLayout(layout)) {
2702a34abf8c781485b788fddacb352d586bffca886cWinson Chung                        mSpringLoadedDragController.cancel();
2703a34abf8c781485b788fddacb352d586bffca886cWinson Chung                    } else {
2704a34abf8c781485b788fddacb352d586bffca886cWinson Chung                        mSpringLoadedDragController.setAlarm(mDragTargetLayout);
2705a34abf8c781485b788fddacb352d586bffca886cWinson Chung                    }
2706a34abf8c781485b788fddacb352d586bffca886cWinson Chung                }
27072b9ff37edb3f5965559b3ff7d37e418b4a2917a1Patrick Dubroy            }
27082b9ff37edb3f5965559b3ff7d37e418b4a2917a1Patrick Dubroy        } else {
27092b9ff37edb3f5965559b3ff7d37e418b4a2917a1Patrick Dubroy            // Test to see if we are over the hotseat otherwise just use the current page
27102b9ff37edb3f5965559b3ff7d37e418b4a2917a1Patrick Dubroy            if (mLauncher.getHotseat() != null && !isDragWidget(d)) {
2711120980bd00f5eecec5717f49a3d7db96571025a9Adam Cohen                mLauncher.getHotseat().getHitRect(r);
2712120980bd00f5eecec5717f49a3d7db96571025a9Adam Cohen                if (r.contains(d.x, d.y)) {
2713bbaa75c8c432c46c00ee2eb836e438b3774d6709Patrick Dubroy                    layout = mLauncher.getHotseat().getLayout();
27142b9ff37edb3f5965559b3ff7d37e418b4a2917a1Patrick Dubroy                }
27152b9ff37edb3f5965559b3ff7d37e418b4a2917a1Patrick Dubroy            }
27160280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            if (layout == null) {
27172b9ff37edb3f5965559b3ff7d37e418b4a2917a1Patrick Dubroy                layout = getCurrentDropLayout();
27182b9ff37edb3f5965559b3ff7d37e418b4a2917a1Patrick Dubroy            }
27192b9ff37edb3f5965559b3ff7d37e418b4a2917a1Patrick Dubroy            if (layout != mDragTargetLayout) {
2720d5e42733799817d11d739b0a882da8dda721126dAdam Cohen                if (mDragTargetLayout != null) {
2721d5e42733799817d11d739b0a882da8dda721126dAdam Cohen                    mDragTargetLayout.setIsDragOverlapping(false);
2722e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen                    mDragTargetLayout.onDragExit();
2723d5e42733799817d11d739b0a882da8dda721126dAdam Cohen                }
2724d5e42733799817d11d739b0a882da8dda721126dAdam Cohen                mDragTargetLayout = layout;
2725120980bd00f5eecec5717f49a3d7db96571025a9Adam Cohen                mDragTargetLayout.setIsDragOverlapping(true);
2726120980bd00f5eecec5717f49a3d7db96571025a9Adam Cohen                mDragTargetLayout.onDragEnter();
2727120980bd00f5eecec5717f49a3d7db96571025a9Adam Cohen            }
2728120980bd00f5eecec5717f49a3d7db96571025a9Adam Cohen        }
2729120980bd00f5eecec5717f49a3d7db96571025a9Adam Cohen
2730120980bd00f5eecec5717f49a3d7db96571025a9Adam Cohen        // Handle the drag over
2731120980bd00f5eecec5717f49a3d7db96571025a9Adam Cohen        if (mDragTargetLayout != null) {
2732120980bd00f5eecec5717f49a3d7db96571025a9Adam Cohen            // We want the point to be mapped to the dragTarget.
2733557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung            if (mLauncher.isHotseatLayout(mDragTargetLayout)) {
2734557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung                mapPointFromSelfToSibling(mLauncher.getHotseat(), mDragViewVisualCenter);
2735557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung            } else {
2736557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung                mapPointFromSelfToChild(mDragTargetLayout, mDragViewVisualCenter, null);
2737557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung            }
27386a3fd3f042c8bfa7d83e29c1eeadff21323ab089Winson Chung            ItemInfo info = (ItemInfo) d.dragInfo;
2739557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung
2740557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung            mTargetCell = findNearestArea((int) mDragViewVisualCenter[0],
2741b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen                    (int) mDragViewVisualCenter[1], 1, 1, mDragTargetLayout, mTargetCell);
2742b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen            float targetCellDistance = mDragTargetLayout.getDistanceFromCell(
2743b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen                    mDragViewVisualCenter[0], mDragViewVisualCenter[1], mTargetCell);
2744b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen
2745b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen            final View dragOverView = mDragTargetLayout.getChildAt(mTargetCell[0],
2746b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen                    mTargetCell[1]);
2747b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen
2748b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen            final View lastDragOverView = mLastDragOverView;
2749b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen            if (mLastDragOverView != dragOverView) {
27503d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung                mDragMode = DRAG_MODE_NONE;
27513d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung                mLastDragOverView = dragOverView;
27523d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung                if (mReorderAlarm != null) {
2753557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung                    mReorderAlarm.cancelAlarm();
27543d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung                }
27553d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung            }
275676078c4ef35b6e95fb6d8129a32cf52a36625e28Adam Cohen
275776078c4ef35b6e95fb6d8129a32cf52a36625e28Adam Cohen            boolean folder = willCreateOrAddToFolder(info, mDragTargetLayout, mTargetCell,
2758b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen                    targetCellDistance, dragOverView, lastDragOverView);
2759b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen
2760b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen            int minSpanX = item.spanX;
2761b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen            int minSpanY = item.spanY;
2762558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            if (item.minSpanX > 0 && item.minSpanY > 0) {
2763558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                minSpanX = item.minSpanX;
2764558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                minSpanY = item.minSpanY;
2765558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            }
2766558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen
2767558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            if (!folder && !mReorderAlarm.alarmPending() && (mLastReorderX != mTargetCell[0] ||
2768558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                    mLastReorderY != mTargetCell[1])) {
2769558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                cancelFolderCreation();
2770558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                ReorderAlarmListener listener = new ReorderAlarmListener(mDragViewVisualCenter,
2771558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                        minSpanX, minSpanY, item.spanX, item.spanY, d.dragView, child);
2772558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                mReorderAlarm.setOnAlarmListener(listener);
2773558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                mReorderAlarm.setAlarm(REORDER_TIMEOUT);
2774558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen            } else if (folder) {
2775558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                if (mReorderAlarm != null) {
2776558baaf0a0b1c6a9062a6771088098533a35222bAdam Cohen                    mReorderAlarm.cancelAlarm();
2777b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen                }
2778557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung            }
2779557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung            // TODO: need to determine what we're going to about visualizing drop locations
2780557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung            /*
2781557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung            boolean resize = resultSpan[0] != info.spanX || resultSpan[1] != info.spanY;
2782b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen            if (!folder) {
2783557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung                mDragTargetLayout.visualizeDropLocation(child, mDragOutline,
2784b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen                        (int) mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1],
27853d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung                        mTargetCell[0], mTargetCell[1], resultSpan[0], resultSpan[1], resize,
2786557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung                        d.dragView.getDragVisualizeOffset(), d.dragView.getDragRegion());
2787557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung
2788b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen            }
27893d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung            */
2790557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung        }
2791557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung    }
2792b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen
2793b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen    private boolean willCreateOrAddToFolder(ItemInfo info, CellLayout targetLayout,
2794557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung            int[] targetCell, float distance, View dragOverView, View lastDragOverView) {
2795557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung        boolean userFolderPending = willCreateUserFolder(info, targetLayout, targetCell, distance,
2796557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung                false);
2797b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen
2798b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen        if (userFolderPending && mDragMode == DRAG_MODE_NONE) {
2799b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen            mFolderCreationAlarm.setOnAlarmListener(new
2800b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen                    FolderCreationAlarmListener(targetLayout, targetCell[0], targetCell[1]));
2801b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen            mFolderCreationAlarm.setAlarm(FOLDER_CREATION_TIMEOUT);
2802b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen        }
2803b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen
2804b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen        boolean willAddToFolder =
2805b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen                willAddToExistingUserFolder(info, targetLayout, targetCell, distance);
28064b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen
2807b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen        if (willAddToFolder && mDragMode == DRAG_MODE_NONE) {
2808b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen            FolderIcon fi = ((FolderIcon) dragOverView);
28094b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen            mDragMode = DRAG_MODE_ADD_TO_FOLDER;
2810b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen            fi.onDragEnter(info);
2811b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen            if (targetLayout != null) {
2812b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen                targetLayout.clearDragOutlines();
2813b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen            }
2814b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen        }
2815b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen
2816b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen        if (dragOverView != lastDragOverView || (mCreateUserFolderOnDrop && !userFolderPending)
2817b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen                || (!willAddToFolder && mDragMode == DRAG_MODE_ADD_TO_FOLDER)) {
2818b7e1618c627c6471c565f4f599228648d9e70a10Adam Cohen            cancelFolderCreation();
28199c6de3d7c3e7d40e1e443b6fd69e3077ab9e9673Michael Jurka            if (lastDragOverView != null && lastDragOverView instanceof FolderIcon) {
28209c6de3d7c3e7d40e1e443b6fd69e3077ab9e9673Michael Jurka                ((FolderIcon) lastDragOverView).onDragExit(info);
28219c6de3d7c3e7d40e1e443b6fd69e3077ab9e9673Michael Jurka            }
282231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
28239c6de3d7c3e7d40e1e443b6fd69e3077ab9e9673Michael Jurka
28249c6de3d7c3e7d40e1e443b6fd69e3077ab9e9673Michael Jurka        return willAddToFolder || userFolderPending;
28259c6de3d7c3e7d40e1e443b6fd69e3077ab9e9673Michael Jurka    }
28269c6de3d7c3e7d40e1e443b6fd69e3077ab9e9673Michael Jurka
28279c6de3d7c3e7d40e1e443b6fd69e3077ab9e9673Michael Jurka    private void cleanupFolderCreation(DragObject d) {
2828c9d95c5897fc5ebbf53903d4ab18ad13d196f643Michael Jurka        if (mDragFolderRingAnimator != null && mCreateUserFolderOnDrop) {
28299c6de3d7c3e7d40e1e443b6fd69e3077ab9e9673Michael Jurka            mDragFolderRingAnimator.animateToNaturalState();
28309c6de3d7c3e7d40e1e443b6fd69e3077ab9e9673Michael Jurka        }
28319c6de3d7c3e7d40e1e443b6fd69e3077ab9e9673Michael Jurka        if (mLastDragOverView != null && mLastDragOverView instanceof FolderIcon) {
28329c6de3d7c3e7d40e1e443b6fd69e3077ab9e9673Michael Jurka            if (d != null) {
2833df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen                ((FolderIcon) mLastDragOverView).onDragExit(d.dragInfo);
2834c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            }
2835c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        }
28369c6de3d7c3e7d40e1e443b6fd69e3077ab9e9673Michael Jurka        mFolderCreationAlarm.cancelAlarm();
28379c6de3d7c3e7d40e1e443b6fd69e3077ab9e9673Michael Jurka    }
28389c6de3d7c3e7d40e1e443b6fd69e3077ab9e9673Michael Jurka
28399c6de3d7c3e7d40e1e443b6fd69e3077ab9e9673Michael Jurka    private void cancelFolderCreation() {
284031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        if (mDragFolderRingAnimator != null && mCreateUserFolderOnDrop) {
2841c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            mDragFolderRingAnimator.animateToNaturalState();
2842c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        }
2843c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        mCreateUserFolderOnDrop = false;
2844c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        mFolderCreationAlarm.cancelAlarm();
2845c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen    }
2846557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung
28473d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung    class FolderCreationAlarmListener implements OnAlarmListener {
28483d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        CellLayout layout;
2849c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        int cellX;
2850c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        int cellY;
28513e8f811f31a2275e778244427271f77f4116c08bAdam Cohen
2852c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        public FolderCreationAlarmListener(CellLayout layout, int cellX, int cellY) {
2853c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            this.layout = layout;
285410b1737910ea7890ca95bbbe5363fd5aa513b856Adam Cohen            this.cellX = cellX;
285510b1737910ea7890ca95bbbe5363fd5aa513b856Adam Cohen            this.cellY = cellY;
2856c4e772e4b3f21bde342e475ebc49b5b76b8f74e8Michael Jurka        }
28579c6de3d7c3e7d40e1e443b6fd69e3077ab9e9673Michael Jurka
2858c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        public void onAlarm(Alarm alarm) {
2859c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            if (mDragFolderRingAnimator == null) {
28609c6de3d7c3e7d40e1e443b6fd69e3077ab9e9673Michael Jurka                mDragFolderRingAnimator = new FolderRingAnimator(mLauncher, null);
28619c6de3d7c3e7d40e1e443b6fd69e3077ab9e9673Michael Jurka            }
286231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            mDragFolderRingAnimator.setCell(cellX, cellY);
28633d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung            mDragFolderRingAnimator.setCellLayout(layout);
28643d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung            mDragFolderRingAnimator.animateToAcceptState();
2865716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen            layout.showFolderAccept(mDragFolderRingAnimator);
2866d3ef3065ab0941567c45e9aec98783138b623c68Michael Jurka            layout.clearDragOutlines();
28676569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy            mCreateUserFolderOnDrop = true;
2868d5e42733799817d11d739b0a882da8dda721126dAdam Cohen            mDragMode = DRAG_MODE_CREATE_FOLDER;
2869d5e42733799817d11d739b0a882da8dda721126dAdam Cohen        }
28703d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung    }
2871aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
28723e8f811f31a2275e778244427271f77f4116c08bAdam Cohen    class ReorderAlarmListener implements OnAlarmListener {
28733e8f811f31a2275e778244427271f77f4116c08bAdam Cohen        float[] dragViewCenter;
28744b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen        int minSpanX, minSpanY, spanX, spanY;
28754b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen        DragView dragView;
28764b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen        View child;
28774b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen
2878557d6ed50cc6560163440aa134870ef0bb11415bWinson Chung        public ReorderAlarmListener(float[] dragViewCenter, int minSpanX, int minSpanY, int spanX,
28794b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen                int spanY, DragView dragView, View child) {
28804b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen            this.dragViewCenter = dragViewCenter;
28814b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen            this.minSpanX = minSpanX;
28824b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen            this.minSpanY = minSpanY;
28834b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen            this.spanX = spanX;
28844b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen            this.spanY = spanY;
28854b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen            this.child = child;
28864b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen            this.dragView = dragView;
28874b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen        }
28884b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen
28894b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen        public void onAlarm(Alarm alarm) {
28904b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen            int[] resultSpan = new int[2];
28914b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen            mTargetCell = mDragTargetLayout.createArea((int) mDragViewVisualCenter[0],
28924b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen                (int) mDragViewVisualCenter[1], minSpanX, minSpanY, spanX, spanY,
28934b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen                child, mTargetCell, resultSpan, CellLayout.MODE_DRAG_OVER);
28944b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen
28954b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen            mLastReorderX = mTargetCell[0];
28964b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen            mLastReorderY = mTargetCell[1];
28974b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen
28984b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen            if (mDragMode == DRAG_MODE_ADD_TO_FOLDER) {
28994b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen            }
29004b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen            mDragMode = DRAG_MODE_REORDER;
29014b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen
29024b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen            // TODO: need to determine what we're going to about visualizing drop locations
29034b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen            /*
29044b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen            boolean resize = resultSpan[0] != spanX || resultSpan[1] != spanY;
29054b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen            mDragTargetLayout.visualizeDropLocation(child, mDragOutline,
29064b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen                (int) mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1],
29074b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen                mTargetCell[0], mTargetCell[1], resultSpan[0], resultSpan[1], resize,
29084b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen                dragView.getDragVisualizeOffset(), dragView.getDragRegion());
29094b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen            */
29104b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen        }
29114b285c5a60028f7c9ce39cfb318a730d0ae95c27Adam Cohen    }
2912af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka
291331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
2914aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung    public void getHitRect(Rect outRect) {
291570864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey        // We want the workspace to have the whole area of the display (it will find the correct
291670864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey        // cell layout to drop to in the existing drag/drop logic.
291770864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey        outRect.set(0, 0, mDisplayWidth, mDisplayHeight);
291870864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey    }
29195f445425606b2c27276a79e9e871cf7f67b1b719Patrick Dubroy
29205f445425606b2c27276a79e9e871cf7f67b1b719Patrick Dubroy    /**
292170864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey     * Add the item specified by dragInfo to the given layout.
292231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @return true if successful
292370864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey     */
29240280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public boolean addExternalItemToScreen(ItemInfo dragInfo, CellLayout layout) {
29250280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        if (layout.findCellForSpan(mTempEstimate, dragInfo.spanX, dragInfo.spanY)) {
29260280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            onDropExternal(dragInfo.dropPos, (ItemInfo) dragInfo, (CellLayout) layout, false);
29270280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            return true;
29280280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        }
29290280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        mLauncher.showOutOfSpaceMessage();
29300280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        return false;
29310280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
29320280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
29330280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    private void onDropExternal(int[] touchXY, Object dragInfo,
293470864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey            CellLayout cellLayout, boolean insertAtFirst) {
2935e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        onDropExternal(touchXY, dragInfo, cellLayout, insertAtFirst, null);
2936e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen    }
293770864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey
29386a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka    /**
293970864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey     * Drop an item that didn't originate on one of the workspace screens.
29400280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * It may have come from Launcher (e.g. from all apps or customize), or it may have
2941e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen     * come from another app altogether.
294270864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey     *
2943aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     * NOTE: This can also be called when we are outside of a drag event, when we want
2944df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * to add an item to one of the workspace screens.
2945df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     */
2946e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen    private void onDropExternal(final int[] touchXY, final Object dragInfo,
2947e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen            final CellLayout cellLayout, boolean insertAtFirst, DragObject d) {
2948df0353815c629fc678824b07a234b89a1ff94208Adam Cohen        final Runnable exitSpringLoadedRunnable = new Runnable() {
2949df0353815c629fc678824b07a234b89a1ff94208Adam Cohen            @Override
2950e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen            public void run() {
2951df0353815c629fc678824b07a234b89a1ff94208Adam Cohen                mLauncher.exitSpringLoadedDragModeDelayed(true, false, null);
2952e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen            }
2953df0353815c629fc678824b07a234b89a1ff94208Adam Cohen        };
2954df0353815c629fc678824b07a234b89a1ff94208Adam Cohen
29554c98d9235d164680186180974719f551cf935d08Winson Chung        ItemInfo info = (ItemInfo) dragInfo;
295631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int spanX = info.spanX;
2957c2f7f4794867cd1b3e97fd0f379ad8ad15958a6cMichael Jurka        int spanY = info.spanY;
295800acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato        if (mDragInfo != null) {
2959d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka            spanX = mDragInfo.spanX;
2960d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka            spanY = mDragInfo.spanY;
2961d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka        }
2962d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka
2963d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka        final long container = mLauncher.isHotseatLayout(cellLayout) ?
296431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                LauncherSettings.Favorites.CONTAINER_HOTSEAT :
296531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                    LauncherSettings.Favorites.CONTAINER_DESKTOP;
2966e3887cc4ec3cebda2333298e56a35acb49ccdf13Patrick Dubroy        final int screen = indexOfChild(cellLayout);
2967e3887cc4ec3cebda2333298e56a35acb49ccdf13Patrick Dubroy        if (!mLauncher.isHotseatLayout(cellLayout) && screen != mCurrentPage
2968e3887cc4ec3cebda2333298e56a35acb49ccdf13Patrick Dubroy                && mState != State.SPRING_LOADED) {
2969c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            snapToPage(screen);
2970aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        }
2971d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka
2972d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka        if (info instanceof PendingAddItemInfo) {
29733d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung            final PendingAddItemInfo pendingInfo = (PendingAddItemInfo) dragInfo;
2974d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka
2975d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka            boolean findNearestVacantCell = true;
2976d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka            if (pendingInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) {
297700acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato                mTargetCell = findNearestArea((int) touchXY[0], (int) touchXY[1], spanX, spanY,
297831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                        cellLayout, mTargetCell);
2979ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy                float distance = cellLayout.getDistanceFromCell(mDragViewVisualCenter[0],
2980e3887cc4ec3cebda2333298e56a35acb49ccdf13Patrick Dubroy                        mDragViewVisualCenter[1], mTargetCell);
2981e3887cc4ec3cebda2333298e56a35acb49ccdf13Patrick Dubroy                if (willCreateUserFolder((ItemInfo) d.dragInfo, mDragTargetLayout, mTargetCell,
2982e3887cc4ec3cebda2333298e56a35acb49ccdf13Patrick Dubroy                        distance, true) || willAddToExistingUserFolder((ItemInfo) d.dragInfo,
2983c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen                                mDragTargetLayout, mTargetCell, distance)) {
29843d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung                    findNearestVacantCell = false;
29853d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung                }
29863d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung            }
29873d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung
29883d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung            final ItemInfo item = (ItemInfo) d.dragInfo;
29893d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung            if (findNearestVacantCell) {
29903d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung                int minSpanX = item.spanX;
299131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                int minSpanY = item.spanY;
29924be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                if (item.minSpanX > 0 && item.minSpanY > 0) {
299331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                    minSpanX = item.minSpanX;
299431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                    minSpanY = item.minSpanY;
299531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                }
29960280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                int[] resultSpan = new int[2];
29970280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                mTargetCell = mDragTargetLayout.createArea((int) mDragViewVisualCenter[0],
29980280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                        (int) mDragViewVisualCenter[1], minSpanX, minSpanY, info.spanX, info.spanY,
29990280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                        null, mTargetCell, resultSpan, CellLayout.MODE_ON_DROP_EXTERNAL);
30000142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka                item.spanX = resultSpan[0];
30010142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka                item.spanY = resultSpan[1];
30020142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka            }
30030142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka
30040142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka            Runnable onAnimationCompleteRunnable = new Runnable() {
30050142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka                @Override
30060142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka                public void run() {
300731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                    // When dragging and dropping from customization tray, we deal with creating
3008d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka                    // widgets/shortcuts/folders in a slightly different way
30090142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka                    switch (pendingInfo.itemType) {
301031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                    case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
301195bb800de9b0142bea0110b074eddbcf0e475736Adam Cohen                        int span[] = new int[2];
301295bb800de9b0142bea0110b074eddbcf0e475736Adam Cohen                        span[0] = item.spanX;
301395bb800de9b0142bea0110b074eddbcf0e475736Adam Cohen                        span[1] = item.spanY;
301495bb800de9b0142bea0110b074eddbcf0e475736Adam Cohen                        mLauncher.addAppWidgetFromDrop((PendingAddWidgetInfo) pendingInfo,
301531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                                container, screen, mTargetCell, span, null);
301631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                        break;
30170142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka                    case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
301831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                        mLauncher.processShortcutFromDrop(pendingInfo.componentName,
3019d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka                                container, screen, mTargetCell, null);
30200142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka                        break;
302131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                    default:
302295bb800de9b0142bea0110b074eddbcf0e475736Adam Cohen                        throw new IllegalStateException("Unknown item type: " +
302395bb800de9b0142bea0110b074eddbcf0e475736Adam Cohen                                pendingInfo.itemType);
302495bb800de9b0142bea0110b074eddbcf0e475736Adam Cohen                    }
302595bb800de9b0142bea0110b074eddbcf0e475736Adam Cohen                    cellLayout.onDragExit();
302631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                }
3027138a04170d964da9cdec228e95b976875ae52481Karl Rosaen            };
30281262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy            View finalView = pendingInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET
30291c4cf4a11f3f7f24bbf65f958fdd22295d0bbd55Winson Chung                    ? ((PendingAddWidgetInfo) pendingInfo).boundWidget : null;
30301c4cf4a11f3f7f24bbf65f958fdd22295d0bbd55Winson Chung            int animationStyle = ANIMATE_INTO_POSITION_AND_DISAPPEAR;
30311c4cf4a11f3f7f24bbf65f958fdd22295d0bbd55Winson Chung            if (pendingInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET &&
30321c4cf4a11f3f7f24bbf65f958fdd22295d0bbd55Winson Chung                    ((PendingAddWidgetInfo) pendingInfo).info.configure != null) {
30331c4cf4a11f3f7f24bbf65f958fdd22295d0bbd55Winson Chung                animationStyle = ANIMATE_INTO_POSITION_AND_REMAIN;
30341c4cf4a11f3f7f24bbf65f958fdd22295d0bbd55Winson Chung            }
30351c4cf4a11f3f7f24bbf65f958fdd22295d0bbd55Winson Chung            animateWidgetDrop(info, cellLayout, d.dragView, onAnimationCompleteRunnable,
30361c4cf4a11f3f7f24bbf65f958fdd22295d0bbd55Winson Chung                    animationStyle, finalView, true);
30371c4cf4a11f3f7f24bbf65f958fdd22295d0bbd55Winson Chung        } else {
30381c4cf4a11f3f7f24bbf65f958fdd22295d0bbd55Winson Chung            // This is for other drag/drop cases, like dragging from All Apps
3039d74c984fcc61f86160476a2543faff715e3ee2fdMichael Jurka            View view = null;
3040d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka
304154fa3b95557c283976e8c1aa8a157b460b0b4513Patrick Dubroy            switch (info.itemType) {
304254fa3b95557c283976e8c1aa8a157b460b0b4513Patrick Dubroy            case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
304354fa3b95557c283976e8c1aa8a157b460b0b4513Patrick Dubroy            case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
3044c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen                if (info.container == NO_ID && info instanceof ApplicationInfo) {
304554fa3b95557c283976e8c1aa8a157b460b0b4513Patrick Dubroy                    // Came from all apps -- make a copy
304654fa3b95557c283976e8c1aa8a157b460b0b4513Patrick Dubroy                    info = new ShortcutInfo((ApplicationInfo) info);
3047c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung                }
30480207c522472d7252f146f4d39efa456ca5248c6bPatrick Dubroy                view = mLauncher.createShortcut(R.layout.application, cellLayout,
3049c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung                        (ShortcutInfo) info);
30500207c522472d7252f146f4d39efa456ca5248c6bPatrick Dubroy                break;
30510207c522472d7252f146f4d39efa456ca5248c6bPatrick Dubroy            case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
3052c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung                view = FolderIcon.fromXml(R.layout.folder_icon, mLauncher, cellLayout,
3053c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung                        (FolderInfo) info, mIconCache);
305470b9530f3147663d38875260b48d931793b7d378Patrick Dubroy                break;
3055c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung            default:
3056c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung                throw new IllegalStateException("Unknown item type: " + info.itemType);
3057c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung            }
3058c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung
305970b9530f3147663d38875260b48d931793b7d378Patrick Dubroy            // First we find the cell nearest to point at which the item is
306008ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy            // dropped, without any consideration to whether there is an item there.
306108ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy            if (touchXY != null) {
30621262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy                mTargetCell = findNearestArea((int) touchXY[0], (int) touchXY[1], spanX, spanY,
30631262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy                        cellLayout, mTargetCell);
3064d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka                float distance = cellLayout.getDistanceFromCell(mDragViewVisualCenter[0],
3065c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung                        mDragViewVisualCenter[1], mTargetCell);
3066c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung                d.postAnimationRunnable = exitSpringLoadedRunnable;
3067c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung                if (createUserFolderIfNecessary(view, container, cellLayout, mTargetCell, distance,
3068c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung                        true, d.dragView, d.postAnimationRunnable)) {
3069c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung                    return;
3070c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung                }
3071c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung                if (addToExistingFolderIfNecessary(view, cellLayout, mTargetCell, distance, d,
3072c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung                        true)) {
3073c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung                    return;
3074c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung                }
3075c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung            }
3076c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung
3077c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung            if (touchXY != null) {
3078c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung                // when dragging and dropping, just find the closest free spot
3079c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung                mTargetCell = mDragTargetLayout.createArea((int) mDragViewVisualCenter[0],
3080c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung                        (int) mDragViewVisualCenter[1], 1, 1, 1, 1,
3081c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung                        null, mTargetCell, null, CellLayout.MODE_ON_DROP);
3082c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung            } else {
3083c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung                cellLayout.findCellForSpan(mTargetCell, 1, 1);
3084c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung            }
3085c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung            addInScreen(view, container, screen, mTargetCell[0], mTargetCell[1], info.spanX,
3086c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung                    info.spanY, insertAtFirst);
30871262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy            cellLayout.onDropChild(view);
3088c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung            CellLayout.LayoutParams lp = (CellLayout.LayoutParams) view.getLayoutParams();
30891262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy            cellLayout.getShortcutsAndWidgets().measureChild(view);
30901262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy
30913d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung
30923d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung            LauncherModel.addOrMoveItemInDatabase(mLauncher, info, container, screen,
30933d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung                    lp.cellX, lp.cellY);
30943d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung
30953d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung            if (d.dragView != null) {
30963d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung                // We wrap the animation call in the temporary set and reset of the current
30973d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung                // cellLayout to its final transform -- this means we animate the drag view to
30983d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung                // the correct final location.
30993d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung                setFinalTransitionTransform(cellLayout);
31003d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung                mLauncher.getDragLayer().animateViewIntoPosition(d.dragView, view,
31013d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung                        exitSpringLoadedRunnable);
31023d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung                resetTransitionTransform(cellLayout);
31033d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung            }
31043d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        }
31053d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung    }
31063d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung
31073d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung    public Bitmap createWidgetBitmap(ItemInfo widgetInfo, View layout) {
31083d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        int[] unScaledSize = mLauncher.getWorkspace().estimateItemSize(widgetInfo.spanX,
31093d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung                widgetInfo.spanY, widgetInfo, false);
31103d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        int visibility = layout.getVisibility();
31113d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        layout.setVisibility(VISIBLE);
31123d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung
31133d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        int width = MeasureSpec.makeMeasureSpec(unScaledSize[0], MeasureSpec.EXACTLY);
31143d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        int height = MeasureSpec.makeMeasureSpec(unScaledSize[1], MeasureSpec.EXACTLY);
31153d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        Bitmap b = Bitmap.createBitmap(unScaledSize[0], unScaledSize[1],
31163d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung                Bitmap.Config.ARGB_8888);
31173d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        Canvas c = new Canvas(b);
31183d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung
31193d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        layout.measure(width, height);
31203d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        layout.layout(0, 0, unScaledSize[0], unScaledSize[1]);
31213d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        layout.draw(c);
31223d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        c.setBitmap(null);
31233d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        layout.setVisibility(visibility);
31243d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        return b;
31253d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung    }
312631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
31273d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung    private void getFinalPositionForDropAnimation(int[] loc, float[] scaleXY,
31283d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung            DragView dragView, CellLayout layout, ItemInfo info, int[] targetCell, View finalView,
31293d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung            boolean external) {
31303d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        // Now we animate the dragView, (ie. the widget or shortcut preview) into its final
31313d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        // location and size on the home screen.
31323d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        int spanX = info.spanX;
31333d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        int spanY = info.spanY;
31343d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung
31353d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        Rect r = estimateItemPosition(layout, info, targetCell[0], targetCell[1], spanX, spanY);
31363d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        loc[0] = r.left;
31373d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        loc[1] = r.top;
31383d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung
313931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        setFinalTransitionTransform(layout);
31403d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        float cellLayoutScale =
31413d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung                mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(layout, loc);
314231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        resetTransitionTransform(layout);
3143aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        float dragViewScaleX = (1.0f * r.width()) / dragView.getMeasuredWidth();
314431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        float dragViewScaleY = (1.0f * r.height()) / dragView.getMeasuredHeight();
314531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
314631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // The animation will scale the dragView about its center, so we need to center about
314731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // the final location.
314831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        loc[0] -= (dragView.getMeasuredWidth() - cellLayoutScale * r.width()) / 2;
314931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        loc[1] -= (dragView.getMeasuredHeight() - cellLayoutScale * r.height()) / 2;
315031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
315131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        scaleXY[0] = dragViewScaleX * cellLayoutScale;
315231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        scaleXY[1] = dragViewScaleY * cellLayoutScale;
31533d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung    }
31543d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung
31553d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung    public void animateWidgetDrop(ItemInfo info, CellLayout cellLayout, DragView dragView,
315631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            final Runnable onCompleteRunnable, int animationType, final View finalView,
31573d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung            boolean external) {
315831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        Rect from = new Rect();
315931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        mLauncher.getDragLayer().getViewRectRelativeToSelf(dragView, from);
316031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
316131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int[] finalPos = new int[2];
316231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        float scaleXY[] = new float[2];
316331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        getFinalPositionForDropAnimation(finalPos, scaleXY, dragView, cellLayout, info, mTargetCell,
316431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                finalView, external);
316531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
3166df0353815c629fc678824b07a234b89a1ff94208Adam Cohen        Resources res = mLauncher.getResources();
31673d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        int duration = res.getInteger(R.integer.config_dropAnimMaxDuration) - 200;
31683d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung
3169df0353815c629fc678824b07a234b89a1ff94208Adam Cohen        // In the case where we've prebound the widget, we remove it from the DragLayer
3170df0353815c629fc678824b07a234b89a1ff94208Adam Cohen        if (finalView instanceof AppWidgetHostView && external) {
3171df0353815c629fc678824b07a234b89a1ff94208Adam Cohen            mLauncher.getDragLayer().removeView(finalView);
3172df0353815c629fc678824b07a234b89a1ff94208Adam Cohen        }
3173df0353815c629fc678824b07a234b89a1ff94208Adam Cohen        if ((animationType == ANIMATE_INTO_POSITION_AND_RESIZE || external) && finalView != null) {
3174df0353815c629fc678824b07a234b89a1ff94208Adam Cohen            Bitmap crossFadeBitmap = createWidgetBitmap(info, finalView);
3175df0353815c629fc678824b07a234b89a1ff94208Adam Cohen            dragView.setCrossFadeBitmap(crossFadeBitmap);
3176df0353815c629fc678824b07a234b89a1ff94208Adam Cohen            dragView.crossFade((int) (duration * 0.8f));
3177df0353815c629fc678824b07a234b89a1ff94208Adam Cohen        } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET && external) {
317831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            scaleXY[0] = scaleXY[1] = Math.min(scaleXY[0],  scaleXY[1]);
317964e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato        }
3180629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy
3181574d20ec84551370987dde530c27ec493bdef564Romain Guy        DragLayer dragLayer = mLauncher.getDragLayer();
318264e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato        if (animationType == CANCEL_TWO_STAGE_WIDGET_DROP_ANIMATION) {
318364e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato            mLauncher.getDragLayer().animateViewIntoPosition(dragView, finalPos, 0f, 0.1f, 0.1f,
318464e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato                    DragLayer.ANIMATION_END_DISAPPEAR, onCompleteRunnable, duration);
318564e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato        } else {
318664e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato            int endStyle;
318764e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato            if (animationType == ANIMATE_INTO_POSITION_AND_REMAIN) {
31883d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung                endStyle = DragLayer.ANIMATION_END_REMAIN_VISIBLE;
31893d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung            } else {
31907a25a9e39a13df706daeb0a4a82273f3c5151997Winson Chung                endStyle = DragLayer.ANIMATION_END_DISAPPEAR;;
3191629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy            }
3192629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy
3193629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy            Runnable onComplete = new Runnable() {
3194629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy                @Override
3195629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy                public void run() {
3196629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy                    if (finalView != null) {
3197aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung                        finalView.setVisibility(VISIBLE);
3198629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy                    }
3199629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy                    if (onCompleteRunnable != null) {
3200629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy                        onCompleteRunnable.run();
3201629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy                    }
3202aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung                }
32030589f0f66ce498512c6ee47482c649d88294c9d0Joe Onorato            };
32040589f0f66ce498512c6ee47482c649d88294c9d0Joe Onorato            dragLayer.animateViewIntoPosition(dragView, from.left, from.top, finalPos[0],
3205629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy                    finalPos[1], 1, 1, 1, scaleXY[0], scaleXY[1], onComplete, endStyle,
3206629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy                    duration, this);
3207aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        }
320864e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato    }
320964e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato
321064e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato    public void setFinalTransitionTransform(CellLayout layout) {
321164e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato        if (isSwitchingState()) {
321264e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato            int index = indexOfChild(layout);
321364e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato            mCurrentScaleX = layout.getScaleX();
321464e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato            mCurrentScaleY = layout.getScaleY();
3215629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy            mCurrentTranslationX = layout.getTranslationX();
3216df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen            mCurrentTranslationY = layout.getTranslationY();
3217df2cc41acbfacd576f99483a4af1cda32ebd3d09Adam Cohen            mCurrentRotationY = layout.getRotationY();
32180589f0f66ce498512c6ee47482c649d88294c9d0Joe Onorato            layout.setScaleX(mNewScaleXs[index]);
3219629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy            layout.setScaleY(mNewScaleYs[index]);
3220df1e4e868a1970b756486dadd652651d40276d36Adam Cohen            layout.setTranslationX(mNewTranslationXs[index]);
3221df1e4e868a1970b756486dadd652651d40276d36Adam Cohen            layout.setTranslationY(mNewTranslationYs[index]);
3222aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            layout.setRotationY(mNewRotationYs[index]);
3223629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy        }
32240589f0f66ce498512c6ee47482c649d88294c9d0Joe Onorato    }
3225629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy    public void resetTransitionTransform(CellLayout layout) {
3226629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy        if (isSwitchingState()) {
3227aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            mCurrentScaleX = layout.getScaleX();
322864e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato            mCurrentScaleY = layout.getScaleY();
322964e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato            mCurrentTranslationX = layout.getTranslationX();
323064e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato            mCurrentTranslationY = layout.getTranslationY();
3231df1e4e868a1970b756486dadd652651d40276d36Adam Cohen            mCurrentRotationY = layout.getRotationY();
323264e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato            layout.setScaleX(mCurrentScaleX);
323364e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato            layout.setScaleY(mCurrentScaleY);
3234629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy            layout.setTranslationX(mCurrentTranslationX);
3235629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy            layout.setTranslationY(mCurrentTranslationY);
3236df1e4e868a1970b756486dadd652651d40276d36Adam Cohen            layout.setRotationY(mCurrentRotationY);
3237df1e4e868a1970b756486dadd652651d40276d36Adam Cohen        }
3238df1e4e868a1970b756486dadd652651d40276d36Adam Cohen    }
3239629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy
3240629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy    /**
3241629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy     * Return the current {@link CellLayout}, correctly picking the destination
3242629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy     * screen while a scroll is in progress.
3243629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy     */
3244e1cc6c3745c9ba721b6ab888d74c9d9e1d13ea6aDaniel Sandler    public CellLayout getCurrentDropLayout() {
324564e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato        return (CellLayout) getChildAt(mNextPage == INVALID_PAGE ? mCurrentPage : mNextPage);
324664e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato    }
324764e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato
3248aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung    /**
324964e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato     * Return the current CellInfo describing our current drag; this method exists
325064e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato     * so that Launcher can sync this object with the correct info when the activity is created/
3251629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy     * destroyed
3252574d20ec84551370987dde530c27ec493bdef564Romain Guy     *
3253574d20ec84551370987dde530c27ec493bdef564Romain Guy     */
3254aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung    public CellLayout.CellInfo getDragInfo() {
3255629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy        return mDragInfo;
3256629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy    }
3257629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy
32587a25a9e39a13df706daeb0a4a82273f3c5151997Winson Chung    /**
32597a25a9e39a13df706daeb0a4a82273f3c5151997Winson Chung     * Calculate the nearest cell where the given object would be dropped.
32607a25a9e39a13df706daeb0a4a82273f3c5151997Winson Chung     *
3261629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy     * pixelX and pixelY should be in the coordinate system of layout
3262629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy     */
3263629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy    private int[] findNearestArea(int pixelX, int pixelY,
3264574d20ec84551370987dde530c27ec493bdef564Romain Guy            int spanX, int spanY, CellLayout layout, int[] recycle) {
3265aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        return layout.findNearestArea(
3266629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy                pixelX, pixelY, spanX, spanY, recycle);
3267629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy    }
3268629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy
32695c16f3ecd6b47bff3abbe40deb3d39c66a3b0012Romain Guy    void setup(DragController dragController) {
327031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        mSpringLoadedDragController = new SpringLoadedDragController(mLauncher);
3271629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy        mDragController = dragController;
327231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
327331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // hardware layers on children are enabled on startup, but should be disabled until
3274f96811cdf564469a7a654a0c876288c9fd14f35eThe Android Open Source Project        // needed
327564e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato        updateChildrenLayersEnabled();
32763d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        setWallpaperDimension();
32773d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung    }
3278f96811cdf564469a7a654a0c876288c9fd14f35eThe Android Open Source Project
3279f96811cdf564469a7a654a0c876288c9fd14f35eThe Android Open Source Project    /**
3280f96811cdf564469a7a654a0c876288c9fd14f35eThe Android Open Source Project     * Called at the end of a drag which originated on the workspace.
3281f96811cdf564469a7a654a0c876288c9fd14f35eThe Android Open Source Project     */
32820589f0f66ce498512c6ee47482c649d88294c9d0Joe Onorato    public void onDropCompleted(View target, DragObject d, boolean success) {
32830589f0f66ce498512c6ee47482c649d88294c9d0Joe Onorato        if (success) {
3284f96811cdf564469a7a654a0c876288c9fd14f35eThe Android Open Source Project            if (target != this) {
3285f96811cdf564469a7a654a0c876288c9fd14f35eThe Android Open Source Project                if (mDragInfo != null) {
3286f96811cdf564469a7a654a0c876288c9fd14f35eThe Android Open Source Project                    getParentCellLayoutForView(mDragInfo.cell).removeView(mDragInfo.cell);
3287f96811cdf564469a7a654a0c876288c9fd14f35eThe Android Open Source Project                    if (mDragInfo.cell instanceof DropTarget) {
3288f96811cdf564469a7a654a0c876288c9fd14f35eThe Android Open Source Project                        mDragController.removeDropTarget((DropTarget) mDragInfo.cell);
3289f96811cdf564469a7a654a0c876288c9fd14f35eThe Android Open Source Project                    }
329064e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato                }
329164e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato            }
3292aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        } else if (mDragInfo != null) {
329364e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato            // NOTE: When 'success' is true, onDragExit is called by the DragController before
329464e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato            // calling onDropCompleted(). We call it ourselves here, but maybe this should be
329564e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato            // moved into DragController.cancelDrag().
329664e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato            doDragExit(null);
329764e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato            CellLayout cellLayout;
329864e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato            if (mLauncher.isHotseatLayout(target)) {
329964e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato                cellLayout = mLauncher.getHotseat().getLayout();
330064e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato            } else {
3301f96811cdf564469a7a654a0c876288c9fd14f35eThe Android Open Source Project                cellLayout = (CellLayout) getChildAt(mDragInfo.screen);
3302f96811cdf564469a7a654a0c876288c9fd14f35eThe Android Open Source Project            }
3303f96811cdf564469a7a654a0c876288c9fd14f35eThe Android Open Source Project            cellLayout.onDropChild(mDragInfo.cell);
3304f96811cdf564469a7a654a0c876288c9fd14f35eThe Android Open Source Project        }
3305f96811cdf564469a7a654a0c876288c9fd14f35eThe Android Open Source Project        if (d.cancelled &&  mDragInfo.cell != null) {
3306f96811cdf564469a7a654a0c876288c9fd14f35eThe Android Open Source Project                mDragInfo.cell.setVisibility(VISIBLE);
330714f122bf847e50a3e7730ccbe57abc25d086a01bJoe Onorato        }
3308de1af7661548692d370518528ff91c7422b9c8aeWinson Chung        mDragOutline = null;
3309de1af7661548692d370518528ff91c7422b9c8aeWinson Chung        mDragInfo = null;
3310de1af7661548692d370518528ff91c7422b9c8aeWinson Chung
3311de1af7661548692d370518528ff91c7422b9c8aeWinson Chung        saveWorkspaceStateToDb();
3312de1af7661548692d370518528ff91c7422b9c8aeWinson Chung        // Hide the scrolling indicator after you pick up an item
3313de1af7661548692d370518528ff91c7422b9c8aeWinson Chung        hideScrollingIndicator(false);
3314c45b16862918a0c6c253bba12032165b030565afJoe Onorato    }
33150142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka
331631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public void saveWorkspaceStateToDb() {
331731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int count = getChildCount();
33180142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka        for (int i = 0; i < count; i++) {
33190142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka            CellLayout cl = (CellLayout) getChildAt(i);
33200142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka            if (cl.isItemPlacementDirty()) {
332131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                updateItemLocationsInDatabase(cl);
33220142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka                cl.setItemPlacementDirty(false);
3323f314b0eab03bb354c14b6c89f694a6685bd246d9Winson Chung            }
332431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
33256a0f57dfafced837a2a282d8feec28d5418be3b9Winson Chung    }
33266a0f57dfafced837a2a282d8feec28d5418be3b9Winson Chung
33276a0f57dfafced837a2a282d8feec28d5418be3b9Winson Chung    private void updateItemLocationsInDatabase(CellLayout cl) {
33286a0f57dfafced837a2a282d8feec28d5418be3b9Winson Chung        int count = cl.getShortcutsAndWidgets().getChildCount();
33296a0f57dfafced837a2a282d8feec28d5418be3b9Winson Chung        int screen = indexOfChild(cl);
33306a0f57dfafced837a2a282d8feec28d5418be3b9Winson Chung        for (int i = 0; i < count; i++) {
33316a0f57dfafced837a2a282d8feec28d5418be3b9Winson Chung            View v = cl.getShortcutsAndWidgets().getChildAt(i);
33328dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            ItemInfo info = (ItemInfo) v.getTag();
33338dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen
33348dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen            LauncherModel.moveItemInDatabase(mLauncher, info, Favorites.CONTAINER_DESKTOP, screen,
33358dfcba4af7a7ece09e8c7d96053e54f3a383e905Adam Cohen                        info.cellX, info.cellY);
333632174c878c77b4e0f13449f4c26ff6b487bc7ca6Winson Chung        }
333732174c878c77b4e0f13449f4c26ff6b487bc7ca6Winson Chung    }
333832174c878c77b4e0f13449f4c26ff6b487bc7ca6Winson Chung
333932174c878c77b4e0f13449f4c26ff6b487bc7ca6Winson Chung    public boolean supportsFlingToDelete() {
334032174c878c77b4e0f13449f4c26ff6b487bc7ca6Winson Chung        return true;
334132174c878c77b4e0f13449f4c26ff6b487bc7ca6Winson Chung    }
334232174c878c77b4e0f13449f4c26ff6b487bc7ca6Winson Chung
3343a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung    public boolean isDropEnabled() {
3344a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung        return true;
3345a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung    }
3346a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung
3347a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung    @Override
3348a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung    protected void onRestoreInstanceState(Parcelable state) {
3349a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung        super.onRestoreInstanceState(state);
3350a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung        Launcher.setScreen(mCurrentPage);
3351a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung    }
3352a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung
3353a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung    @Override
3354a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung    public void scrollLeft() {
3355a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung        if (!isSmall() && !mIsSwitchingState) {
3356a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung            super.scrollLeft();
3357a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung        }
3358a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung        Folder openFolder = getOpenFolder();
3359a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung        if (openFolder != null) {
3360a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung            openFolder.completeDragExit();
3361a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung        }
3362a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung    }
3363a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung
3364a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung    @Override
3365a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung    public void scrollRight() {
3366a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung        if (!isSmall() && !mIsSwitchingState) {
3367a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung            super.scrollRight();
3368a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung        }
3369a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung        Folder openFolder = getOpenFolder();
3370a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung        if (openFolder != null) {
3371a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung            openFolder.completeDragExit();
3372a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung        }
3373a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung    }
3374a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung
3375a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung    @Override
3376a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung    public boolean onEnterScrollArea(int x, int y, int direction) {
3377a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung        // Ignore the scroll area if we are dragging over the hot seat
3378a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung        if (mLauncher.getHotseat() != null) {
3379a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung            Rect r = new Rect();
3380a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung            mLauncher.getHotseat().getHitRect(r);
3381a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung            if (r.contains(x, y)) {
3382a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung                return false;
3383a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung            }
3384a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung        }
3385a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung
3386a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung        boolean result = false;
3387a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung        if (!isSmall() && !mIsSwitchingState) {
3388a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung            mInScrollArea = true;
3389a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung
3390a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung            final int page = (mNextPage != INVALID_PAGE ? mNextPage : mCurrentPage) +
3391a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung                       (direction == DragController.SCROLL_LEFT ? -1 : 1);
3392a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung            cancelFolderCreation();
3393a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung
3394a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung            if (0 <= page && page < getChildCount()) {
3395a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung                CellLayout layout = (CellLayout) getChildAt(page);
3396a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung                // Exit the current layout and mark the overlapping layout
3397a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung                if (mDragTargetLayout != null) {
3398a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung                    mDragTargetLayout.setIsDragOverlapping(false);
3399a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung                    mDragTargetLayout.onDragExit();
3400a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung                }
3401a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung                mDragTargetLayout = layout;
3402a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung                mDragTargetLayout.setIsDragOverlapping(true);
3403a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung
3404a6427b15c18d5b8f3078f553d78f8432de9f46e9Winson Chung                // Workspace is responsible for drawing the edge glow on adjacent pages,
340531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                // so we need to redraw the workspace when this may have changed.
3406                invalidate();
3407                result = true;
3408            }
3409        }
3410        return result;
3411    }
3412
3413    @Override
3414    public boolean onExitScrollArea() {
3415        boolean result = false;
3416        if (mInScrollArea) {
3417            if (mDragTargetLayout != null) {
3418                mDragTargetLayout.setIsDragOverlapping(false);
3419                // Workspace is responsible for drawing the edge glow on adjacent pages,
3420                // so we need to redraw the workspace when this may have changed.
3421                invalidate();
3422            }
3423            if (mDragTargetLayout != null && mDragHasEnteredWorkspace) {
3424                // Unmark the overlapping layout and re-enter the current layout
3425                mDragTargetLayout = getCurrentDropLayout();
3426                mDragTargetLayout.onDragEnter();
3427            }
3428            result = true;
3429            mInScrollArea = false;
3430        }
3431        return result;
3432    }
3433
3434    private void onResetScrollArea() {
3435        if (mDragTargetLayout != null) {
3436            // Unmark the overlapping layout
3437            mDragTargetLayout.setIsDragOverlapping(false);
3438
3439            // Workspace is responsible for drawing the edge glow on adjacent pages,
3440            // so we need to redraw the workspace when this may have changed.
3441            invalidate();
3442        }
3443        mInScrollArea = false;
3444    }
3445
3446    /**
3447     * Returns a specific CellLayout
3448     */
3449    CellLayout getParentCellLayoutForView(View v) {
3450        ArrayList<CellLayout> layouts = getWorkspaceAndHotseatCellLayouts();
3451        for (CellLayout layout : layouts) {
3452            if (layout.getShortcutsAndWidgets().indexOfChild(v) > -1) {
3453                return layout;
3454            }
3455        }
3456        return null;
3457    }
3458
3459    /**
3460     * Returns a list of all the CellLayouts in the workspace.
3461     */
3462    ArrayList<CellLayout> getWorkspaceAndHotseatCellLayouts() {
3463        ArrayList<CellLayout> layouts = new ArrayList<CellLayout>();
3464        int screenCount = getChildCount();
3465        for (int screen = 0; screen < screenCount; screen++) {
3466            layouts.add(((CellLayout) getChildAt(screen)));
3467        }
3468        if (mLauncher.getHotseat() != null) {
3469            layouts.add(mLauncher.getHotseat().getLayout());
3470        }
3471        return layouts;
3472    }
3473
3474    /**
3475     * We should only use this to search for specific children.  Do not use this method to modify
3476     * ShortcutsAndWidgetsContainer directly. Includes ShortcutAndWidgetContainers from
3477     * the hotseat and workspace pages
3478     */
3479    ArrayList<ShortcutAndWidgetContainer> getAllShortcutAndWidgetContainers() {
3480        ArrayList<ShortcutAndWidgetContainer> childrenLayouts =
3481                new ArrayList<ShortcutAndWidgetContainer>();
3482        int screenCount = getChildCount();
3483        for (int screen = 0; screen < screenCount; screen++) {
3484            childrenLayouts.add(((CellLayout) getChildAt(screen)).getShortcutsAndWidgets());
3485        }
3486        if (mLauncher.getHotseat() != null) {
3487            childrenLayouts.add(mLauncher.getHotseat().getLayout().getShortcutsAndWidgets());
3488        }
3489        return childrenLayouts;
3490    }
3491
3492    public Folder getFolderForTag(Object tag) {
3493        ArrayList<ShortcutAndWidgetContainer> childrenLayouts =
3494                getAllShortcutAndWidgetContainers();
3495        for (ShortcutAndWidgetContainer layout: childrenLayouts) {
3496            int count = layout.getChildCount();
3497            for (int i = 0; i < count; i++) {
3498                View child = layout.getChildAt(i);
3499                if (child instanceof Folder) {
3500                    Folder f = (Folder) child;
3501                    if (f.getInfo() == tag && f.getInfo().opened) {
3502                        return f;
3503                    }
3504                }
3505            }
3506        }
3507        return null;
3508    }
3509
3510    public View getViewForTag(Object tag) {
3511        ArrayList<ShortcutAndWidgetContainer> childrenLayouts =
3512                getAllShortcutAndWidgetContainers();
3513        for (ShortcutAndWidgetContainer layout: childrenLayouts) {
3514            int count = layout.getChildCount();
3515            for (int i = 0; i < count; i++) {
3516                View child = layout.getChildAt(i);
3517                if (child.getTag() == tag) {
3518                    return child;
3519                }
3520            }
3521        }
3522        return null;
3523    }
3524
3525    void clearDropTargets() {
3526        ArrayList<ShortcutAndWidgetContainer> childrenLayouts =
3527                getAllShortcutAndWidgetContainers();
3528        for (ShortcutAndWidgetContainer layout: childrenLayouts) {
3529            int childCount = layout.getChildCount();
3530            for (int j = 0; j < childCount; j++) {
3531                View v = layout.getChildAt(j);
3532                if (v instanceof DropTarget) {
3533                    mDragController.removeDropTarget((DropTarget) v);
3534                }
3535            }
3536        }
3537    }
3538
3539    void removeItems(final ArrayList<ApplicationInfo> apps) {
3540        final AppWidgetManager widgets = AppWidgetManager.getInstance(getContext());
3541
3542        final HashSet<String> packageNames = new HashSet<String>();
3543        final int appCount = apps.size();
3544        for (int i = 0; i < appCount; i++) {
3545            packageNames.add(apps.get(i).componentName.getPackageName());
3546        }
3547
3548        ArrayList<CellLayout> cellLayouts = getWorkspaceAndHotseatCellLayouts();
3549        for (final CellLayout layoutParent: cellLayouts) {
3550            final ViewGroup layout = layoutParent.getShortcutsAndWidgets();
3551
3552            // Avoid ANRs by treating each screen separately
3553            post(new Runnable() {
3554                public void run() {
3555                    final ArrayList<View> childrenToRemove = new ArrayList<View>();
3556                    childrenToRemove.clear();
3557
3558                    int childCount = layout.getChildCount();
3559                    for (int j = 0; j < childCount; j++) {
3560                        final View view = layout.getChildAt(j);
3561                        Object tag = view.getTag();
3562
3563                        if (tag instanceof ShortcutInfo) {
3564                            final ShortcutInfo info = (ShortcutInfo) tag;
3565                            final Intent intent = info.intent;
3566                            final ComponentName name = intent.getComponent();
3567
3568                            if (Intent.ACTION_MAIN.equals(intent.getAction()) && name != null) {
3569                                for (String packageName: packageNames) {
3570                                    if (packageName.equals(name.getPackageName())) {
3571                                        LauncherModel.deleteItemFromDatabase(mLauncher, info);
3572                                        childrenToRemove.add(view);
3573                                    }
3574                                }
3575                            }
3576                        } else if (tag instanceof FolderInfo) {
3577                            final FolderInfo info = (FolderInfo) tag;
3578                            final ArrayList<ShortcutInfo> contents = info.contents;
3579                            final int contentsCount = contents.size();
3580                            final ArrayList<ShortcutInfo> appsToRemoveFromFolder =
3581                                    new ArrayList<ShortcutInfo>();
3582
3583                            for (int k = 0; k < contentsCount; k++) {
3584                                final ShortcutInfo appInfo = contents.get(k);
3585                                final Intent intent = appInfo.intent;
3586                                final ComponentName name = intent.getComponent();
3587
3588                                if (Intent.ACTION_MAIN.equals(intent.getAction()) && name != null) {
3589                                    for (String packageName: packageNames) {
3590                                        if (packageName.equals(name.getPackageName())) {
3591                                            appsToRemoveFromFolder.add(appInfo);
3592                                        }
3593                                    }
3594                                }
3595                            }
3596                            for (ShortcutInfo item: appsToRemoveFromFolder) {
3597                                info.remove(item);
3598                                LauncherModel.deleteItemFromDatabase(mLauncher, item);
3599                            }
3600                        } else if (tag instanceof LauncherAppWidgetInfo) {
3601                            final LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) tag;
3602                            final AppWidgetProviderInfo provider =
3603                                    widgets.getAppWidgetInfo(info.appWidgetId);
3604                            if (provider != null) {
3605                                for (String packageName: packageNames) {
3606                                    if (packageName.equals(provider.provider.getPackageName())) {
3607                                        LauncherModel.deleteItemFromDatabase(mLauncher, info);
3608                                        childrenToRemove.add(view);
3609                                    }
3610                                }
3611                            }
3612                        }
3613                    }
3614
3615                    childCount = childrenToRemove.size();
3616                    for (int j = 0; j < childCount; j++) {
3617                        View child = childrenToRemove.get(j);
3618                        // Note: We can not remove the view directly from CellLayoutChildren as this
3619                        // does not re-mark the spaces as unoccupied.
3620                        layoutParent.removeViewInLayout(child);
3621                        if (child instanceof DropTarget) {
3622                            mDragController.removeDropTarget((DropTarget)child);
3623                        }
3624                    }
3625
3626                    if (childCount > 0) {
3627                        layout.requestLayout();
3628                        layout.invalidate();
3629                    }
3630                }
3631            });
3632        }
3633    }
3634
3635    void updateShortcuts(ArrayList<ApplicationInfo> apps) {
3636        ArrayList<ShortcutAndWidgetContainer> childrenLayouts = getAllShortcutAndWidgetContainers();
3637        for (ShortcutAndWidgetContainer layout: childrenLayouts) {
3638            int childCount = layout.getChildCount();
3639            for (int j = 0; j < childCount; j++) {
3640                final View view = layout.getChildAt(j);
3641                Object tag = view.getTag();
3642                if (tag instanceof ShortcutInfo) {
3643                    ShortcutInfo info = (ShortcutInfo) tag;
3644                    // We need to check for ACTION_MAIN otherwise getComponent() might
3645                    // return null for some shortcuts (for instance, for shortcuts to
3646                    // web pages.)
3647                    final Intent intent = info.intent;
3648                    final ComponentName name = intent.getComponent();
3649                    if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION &&
3650                            Intent.ACTION_MAIN.equals(intent.getAction()) && name != null) {
3651                        final int appCount = apps.size();
3652                        for (int k = 0; k < appCount; k++) {
3653                            ApplicationInfo app = apps.get(k);
3654                            if (app.componentName.equals(name)) {
3655                                BubbleTextView shortcut = (BubbleTextView) view;
3656                                info.updateIcon(mIconCache);
3657                                info.title = app.title.toString();
3658                                shortcut.applyFromShortcutInfo(info, mIconCache);
3659                            }
3660                        }
3661                    }
3662                }
3663            }
3664        }
3665    }
3666
3667    void moveToDefaultScreen(boolean animate) {
3668        if (!isSmall()) {
3669            if (animate) {
3670                snapToPage(mDefaultPage);
3671            } else {
3672                setCurrentPage(mDefaultPage);
3673            }
3674        }
3675        getChildAt(mDefaultPage).requestFocus();
3676    }
3677
3678    @Override
3679    public void syncPages() {
3680    }
3681
3682    @Override
3683    public void syncPageItems(int page, boolean immediate) {
3684    }
3685
3686    @Override
3687    protected String getCurrentPageDescription() {
3688        int page = (mNextPage != INVALID_PAGE) ? mNextPage : mCurrentPage;
3689        return String.format(mContext.getString(R.string.workspace_scroll_format),
3690                page + 1, getChildCount());
3691    }
3692
3693    public void getLocationInDragLayer(int[] loc) {
3694        mLauncher.getDragLayer().getLocationInDragLayer(this, loc);
3695    }
3696
3697    void setFadeForOverScroll(float fade) {
3698        if (!isScrollingIndicatorEnabled()) return;
3699
3700        mOverscrollFade = fade;
3701        float reducedFade = 0.5f + 0.5f * (1 - fade);
3702        final ViewGroup parent = (ViewGroup) getParent();
3703        final ImageView qsbDivider = (ImageView) (parent.findViewById(R.id.qsb_divider));
3704        final ImageView dockDivider = (ImageView) (parent.findViewById(R.id.dock_divider));
3705        final View scrollIndicator = getScrollingIndicator();
3706
3707        cancelScrollingIndicatorAnimations();
3708        if (qsbDivider != null) qsbDivider.setAlpha(reducedFade);
3709        if (dockDivider != null) dockDivider.setAlpha(reducedFade);
3710        scrollIndicator.setAlpha(1 - fade);
3711    }
3712}
3713