Workspace.java revision 265b9a66542148e0ff13971001cb9461065e1e0e
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 1968846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chungimport android.animation.Animator; 2068846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chungimport android.animation.Animator.AnimatorListener; 2168846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chungimport android.animation.AnimatorListenerAdapter; 22495f2892288504f4ab87e62957b3f71144dd73c2Adam Powellimport android.animation.AnimatorSet; 23580e27748137ff08599aa719d106b31215a28353Winson Chungimport android.animation.ObjectAnimator; 240280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurkaimport android.animation.TimeInterpolator; 2568846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chungimport android.animation.ValueAnimator; 26b1254a6bdb11024042fb6c27e179210c1bbd6e1cChet Haaseimport android.animation.ValueAnimator.AnimatorUpdateListener; 270280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurkaimport android.app.AlertDialog; 280280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurkaimport android.app.WallpaperManager; 29cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroyimport android.appwidget.AppWidgetHostView; 30cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroyimport android.appwidget.AppWidgetManager; 31cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroyimport android.appwidget.AppWidgetProviderInfo; 3268846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chungimport android.content.ClipData; 338f573952b8729b4319043ae0908997ecd2d68951Dianne Hackbornimport android.content.ClipDescription; 34629de3ef739883c0962423cc0c3a26299f162d3dRomain Guyimport android.content.ComponentName; 35629de3ef739883c0962423cc0c3a26299f162d3dRomain Guyimport android.content.Context; 36a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chungimport android.content.Intent; 37a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chungimport android.content.res.Resources; 38495f2892288504f4ab87e62957b3f71144dd73c2Adam Powellimport android.content.res.TypedArray; 3931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.graphics.Bitmap; 4031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.graphics.Camera; 41495f2892288504f4ab87e62957b3f71144dd73c2Adam Powellimport android.graphics.Canvas; 425c16f3ecd6b47bff3abbe40deb3d39c66a3b0012Romain Guyimport android.graphics.Matrix; 437247f6315baf16eacb3286f21bd80321385c1defPatrick Dubroyimport android.graphics.Paint; 4431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.graphics.Point; 454be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onoratoimport android.graphics.PorterDuff; 466b879f0a5885274a85333531e091283405d490ccAdam Lesinskiimport android.graphics.Rect; 4731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.graphics.RectF; 48a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurkaimport android.graphics.Region.Op; 49a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chungimport android.graphics.drawable.Drawable; 5031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.os.IBinder; 51a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chungimport android.os.Parcelable; 524be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onoratoimport android.util.AttributeSet; 53f96811cdf564469a7a654a0c876288c9fd14f35eThe Android Open Source Projectimport android.util.DisplayMetrics; 545c16f3ecd6b47bff3abbe40deb3d39c66a3b0012Romain Guyimport android.util.Log; 55956091ba7863bd72086275e61084864994dd6fa7Joe Onoratoimport android.util.Pair; 56495f2892288504f4ab87e62957b3f71144dd73c2Adam Powellimport android.view.Display; 5731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.DragEvent; 58291ad12232c98e383d44d76ffe09e97e204c61bcDaniel Sandlerimport android.view.MotionEvent; 59580e27748137ff08599aa719d106b31215a28353Winson Chungimport android.view.View; 60a34abf8c781485b788fddacb352d586bffca886cWinson Chungimport android.view.ViewConfiguration; 61a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chungimport android.view.ViewGroup; 6231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.animation.DecelerateInterpolator; 6331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.widget.ImageView; 64cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroyimport android.widget.TextView; 65f96811cdf564469a7a654a0c876288c9fd14f35eThe Android Open Source Projectimport android.widget.Toast; 66a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung 6731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport com.android.launcher.R; 6868846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chungimport com.android.launcher2.FolderIcon.FolderRingAnimator; 6968846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chungimport com.android.launcher2.InstallWidgetReceiver.WidgetMimeTypeHandlerData; 70edcce099c98a6c40d10109ac092ab50f9d2668f3Romain Guy 7131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport java.util.ArrayList; 720142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurkaimport java.util.HashSet; 730142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurkaimport java.util.List; 74aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 7531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project/** 760142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka * The workspace is a wide area with a wallpaper and a finite number of pages. 77dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka * Each page contains a number of icons, folders or widgets the user can 78e47f55c30b9c24f01f2be861247c92f17fbe4a61Romain Guy * interact with. A workspace is meant to be used with a fixed width only. 793a8820bdbad90642cf5cda4b00a8c92ecb699159Joe Onorato */ 800142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurkapublic class Workspace extends SmoothPagedView 81dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka implements DropTarget, DragSource, DragScroller, View.OnTouchListener, 82dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka DragController.DragListener { 83dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka @SuppressWarnings({"UnusedDeclaration"}) 84a985e598f6071f4caca15ba3cb6b2cd3e38b217dAdam Cohen private static final String TAG = "Launcher.Workspace"; 85f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen 86f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen // Y rotation to apply to the workspace screens 876b879f0a5885274a85333531e091283405d490ccAdam Lesinski private static final float WORKSPACE_ROTATION = 12.5f; 88a985e598f6071f4caca15ba3cb6b2cd3e38b217dAdam Cohen private static final float WORKSPACE_OVERSCROLL_ROTATION = 24f; 89a985e598f6071f4caca15ba3cb6b2cd3e38b217dAdam Cohen private static float CAMERA_DISTANCE = 6500; 90a985e598f6071f4caca15ba3cb6b2cd3e38b217dAdam Cohen 911b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen private static final int CHILDREN_OUTLINE_FADE_OUT_DELAY = 0; 92a985e598f6071f4caca15ba3cb6b2cd3e38b217dAdam Cohen private static final int CHILDREN_OUTLINE_FADE_OUT_DURATION = 375; 931b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen private static final int CHILDREN_OUTLINE_FADE_IN_DURATION = 100; 94a985e598f6071f4caca15ba3cb6b2cd3e38b217dAdam Cohen 959171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung private static final int BACKGROUND_FADE_OUT_DURATION = 350; 969171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung private static final int ADJACENT_SCREEN_DROP_DURATION = 300; 979171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung private static final int FLING_THRESHOLD_VELOCITY = 500; 98f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen 999171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung // These animators are used to fade the children's outlines 1009171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung private ObjectAnimator mChildrenOutlineFadeInAnimation; 1019171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung private ObjectAnimator mChildrenOutlineFadeOutAnimation; 1029171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung private float mChildrenOutlineAlpha = 0; 1039171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung 1049171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung // These properties refer to the background protection gradient used for AllApps and Customize 1059171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung private ValueAnimator mBackgroundFadeInAnimation; 1069171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung private ValueAnimator mBackgroundFadeOutAnimation; 1079171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung private Drawable mBackground; 108472b281d5cb4f5660df981a6c912266b9f5703feChet Haase boolean mDrawBackground = true; 109472b281d5cb4f5660df981a6c912266b9f5703feChet Haase private float mBackgroundAlpha = 0; 1109171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung private float mOverScrollMaxBackgroundAlpha = 0.0f; 111f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen private int mOverScrollPageIndex = -1; 112f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen 1138f573952b8729b4319043ae0908997ecd2d68951Dianne Hackborn private float mWallpaperScrollRatio = 1.0f; 114aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 1150142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka private final WallpaperManager mWallpaperManager; 11631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private IBinder mWindowToken; 11721f12b52a54d2658ed14fcf7bb1ca17a198f62beAdam Cohen private static final float WALLPAPER_SCREENS_SPAN = 2f; 11821f12b52a54d2658ed14fcf7bb1ca17a198f62beAdam Cohen 11931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private int mDefaultPage; 12031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 12131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 12231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * CellInfo for the cell that is currently being dragged 123aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung */ 12470864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey private CellLayout.CellInfo mDragInfo; 12570864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey 12670864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey /** 12770864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * Target drop area calculated during last acceptDrop call. 12831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 1296569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy private int[] mTargetCell = new int[2]; 1306569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 1316569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy /** 1326569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy * The CellLayout that is currently being dragged over 1336569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy */ 13431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private CellLayout mDragTargetLayout = null; 1350589f0f66ce498512c6ee47482c649d88294c9d0Joe Onorato 13600acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato private Launcher mLauncher; 137aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung private IconCache mIconCache; 1384516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka private DragController mDragController; 1394516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka 14031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // These are temporary variables to prevent having to allocate a new object just to 14170864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey // return an (x, y) value from helper functions. Do NOT use them to maintain other state. 1420280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka private int[] mTempCell = new int[2]; 143a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka private int[] mTempEstimate = new int[2]; 1444516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka private float[] mDragViewVisualCenter = new float[2]; 1454516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka private float[] mTempDragCoordinates = new float[2]; 146a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka private float[] mTempCellLayoutCenterCoordinates = new float[2]; 1470280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka private float[] mTempDragBottomRightCoordinates = new float[2]; 14831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private Matrix mTempInverseMatrix = new Matrix(); 149d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen 150d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen private SpringLoadedDragController mSpringLoadedDragController; 15131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private float mSpringLoadedShrinkFactor; 1528a73c51ee87b6d9b12daba188034889caf7a905bRomain Guy 1538a73c51ee87b6d9b12daba188034889caf7a905bRomain Guy private static final int DEFAULT_CELL_COUNT_X = 4; 154aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung private static final int DEFAULT_CELL_COUNT_Y = 4; 1551262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy 156dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka // State variable that indicates whether the pages are small (ie when you're 157c0e8fcae492730210b2b8b6d5bb3d65636bad245Michael Jurka // in all apps or customize mode) 158c0e8fcae492730210b2b8b6d5bb3d65636bad245Michael Jurka 159b1254a6bdb11024042fb6c27e179210c1bbd6e1cChet Haase enum State { NORMAL, SPRING_LOADED, SMALL }; 1603e7c7634531302271270c8cf418abc959d621cbcMichael Jurka private State mState = State.NORMAL; 1613e7c7634531302271270c8cf418abc959d621cbcMichael Jurka private boolean mIsSwitchingState = false; 1623e7c7634531302271270c8cf418abc959d621cbcMichael Jurka private boolean mSwitchStateAfterFirstLayout = false; 163883f55b1d261862b0de1b43af0b17d351761a9c6Michael Jurka private State mStateAfterFirstLayout; 164883f55b1d261862b0de1b43af0b17d351761a9c6Michael Jurka 1653c4c20fbe682cb4b3ef94f09afe0af09171583f3Michael Jurka private AnimatorSet mAnimator; 166dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka private AnimatorListener mChangeStateAnimationListener; 16754fa3b95557c283976e8c1aa8a157b460b0b4513Patrick Dubroy 1681262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy boolean mAnimatingViewIntoPlace = false; 1691262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy boolean mIsDragOccuring = false; 17054fa3b95557c283976e8c1aa8a157b460b0b4513Patrick Dubroy boolean mChildrenLayersEnabled = true; 17154fa3b95557c283976e8c1aa8a157b460b0b4513Patrick Dubroy 17254fa3b95557c283976e8c1aa8a157b460b0b4513Patrick Dubroy /** Is the user is dragging an item near the edge of a page? */ 17354fa3b95557c283976e8c1aa8a157b460b0b4513Patrick Dubroy private boolean mInScrollArea = false; 17454fa3b95557c283976e8c1aa8a157b460b0b4513Patrick Dubroy 1758e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy private final HolographicOutlineHelper mOutlineHelper = new HolographicOutlineHelper(); 1764be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato private Bitmap mDragOutline = null; 1778e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy private final Rect mTempRect = new Rect(); 1788e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy private final int[] mTempXY = new int[2]; 1794be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato private int mDragViewMultiplyColor; 180cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy private float mOverscrollFade = 0; 181cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy 182cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy // Paint used to draw external drop outline 183cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy private final Paint mExternalDragOutlinePaint = new Paint(); 184cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy 185a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung // Camera and Matrix used to determine the final position of a neighboring CellLayout 186a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung private final Matrix mMatrix = new Matrix(); 187a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung private final Camera mCamera = new Camera(); 1888ae3a62e2e48dfb8f860c8b6e2c7e72b9595d7aaPatrick Dubroy private final float mTempFloat2[] = new float[2]; 1898ae3a62e2e48dfb8f860c8b6e2c7e72b9595d7aaPatrick Dubroy 1908ae3a62e2e48dfb8f860c8b6e2c7e72b9595d7aaPatrick Dubroy enum WallpaperVerticalOffset { TOP, MIDDLE, BOTTOM }; 1916b879f0a5885274a85333531e091283405d490ccAdam Lesinski int mWallpaperWidth; 1926b879f0a5885274a85333531e091283405d490ccAdam Lesinski int mWallpaperHeight; 1936b879f0a5885274a85333531e091283405d490ccAdam Lesinski WallpaperOffsetInterpolator mWallpaperOffset; 1946b879f0a5885274a85333531e091283405d490ccAdam Lesinski boolean mUpdateWallpaperOffsetImmediately = false; 1956b879f0a5885274a85333531e091283405d490ccAdam Lesinski private Runnable mDelayedResizeRunnable; 19631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private int mDisplayWidth; 19731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private int mDisplayHeight; 19831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private int mWallpaperTravelWidth; 19931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 2000142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka // Variables relating to the creation of user folders by hovering shortcuts over shortcuts 20131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private static final int FOLDER_CREATION_TIMEOUT = 250; 20231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private final Alarm mFolderCreationAlarm = new Alarm(); 20331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private FolderRingAnimator mDragFolderRingAnimator = null; 20431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private View mLastDragOverView = null; 20531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private boolean mCreateUserFolderOnDrop = false; 20631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 20731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // Variables relating to touch disambiguation (scrolling workspace vs. scrolling a widget) 20831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private float mXDown; 20931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private float mYDown; 2100142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka final static float START_DAMPING_TOUCH_SLOP_ANGLE = (float) Math.PI / 6; 21131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final static float MAX_SWIPE_ANGLE = (float) Math.PI / 3; 21231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final static float TOUCH_SLOP_DAMPING_FACTOR = 4; 21331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 21431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // These variables are used for storing the initial and final values during workspace animations 2150142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka private int mSavedScrollX; 2165f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka private float mSavedRotationY; 2175f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka private float mSavedTranslationX; 2185f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka private float mCurrentScaleX; 2195f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka private float mCurrentScaleY; 22031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private float mCurrentRotationY; 2218f573952b8729b4319043ae0908997ecd2d68951Dianne Hackborn private float mCurrentTranslationX; 222aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung private float mCurrentTranslationY; 223aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung private float[] mOldTranslationXs; 224aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung private float[] mOldTranslationYs; 225d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen private float[] mOldScaleXs; 226d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen private float[] mOldScaleYs; 2270142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka private float[] mOldBackgroundAlphas; 22831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private float[] mOldBackgroundAlphaMultipliers; 22931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private float[] mOldAlphas; 230d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen private float[] mOldRotationYs; 2310d44e9482b95d8f163b28bf20131c4349185b589Joe Onorato private float[] mNewTranslationXs; 2320142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka private float[] mNewTranslationYs; 23331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private float[] mNewScaleXs; 23431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private float[] mNewScaleYs; 23531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private float[] mNewBackgroundAlphas; 23631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private float[] mNewBackgroundAlphaMultipliers; 23731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private float[] mNewAlphas; 23831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private float[] mNewRotationYs; 2390142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka private float mTransitionProgress; 2400589f0f66ce498512c6ee47482c649d88294c9d0Joe Onorato 2410142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka /** 2420142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka * Used to inflate the Workspace from XML. 2430589f0f66ce498512c6ee47482c649d88294c9d0Joe Onorato * 2440589f0f66ce498512c6ee47482c649d88294c9d0Joe Onorato * @param context The application's context. 245a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung * @param attrs The attributes set containing the Workspace's customization values. 246cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy */ 24731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public Workspace(Context context, AttributeSet attrs) { 2489171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung this(context, attrs, 0); 2499171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung } 2509171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung 2513c4c20fbe682cb4b3ef94f09afe0af09171583f3Michael Jurka /** 2523c4c20fbe682cb4b3ef94f09afe0af09171583f3Michael Jurka * Used to inflate the Workspace from XML. 253c0e8fcae492730210b2b8b6d5bb3d65636bad245Michael Jurka * 254c0e8fcae492730210b2b8b6d5bb3d65636bad245Michael Jurka * @param context The application's context. 255c0e8fcae492730210b2b8b6d5bb3d65636bad245Michael Jurka * @param attrs The attributes set containing the Workspace's customization values. 2563c4c20fbe682cb4b3ef94f09afe0af09171583f3Michael Jurka * @param defStyle Unused. 2573c4c20fbe682cb4b3ef94f09afe0af09171583f3Michael Jurka */ 258c0e8fcae492730210b2b8b6d5bb3d65636bad245Michael Jurka public Workspace(Context context, AttributeSet attrs, int defStyle) { 259dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka super(context, attrs, defStyle); 260dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka mContentIsRefreshable = false; 2610142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 26231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // With workspace, data is available straight from the get-go 26331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project setDataIsReady(); 26431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 265f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen mFadeInAdjacentScreens = 266f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen getResources().getBoolean(R.bool.config_workspaceFadeAdjacentScreens); 267f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen mWallpaperManager = WallpaperManager.getInstance(context); 268f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen 269f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen int cellCountX = DEFAULT_CELL_COUNT_X; 270f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen int cellCountY = DEFAULT_CELL_COUNT_Y; 271f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen 272f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen TypedArray a = context.obtainStyledAttributes(attrs, 273f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen R.styleable.Workspace, defStyle, 0); 27431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 27531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final Resources res = context.getResources(); 27631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (LauncherApplication.isScreenLarge()) { 27731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // Determine number of rows/columns dynamically 27821f12b52a54d2658ed14fcf7bb1ca17a198f62beAdam Cohen // TODO: This code currently fails on tablets with an aspect ratio < 1.3. 27931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // Around that ratio we should make cells the same size in portrait and 28031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // landscape 28131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project TypedArray actionBarSizeTypedArray = 28231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project context.obtainStyledAttributes(new int[] { android.R.attr.actionBarSize }); 28331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final float actionBarHeight = actionBarSizeTypedArray.getDimension(0, 0f); 28431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final float systemBarHeight = res.getDimension(R.dimen.status_bar_height); 28531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final float smallestScreenDim = res.getConfiguration().smallestScreenWidthDp; 28631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 28721f12b52a54d2658ed14fcf7bb1ca17a198f62beAdam Cohen cellCountX = 1; 28831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project while (CellLayout.widthInPortrait(res, cellCountX + 1) <= smallestScreenDim) { 28931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellCountX++; 29031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 29131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 29231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellCountY = 1; 29331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project while (actionBarHeight + CellLayout.heightInLandscape(res, cellCountY + 1) 29431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project <= smallestScreenDim - systemBarHeight) { 29531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellCountY++; 29621f12b52a54d2658ed14fcf7bb1ca17a198f62beAdam Cohen } 29731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 29831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 29931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mSpringLoadedShrinkFactor = 30031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project res.getInteger(R.integer.config_workspaceSpringLoadShrinkPercentage) / 100.0f; 30131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mDragViewMultiplyColor = res.getColor(R.color.drag_view_multiply_color); 30231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 30331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // if the value is manually specified, use that instead 30431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellCountX = a.getInt(R.styleable.Workspace_cellCountX, cellCountX); 30521f12b52a54d2658ed14fcf7bb1ca17a198f62beAdam Cohen cellCountY = a.getInt(R.styleable.Workspace_cellCountY, cellCountY); 30631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mDefaultPage = a.getInt(R.styleable.Workspace_defaultScreen, 1); 30731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project a.recycle(); 30831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 30931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project LauncherModel.updateWorkspaceLayoutCells(cellCountX, cellCountY); 31031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project setHapticFeedbackEnabled(false); 31131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 31231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mLauncher = (Launcher) context; 31331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project initWorkspace(); 31421f12b52a54d2658ed14fcf7bb1ca17a198f62beAdam Cohen 31531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // Disable multitouch across the workspace/all apps/customize tray 31631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project setMotionEventSplittingEnabled(true); 31731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 31831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 31931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // estimate the size of a widget with spans hSpan, vSpan. return MAX_VALUE for each 32031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // dimension if unsuccessful 32131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public int[] estimateItemSize(int hSpan, int vSpan, 3220142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka PendingAddItemInfo pendingItemInfo, boolean springLoaded) { 3230142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka int[] size = new int[2]; 32431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (getChildCount() > 0) { 3250142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka CellLayout cl = (CellLayout) mLauncher.getWorkspace().getChildAt(0); 326aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung RectF r = estimateItemPosition(cl, pendingItemInfo, 0, 0, hSpan, vSpan); 327aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung size[0] = (int) r.width(); 328aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung size[1] = (int) r.height(); 329aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung if (springLoaded) { 33031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project size[0] *= mSpringLoadedShrinkFactor; 33131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project size[1] *= mSpringLoadedShrinkFactor; 33231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 33331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return size; 33431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } else { 33531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project size[0] = Integer.MAX_VALUE; 336dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka size[1] = Integer.MAX_VALUE; 337dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka return size; 33831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 339dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } 3400142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka public RectF estimateItemPosition(CellLayout cl, ItemInfo pendingInfo, 3410142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka int hCell, int vCell, int hSpan, int vSpan) { 34231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project RectF r = new RectF(); 3430142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka cl.cellToRect(hCell, vCell, hSpan, vSpan, r); 344aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung if (pendingInfo instanceof PendingAddWidgetInfo) { 345aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung PendingAddWidgetInfo widgetInfo = (PendingAddWidgetInfo) pendingInfo; 346aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung Rect p = AppWidgetHostView.getDefaultPaddingForWidget(mContext, 347aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung widgetInfo.componentName, null); 34831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project r.top += p.top; 34931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project r.left += p.left; 35031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project r.right -= p.right; 35131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project r.bottom -= p.bottom; 35231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 35331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return r; 35431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 3550142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 3560142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka public void buildPageHardwareLayers() { 35731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (getWindowToken() != null) { 35831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int childCount = getChildCount(); 35931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int i = 0; i < childCount; i++) { 36031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project CellLayout cl = (CellLayout) getChildAt(i); 36131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cl.buildChildrenLayer(); 3620142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 36331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 3640142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 3650142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 3660142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka public void onDragStart(DragSource source, Object info, int dragAction) { 3670142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka mIsDragOccuring = true; 36831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project updateChildrenLayersEnabled(); 36931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mLauncher.lockScreenOrientationOnLargeUI(); 37031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 37131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 37231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public void onDragEnd() { 37331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mIsDragOccuring = false; 37431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project updateChildrenLayersEnabled(); 37531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mLauncher.unlockScreenOrientationOnLargeUI(); 37631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 37731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 37831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 37931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Initializes various states for this workspace. 38031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 38131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected void initWorkspace() { 38231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project Context context = getContext(); 38331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mCurrentPage = mDefaultPage; 38431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project Launcher.setScreen(mCurrentPage); 385aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung LauncherApplication app = (LauncherApplication)context.getApplicationContext(); 386aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung mIconCache = app.getIconCache(); 387aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung mExternalDragOutlinePaint.setAntiAlias(true); 388aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung setWillNotDraw(false); 38931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project setChildrenDrawnWithCacheEnabled(true); 39031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 39131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project try { 39231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final Resources res = getResources(); 39331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mBackground = res.getDrawable(R.drawable.apps_customize_bg); 39431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } catch (Resources.NotFoundException e) { 39531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // In this case, we will skip drawing background protection 39631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 39731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 39831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mChangeStateAnimationListener = new AnimatorListenerAdapter() { 39931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 40031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public void onAnimationStart(Animator animation) { 40131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mIsSwitchingState = true; 40231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 403291ad12232c98e383d44d76ffe09e97e204c61bcDaniel Sandler 404291ad12232c98e383d44d76ffe09e97e204c61bcDaniel Sandler @Override 405291ad12232c98e383d44d76ffe09e97e204c61bcDaniel Sandler public void onAnimationEnd(Animator animation) { 40631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mIsSwitchingState = false; 40731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mWallpaperOffset.setOverrideHorizontalCatchupConstant(false); 40831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mAnimator = null; 40931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project updateChildrenLayersEnabled(); 41031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 41131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project }; 41231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 41331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mWallpaperOffset = new WallpaperOffsetInterpolator(); 41431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project Display display = mLauncher.getWindowManager().getDefaultDisplay(); 41531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mDisplayWidth = display.getWidth(); 41631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mDisplayHeight = display.getHeight(); 41731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mWallpaperTravelWidth = (int) (mDisplayWidth * 418aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung wallpaperTravelToScreenWidthRatio(mDisplayWidth, mDisplayHeight)); 4196569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 420845ba3b17b83a2b11d79c6fb076cf96ab4a737dfMichael Jurka mFlingThresholdVelocity = (int) (FLING_THRESHOLD_VELOCITY * mDensity); 421f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka 422f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka } 423aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 424aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung @Override 4256569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy protected int getScrollMode() { 426aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung return SmoothPagedView.X_LARGE_MODE; 427aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung } 428aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 42931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 4300d44e9482b95d8f163b28bf20131c4349185b589Joe Onorato protected void onViewAdded(View child) { 43131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project super.onViewAdded(child); 43231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (!(child instanceof CellLayout)) { 43300acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato throw new IllegalArgumentException("A Workspace can only have CellLayout children."); 434aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung } 43500acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato CellLayout cl = ((CellLayout) child); 43631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cl.setOnInterceptTouchListener(this); 43731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cl.setClickable(true); 438dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka cl.enableHardwareLayers(); 439dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } 440c0e8fcae492730210b2b8b6d5bb3d65636bad245Michael Jurka 4416b879f0a5885274a85333531e091283405d490ccAdam Lesinski /** 4426b879f0a5885274a85333531e091283405d490ccAdam Lesinski * @return The open folder on the current screen, or null if there is none 4436b879f0a5885274a85333531e091283405d490ccAdam Lesinski */ 4446b879f0a5885274a85333531e091283405d490ccAdam Lesinski Folder getOpenFolder() { 44596226223d9849842bb2a67af051acbae9e0677d5Michael Jurka DragLayer dragLayer = mLauncher.getDragLayer(); 44621f12b52a54d2658ed14fcf7bb1ca17a198f62beAdam Cohen int count = dragLayer.getChildCount(); 44721f12b52a54d2658ed14fcf7bb1ca17a198f62beAdam Cohen for (int i = 0; i < count; i++) { 44821f12b52a54d2658ed14fcf7bb1ca17a198f62beAdam Cohen View child = dragLayer.getChildAt(i); 44921f12b52a54d2658ed14fcf7bb1ca17a198f62beAdam Cohen if (child instanceof Folder) { 45021f12b52a54d2658ed14fcf7bb1ca17a198f62beAdam Cohen Folder folder = (Folder) child; 45121f12b52a54d2658ed14fcf7bb1ca17a198f62beAdam Cohen if (folder.getInfo().opened) 45221f12b52a54d2658ed14fcf7bb1ca17a198f62beAdam Cohen return folder; 45321f12b52a54d2658ed14fcf7bb1ca17a198f62beAdam Cohen } 454dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } 455dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka return null; 4560e26059548e429e5d1c973bebe4c561bead2926fMichael Jurka } 4570e26059548e429e5d1c973bebe4c561bead2926fMichael Jurka 458ded9f8d8658d0b6601006c0a954cd3bf530e55c1Adam Cohen boolean isTouchActive() { 459ded9f8d8658d0b6601006c0a954cd3bf530e55c1Adam Cohen return mTouchState != TOUCH_STATE_REST; 460ded9f8d8658d0b6601006c0a954cd3bf530e55c1Adam Cohen } 461ded9f8d8658d0b6601006c0a954cd3bf530e55c1Adam Cohen 4625f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka /** 4635f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka * Adds the specified child in the specified screen. The position and dimension of 464c0e8fcae492730210b2b8b6d5bb3d65636bad245Michael Jurka * the child are defined by x, y, spanX and spanY. 4655f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka * 4665f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka * @param child The child to add in one of the workspace's screens. 4675f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka * @param screen The screen in which to add the child. 4685f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka * @param x The X position of the child in the screen's grid. 4695f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka * @param y The Y position of the child in the screen's grid. 4705f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka * @param spanX The number of cells spanned horizontally by the child. 4715f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka * @param spanY The number of cells spanned vertically by the child. 4725f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka */ 473c0e8fcae492730210b2b8b6d5bb3d65636bad245Michael Jurka void addInScreen(View child, long container, int screen, int x, int y, int spanX, int spanY) { 4746b879f0a5885274a85333531e091283405d490ccAdam Lesinski addInScreen(child, container, screen, x, y, spanX, spanY, false); 4756b879f0a5885274a85333531e091283405d490ccAdam Lesinski } 4766b879f0a5885274a85333531e091283405d490ccAdam Lesinski 4776b879f0a5885274a85333531e091283405d490ccAdam Lesinski /** 4786b879f0a5885274a85333531e091283405d490ccAdam Lesinski * Adds the specified child in the specified screen. The position and dimension of 4796b879f0a5885274a85333531e091283405d490ccAdam Lesinski * the child are defined by x, y, spanX and spanY. 4805f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka * 4815f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka * @param child The child to add in one of the workspace's screens. 4825f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka * @param screen The screen in which to add the child. 4835f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka * @param x The X position of the child in the screen's grid. 4845f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka * @param y The Y position of the child in the screen's grid. 4851adf5391a3a3d215b226adf3702019c22a99e3b1Michael Jurka * @param spanX The number of cells spanned horizontally by the child. 4861adf5391a3a3d215b226adf3702019c22a99e3b1Michael Jurka * @param spanY The number of cells spanned vertically by the child. 4871adf5391a3a3d215b226adf3702019c22a99e3b1Michael Jurka * @param insert When true, the child is inserted at the beginning of the children list. 4881adf5391a3a3d215b226adf3702019c22a99e3b1Michael Jurka */ 4891adf5391a3a3d215b226adf3702019c22a99e3b1Michael Jurka void addInScreen(View child, long container, int screen, int x, int y, int spanX, int spanY, 4901262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy boolean insert) { 4910142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka if (container == LauncherSettings.Favorites.CONTAINER_DESKTOP) { 4920142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka if (screen < 0 || screen >= getChildCount()) { 49316fed41e5e680c547b23e108788eb85f1b04d36dMichael Jurka Log.e(TAG, "The screen must be >= 0 and < " + getChildCount() 4940142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka + " (was " + screen + "); skipping child"); 4950142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka return; 4960142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 49716fed41e5e680c547b23e108788eb85f1b04d36dMichael Jurka } 49831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 499f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen final CellLayout layout; 50021f12b52a54d2658ed14fcf7bb1ca17a198f62beAdam Cohen if (container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) { 50131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project layout = mLauncher.getHotseat().getLayout(); 50231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project child.setOnKeyListener(null); 5031262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy 50416fed41e5e680c547b23e108788eb85f1b04d36dMichael Jurka // Hide folder title in the hotseat 5051262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy if (child instanceof FolderIcon) { 5061262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy ((FolderIcon) child).setTextVisible(false); 5071262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy } 5081262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy 5098ae3a62e2e48dfb8f860c8b6e2c7e72b9595d7aaPatrick Dubroy if (screen < 0) { 5108ae3a62e2e48dfb8f860c8b6e2c7e72b9595d7aaPatrick Dubroy screen = mLauncher.getHotseat().getOrderInHotseat(x, y); 5118ae3a62e2e48dfb8f860c8b6e2c7e72b9595d7aaPatrick Dubroy } else { 5128ae3a62e2e48dfb8f860c8b6e2c7e72b9595d7aaPatrick Dubroy // Note: We do this to ensure that the hotseat is always laid out in the orientation 5138ae3a62e2e48dfb8f860c8b6e2c7e72b9595d7aaPatrick Dubroy // of the hotseat in order regardless of which orientation they were added 5148ae3a62e2e48dfb8f860c8b6e2c7e72b9595d7aaPatrick Dubroy x = mLauncher.getHotseat().getCellXFromOrder(screen); 51521f12b52a54d2658ed14fcf7bb1ca17a198f62beAdam Cohen y = mLauncher.getHotseat().getCellYFromOrder(screen); 5160142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 5170142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } else { 5180142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka // Show folder title if not in the hotseat 5190142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka if (child instanceof FolderIcon) { 5200142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka ((FolderIcon) child).setTextVisible(true); 5210142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 5220142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 5230142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka layout = (CellLayout) getChildAt(screen); 5240142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka child.setOnKeyListener(new IconKeyEventListener()); 5250142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 5260142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 5270142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams(); 5280142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka if (lp == null) { 5290142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka lp = new CellLayout.LayoutParams(x, y, spanX, spanY); 5300142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } else { 5310142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka lp.cellX = x; 5320142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka lp.cellY = y; 5330142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka lp.cellHSpan = spanX; 5340142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka lp.cellVSpan = spanY; 5358f573952b8729b4319043ae0908997ecd2d68951Dianne Hackborn } 536798300c4c05b12228f2e4f31c49c3cb728a37889Romain Guy 537798300c4c05b12228f2e4f31c49c3cb728a37889Romain Guy if (spanX < 0 && spanY < 0) { 538798300c4c05b12228f2e4f31c49c3cb728a37889Romain Guy lp.isLockedToGrid = false; 539798300c4c05b12228f2e4f31c49c3cb728a37889Romain Guy } 54086f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung 54186f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung // Get the canonical child id to uniquely represent this view in this screen 54286f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung int childId = LauncherModel.getCellLayoutChildId(container, screen, x, y, spanX, spanY); 54386f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung boolean markCellsAsOccupied = !(child instanceof Folder); 54486f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung if (!layout.addViewToCellLayout(child, insert ? 0 : -1, childId, lp, markCellsAsOccupied)) { 54586f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung // TODO: This branch occurs when the workspace is adding views 54686f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung // outside of the defined grid 54786f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung // maybe we should be deleting these items from the LauncherModel? 54886f7753bbd6d87ce85195b0715e5548edbfdb7d1Winson Chung Log.w(TAG, "Failed to add to item at (" + lp.cellX + "," + lp.cellY + ") to CellLayout"); 549956091ba7863bd72086275e61084864994dd6fa7Joe Onorato } 5508f573952b8729b4319043ae0908997ecd2d68951Dianne Hackborn 551aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung if (!(child instanceof Folder)) { 552f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen child.setHapticFeedbackEnabled(false); 5533e7c7634531302271270c8cf418abc959d621cbcMichael Jurka child.setOnLongClickListener(mLongClickListener); 5549171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung } 5559171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung if (child instanceof DropTarget) { 5569171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung mDragController.addDropTarget((DropTarget) child); 5579171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung } 5589171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung } 5593e7c7634531302271270c8cf418abc959d621cbcMichael Jurka 560f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen /** 561f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen * Check if the point (x, y) hits a given page. 562f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen */ 5633e7c7634531302271270c8cf418abc959d621cbcMichael Jurka private boolean hitsPage(int index, float x, float y) { 5649171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung final View page = getChildAt(index); 5659171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung if (page != null) { 5669171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung float[] localXY = { x, y }; 5679171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung mapPointFromSelfToChild(page, localXY); 5689171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung return (localXY[0] >= 0 && localXY[0] < page.getWidth() 5699171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung && localXY[1] >= 0 && localXY[1] < page.getHeight()); 5703e7c7634531302271270c8cf418abc959d621cbcMichael Jurka } 571f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen return false; 572f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen } 5739171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung 5749171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung @Override 575f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen protected boolean hitsPreviousPage(float x, float y) { 576f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen // mNextPage is set to INVALID_PAGE whenever we are stationary. 577f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen // Calculating "next page" this way ensures that you scroll to whatever page you tap on 578f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen final int current = (mNextPage == INVALID_PAGE) ? mCurrentPage : mNextPage; 579f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen 580f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen // Only allow tap to next page on large devices, where there's significant margin outside 5819171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung // the active workspace 5829171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung return LauncherApplication.isScreenLarge() && hitsPage(current - 1, x, y); 5839171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung } 5849171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung 5859171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung @Override 5869171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung protected boolean hitsNextPage(float x, float y) { 5879171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung // mNextPage is set to INVALID_PAGE whenever we are stationary. 5889171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung // Calculating "next page" this way ensures that you scroll to whatever page you tap on 5899171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung final int current = (mNextPage == INVALID_PAGE) ? mCurrentPage : mNextPage; 5909171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung 5919171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung // Only allow tap to next page on large devices, where there's significant margin outside 5929171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung // the active workspace 5939171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung return LauncherApplication.isScreenLarge() && hitsPage(current + 1, x, y); 5949171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung } 5959171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung 5969171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung /** 5979171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung * Called directly from a CellLayout (not by the framework), after we've been added as a 5989171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung * listener via setOnInterceptTouchEventListener(). This allows us to tell the CellLayout 5999171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung * that it should intercept touch events, which is not something that is normally supported. 6009171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung */ 6019171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung @Override 6029171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung public boolean onTouch(View v, MotionEvent event) { 6039171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung return (isSmall() || mIsSwitchingState); 6049171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung } 6059171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung 606f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen public boolean isSwitchingState() { 607f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen return mIsSwitchingState; 608f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen } 609f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen 6106b879f0a5885274a85333531e091283405d490ccAdam Lesinski protected void onWindowVisibilityChanged (int visibility) { 6116b879f0a5885274a85333531e091283405d490ccAdam Lesinski mLauncher.onWindowVisibilityChanged(visibility); 6126b879f0a5885274a85333531e091283405d490ccAdam Lesinski } 6136b879f0a5885274a85333531e091283405d490ccAdam Lesinski 6146b879f0a5885274a85333531e091283405d490ccAdam Lesinski @Override 6156b879f0a5885274a85333531e091283405d490ccAdam Lesinski public boolean dispatchUnhandledMove(View focused, int direction) { 6166b879f0a5885274a85333531e091283405d490ccAdam Lesinski if (isSmall() || mIsSwitchingState) { 6176b879f0a5885274a85333531e091283405d490ccAdam Lesinski // when the home screens are shrunken, shouldn't allow side-scrolling 6186b879f0a5885274a85333531e091283405d490ccAdam Lesinski return false; 6196b879f0a5885274a85333531e091283405d490ccAdam Lesinski } 6206b879f0a5885274a85333531e091283405d490ccAdam Lesinski return super.dispatchUnhandledMove(focused, direction); 6216b879f0a5885274a85333531e091283405d490ccAdam Lesinski } 6226b879f0a5885274a85333531e091283405d490ccAdam Lesinski 6236b879f0a5885274a85333531e091283405d490ccAdam Lesinski @Override 6246b879f0a5885274a85333531e091283405d490ccAdam Lesinski public boolean onInterceptTouchEvent(MotionEvent ev) { 6256b879f0a5885274a85333531e091283405d490ccAdam Lesinski switch (ev.getAction() & MotionEvent.ACTION_MASK) { 6266b879f0a5885274a85333531e091283405d490ccAdam Lesinski case MotionEvent.ACTION_DOWN: 6276b879f0a5885274a85333531e091283405d490ccAdam Lesinski mXDown = ev.getX(); 6286b879f0a5885274a85333531e091283405d490ccAdam Lesinski mYDown = ev.getY(); 6296b879f0a5885274a85333531e091283405d490ccAdam Lesinski break; 6306b879f0a5885274a85333531e091283405d490ccAdam Lesinski case MotionEvent.ACTION_POINTER_UP: 6316b879f0a5885274a85333531e091283405d490ccAdam Lesinski case MotionEvent.ACTION_UP: 6326b879f0a5885274a85333531e091283405d490ccAdam Lesinski if (mTouchState == TOUCH_STATE_REST) { 6336b879f0a5885274a85333531e091283405d490ccAdam Lesinski final CellLayout currentPage = (CellLayout) getChildAt(mCurrentPage); 6346b879f0a5885274a85333531e091283405d490ccAdam Lesinski if (!currentPage.lastDownOnOccupiedCell()) { 635f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen onWallpaperTap(ev); 636f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen } 63721f12b52a54d2658ed14fcf7bb1ca17a198f62beAdam Cohen } 63821f12b52a54d2658ed14fcf7bb1ca17a198f62beAdam Cohen } 6391b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen return super.onInterceptTouchEvent(ev); 6401b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen } 6411b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen 64221f12b52a54d2658ed14fcf7bb1ca17a198f62beAdam Cohen @Override 64321f12b52a54d2658ed14fcf7bb1ca17a198f62beAdam Cohen protected void determineScrollingStart(MotionEvent ev) { 644f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen if (!isSmall() && !mIsSwitchingState) { 645ddb821981e0919bbd3b4c9a2b6aa1811d6c86bb6Adam Cohen float deltaX = Math.abs(ev.getX() - mXDown); 64621f12b52a54d2658ed14fcf7bb1ca17a198f62beAdam Cohen float deltaY = Math.abs(ev.getY() - mYDown); 64721f12b52a54d2658ed14fcf7bb1ca17a198f62beAdam Cohen 648f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen if (Float.compare(deltaX, 0f) == 0) return; 649ddb821981e0919bbd3b4c9a2b6aa1811d6c86bb6Adam Cohen 6501b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen float slope = deltaY / deltaX; 65121f12b52a54d2658ed14fcf7bb1ca17a198f62beAdam Cohen float theta = (float) Math.atan(slope); 6526b879f0a5885274a85333531e091283405d490ccAdam Lesinski 6536b879f0a5885274a85333531e091283405d490ccAdam Lesinski if (deltaX > mTouchSlop || deltaY > mTouchSlop) { 6541b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen cancelCurrentPageLongPress(); 655f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen } 656f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen 657f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen if (theta > MAX_SWIPE_ANGLE) { 658f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen // Above MAX_SWIPE_ANGLE, we don't want to ever start scrolling the workspace 65900acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato return; 66000acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato } else if (theta > START_DAMPING_TOUCH_SLOP_ANGLE) { 661956091ba7863bd72086275e61084864994dd6fa7Joe Onorato // Above START_DAMPING_TOUCH_SLOP_ANGLE and below MAX_SWIPE_ANGLE, we want to 66200acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato // increase the touch slop to make it harder to begin scrolling the workspace. This 66300acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato // results in vertically scrolling widgets to more easily. The higher the angle, the 66400acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato // more we increase touch slop. 66531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project theta -= START_DAMPING_TOUCH_SLOP_ANGLE; 66628750fba6a2d141eb9a1e566718c17236030b815Michael Jurka float extraRatio = (float) 6670142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka Math.sqrt((theta / (MAX_SWIPE_ANGLE - START_DAMPING_TOUCH_SLOP_ANGLE))); 668aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung super.determineScrollingStart(ev, 1 + TOUCH_SLOP_DAMPING_FACTOR * extraRatio); 66979212d81361d1ad8c941c48f8323eb526643ca68Michael Jurka } else { 67079212d81361d1ad8c941c48f8323eb526643ca68Michael Jurka // Below START_DAMPING_TOUCH_SLOP_ANGLE, we don't do anything special 671883f55b1d261862b0de1b43af0b17d351761a9c6Michael Jurka super.determineScrollingStart(ev); 672883f55b1d261862b0de1b43af0b17d351761a9c6Michael Jurka } 673883f55b1d261862b0de1b43af0b17d351761a9c6Michael Jurka } 67479212d81361d1ad8c941c48f8323eb526643ca68Michael Jurka } 67579212d81361d1ad8c941c48f8323eb526643ca68Michael Jurka 676aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung @Override 677aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung protected boolean isScrollingIndicatorEnabled() { 678aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung return mState != State.SPRING_LOADED; 6790142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 680aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 68131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected void onPageBeginMoving() { 68231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project super.onPageBeginMoving(); 68331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 6849171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung if (isHardwareAccelerated()) { 6859171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung updateChildrenLayersEnabled(); 6869171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung } else { 6879171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung if (mNextPage != INVALID_PAGE) { 6889171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung // we're snapping to a particular screen 6899171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung enableChildrenCache(mCurrentPage, mNextPage); 6909171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung } else { 6919171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung // this is when user is actively dragging a particular screen, they might 6929171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung // swipe it either left or right (but we won't advance by more than one screen) 6939171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung enableChildrenCache(mCurrentPage - 1, mCurrentPage + 1); 6949171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung } 6959171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung } 6960142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 697c0e8fcae492730210b2b8b6d5bb3d65636bad245Michael Jurka // Only show page outlines as we pan if we are on large screen 6980142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka if (LauncherApplication.isScreenLarge()) { 6990142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka showOutlines(); 7000142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 7010142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 7020142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 7030142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka protected void onPageEndMoving() { 7040142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka super.onPageEndMoving(); 7050142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 7060142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka if (isHardwareAccelerated()) { 7070142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka updateChildrenLayersEnabled(); 708cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy } else { 7090207c522472d7252f146f4d39efa456ca5248c6bPatrick Dubroy clearChildrenCache(); 7100207c522472d7252f146f4d39efa456ca5248c6bPatrick Dubroy } 7110207c522472d7252f146f4d39efa456ca5248c6bPatrick Dubroy 7120207c522472d7252f146f4d39efa456ca5248c6bPatrick Dubroy // Hide the outlines, as long as we're not dragging 7130207c522472d7252f146f4d39efa456ca5248c6bPatrick Dubroy if (!mDragController.dragging()) { 7140207c522472d7252f146f4d39efa456ca5248c6bPatrick Dubroy // Only hide page outlines as we pan if we are on large screen 7150207c522472d7252f146f4d39efa456ca5248c6bPatrick Dubroy if (LauncherApplication.isScreenLarge()) { 7160207c522472d7252f146f4d39efa456ca5248c6bPatrick Dubroy hideOutlines(); 7170207c522472d7252f146f4d39efa456ca5248c6bPatrick Dubroy } 7180207c522472d7252f146f4d39efa456ca5248c6bPatrick Dubroy } 7190207c522472d7252f146f4d39efa456ca5248c6bPatrick Dubroy mOverScrollMaxBackgroundAlpha = 0.0f; 7200207c522472d7252f146f4d39efa456ca5248c6bPatrick Dubroy mOverScrollPageIndex = -1; 7210207c522472d7252f146f4d39efa456ca5248c6bPatrick Dubroy 7220207c522472d7252f146f4d39efa456ca5248c6bPatrick Dubroy if (mDelayedResizeRunnable != null) { 7230207c522472d7252f146f4d39efa456ca5248c6bPatrick Dubroy mDelayedResizeRunnable.run(); 7240207c522472d7252f146f4d39efa456ca5248c6bPatrick Dubroy mDelayedResizeRunnable = null; 7250207c522472d7252f146f4d39efa456ca5248c6bPatrick Dubroy } 7260207c522472d7252f146f4d39efa456ca5248c6bPatrick Dubroy } 7270207c522472d7252f146f4d39efa456ca5248c6bPatrick Dubroy 7280207c522472d7252f146f4d39efa456ca5248c6bPatrick Dubroy @Override 7290207c522472d7252f146f4d39efa456ca5248c6bPatrick Dubroy protected void notifyPageSwitchListener() { 7300207c522472d7252f146f4d39efa456ca5248c6bPatrick Dubroy super.notifyPageSwitchListener(); 7310207c522472d7252f146f4d39efa456ca5248c6bPatrick Dubroy Launcher.setScreen(mCurrentPage); 7320207c522472d7252f146f4d39efa456ca5248c6bPatrick Dubroy }; 733cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy 7348ae3a62e2e48dfb8f860c8b6e2c7e72b9595d7aaPatrick Dubroy // As a ratio of screen height, the total distance we want the parallax effect to span 7358ae3a62e2e48dfb8f860c8b6e2c7e72b9595d7aaPatrick Dubroy // horizontally 736cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy private float wallpaperTravelToScreenWidthRatio(int width, int height) { 737cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy float aspectRatio = width / (float) height; 738cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy 739cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy // At an aspect ratio of 16/10, the wallpaper parallax effect should span 1.5 * screen width 740cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy // At an aspect ratio of 10/16, the wallpaper parallax effect should span 1.2 * screen width 741cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy // We will use these two data points to extrapolate how much the wallpaper parallax effect 742cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy // to span (ie travel) at any aspect ratio: 74331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 74431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final float ASPECT_RATIO_LANDSCAPE = 16/10f; 74531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final float ASPECT_RATIO_PORTRAIT = 10/16f; 74631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final float WALLPAPER_WIDTH_TO_SCREEN_RATIO_LANDSCAPE = 1.5f; 74731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final float WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT = 1.2f; 748678862186af4ea70d9b4012c9bc127e7fea5e607Joe Onorato 74931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // To find out the desired width at different aspect ratios, we use the following two 75031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // formulas, where the coefficient on x is the aspect ratio (width/height): 75131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // (16/10)x + y = 1.5 75231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // (10/16)x + y = 1.2 7530142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka // We solve for x and y and end up with a final formula: 75431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final float x = 75531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project (WALLPAPER_WIDTH_TO_SCREEN_RATIO_LANDSCAPE - WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT) / 75631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project (ASPECT_RATIO_LANDSCAPE - ASPECT_RATIO_PORTRAIT); 75731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final float y = WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT - x * ASPECT_RATIO_PORTRAIT; 75831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return x * aspectRatio + y; 75931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 760c2e24c0a37ddeab930f731c062705d435e477f75Romain Guy 761678862186af4ea70d9b4012c9bc127e7fea5e607Joe Onorato // The range of scroll values for Workspace 76231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private int getScrollRange() { 7630142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka return getChildOffset(getChildCount() - 1) - getChildOffset(0); 76431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 7650142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 7660142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka protected void setWallpaperDimension() { 76731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project DisplayMetrics displayMetrics = new DisplayMetrics(); 76831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mLauncher.getWindowManager().getDefaultDisplay().getRealMetrics(displayMetrics); 76931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int maxDim = Math.max(displayMetrics.widthPixels, displayMetrics.heightPixels); 77031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int minDim = Math.min(displayMetrics.widthPixels, displayMetrics.heightPixels); 77131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 7727bb1749c69384faf00b238f0684d3b2e23406451Joe Onorato // We need to ensure that there is enough extra space in the wallpaper for the intended 7737bb1749c69384faf00b238f0684d3b2e23406451Joe Onorato // parallax effects 77454dd75463d0eb47c2f468e19063bdc4141dfdf74Michael Jurka if (LauncherApplication.isScreenLarge()) { 77554dd75463d0eb47c2f468e19063bdc4141dfdf74Michael Jurka mWallpaperWidth = (int) (maxDim * wallpaperTravelToScreenWidthRatio(maxDim, minDim)); 7766b4adbc0558fcebbd44998bd00dcd334ddbee32dJoe Onorato mWallpaperHeight = maxDim; 7777bb1749c69384faf00b238f0684d3b2e23406451Joe Onorato } else { 7787bb1749c69384faf00b238f0684d3b2e23406451Joe Onorato mWallpaperWidth = Math.max((int) (minDim * WALLPAPER_SCREENS_SPAN), maxDim); 7797bb1749c69384faf00b238f0684d3b2e23406451Joe Onorato mWallpaperHeight = maxDim; 7806b879f0a5885274a85333531e091283405d490ccAdam Lesinski } 7817bb1749c69384faf00b238f0684d3b2e23406451Joe Onorato new Thread("setWallpaperDimension") { 7827bb1749c69384faf00b238f0684d3b2e23406451Joe Onorato public void run() { 7837bb1749c69384faf00b238f0684d3b2e23406451Joe Onorato mWallpaperManager.suggestDesiredDimensions(mWallpaperWidth, mWallpaperHeight); 7840142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 7850142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka }.start(); 7860142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 7870142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 7880142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka public void setVerticalWallpaperOffset(float offset) { 7893a2b3f2be58843d26549fb0ec6c6533627c7cd19Mike Cleron mWallpaperOffset.setFinalY(offset); 790aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung } 791dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka public float getVerticalWallpaperOffset() { 792fea5d0250767ab938f623a404e6292a32dd2fdf5Adam Powell return mWallpaperOffset.getCurrY(); 7930142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 7940142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka public void setHorizontalWallpaperOffset(float offset) { 795fea5d0250767ab938f623a404e6292a32dd2fdf5Adam Powell mWallpaperOffset.setFinalX(offset); 7960142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 79731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public float getHorizontalWallpaperOffset() { 79831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return mWallpaperOffset.getCurrX(); 79931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 80031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 80131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private float wallpaperOffsetForCurrentScroll() { 80231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // The wallpaper travel width is how far, from left to right, the wallpaper will move 80331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // at this orientation. On tablets in portrait mode we don't move all the way to the 804dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka // edges of the wallpaper, or otherwise the parallax effect would be too strong. 805dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka int wallpaperTravelWidth = mWallpaperWidth; 80631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (LauncherApplication.isScreenLarge()) { 80731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project wallpaperTravelWidth = mWallpaperTravelWidth; 80831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 80931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 81031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // Set wallpaper offset steps (1 / (number of screens - 1)) 81131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mWallpaperManager.setWallpaperOffsetSteps(1.0f / (getChildCount() - 1), 1.0f); 81231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 8132bc6b7c2b8b651dde0a65c64c127f5b85c1290d2Joe Onorato // For the purposes of computing the scrollRange and overScrollOffset, we assume 8142bc6b7c2b8b651dde0a65c64c127f5b85c1290d2Joe Onorato // that mLayoutScale is 1. This means that when we're in spring-loaded mode, 8152bc6b7c2b8b651dde0a65c64c127f5b85c1290d2Joe Onorato // there's no discrepancy between the wallpaper offset for a given page. 8162bc6b7c2b8b651dde0a65c64c127f5b85c1290d2Joe Onorato float layoutScale = mLayoutScale; 8172bc6b7c2b8b651dde0a65c64c127f5b85c1290d2Joe Onorato mLayoutScale = 1f; 8183e7c7634531302271270c8cf418abc959d621cbcMichael Jurka int scrollRange = getScrollRange(); 8196b879f0a5885274a85333531e091283405d490ccAdam Lesinski 8206b879f0a5885274a85333531e091283405d490ccAdam Lesinski // Again, we adjust the wallpaper offset to be consistent between values of mLayoutScale 8216b879f0a5885274a85333531e091283405d490ccAdam Lesinski float adjustedScrollX = Math.max(0, Math.min(mScrollX, mMaxScrollX)); 8226b879f0a5885274a85333531e091283405d490ccAdam Lesinski adjustedScrollX *= mWallpaperScrollRatio; 8236b879f0a5885274a85333531e091283405d490ccAdam Lesinski mLayoutScale = layoutScale; 8246b879f0a5885274a85333531e091283405d490ccAdam Lesinski 8256b879f0a5885274a85333531e091283405d490ccAdam Lesinski float scrollProgress = 8266b879f0a5885274a85333531e091283405d490ccAdam Lesinski adjustedScrollX / (float) scrollRange; 82731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project float offsetInDips = wallpaperTravelWidth * scrollProgress + 82831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project (mWallpaperWidth - wallpaperTravelWidth) / 2; // center it 8290142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka float offset = offsetInDips / (float) mWallpaperWidth; 83031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return offset; 831aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung } 83201f0ed4126be412c8c4352026dad3b2a49832267Michael Jurka private void syncWallpaperOffsetWithScroll() { 83301f0ed4126be412c8c4352026dad3b2a49832267Michael Jurka final boolean enableWallpaperEffects = isHardwareAccelerated(); 83401f0ed4126be412c8c4352026dad3b2a49832267Michael Jurka if (enableWallpaperEffects) { 83501f0ed4126be412c8c4352026dad3b2a49832267Michael Jurka mWallpaperOffset.setFinalX(wallpaperOffsetForCurrentScroll()); 8366b509c1fd62a39916bb957eac07917161f549206Patrick Dubroy } 8370142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 83801f0ed4126be412c8c4352026dad3b2a49832267Michael Jurka 83901f0ed4126be412c8c4352026dad3b2a49832267Michael Jurka public void updateWallpaperOffsetImmediately() { 84001f0ed4126be412c8c4352026dad3b2a49832267Michael Jurka mUpdateWallpaperOffsetImmediately = true; 8410142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 842213d96354e7407dba5c9715eb10d04bebd82c395Michael Jurka 843213d96354e7407dba5c9715eb10d04bebd82c395Michael Jurka private void updateWallpaperOffsets() { 8446b879f0a5885274a85333531e091283405d490ccAdam Lesinski boolean updateNow = false; 8456b879f0a5885274a85333531e091283405d490ccAdam Lesinski boolean keepUpdating = true; 8466b879f0a5885274a85333531e091283405d490ccAdam Lesinski if (mUpdateWallpaperOffsetImmediately) { 8476b879f0a5885274a85333531e091283405d490ccAdam Lesinski updateNow = true; 8486b879f0a5885274a85333531e091283405d490ccAdam Lesinski keepUpdating = false; 8496b879f0a5885274a85333531e091283405d490ccAdam Lesinski mWallpaperOffset.jumpToFinal(); 85079212d81361d1ad8c941c48f8323eb526643ca68Michael Jurka mUpdateWallpaperOffsetImmediately = false; 85179212d81361d1ad8c941c48f8323eb526643ca68Michael Jurka } else { 8526b879f0a5885274a85333531e091283405d490ccAdam Lesinski updateNow = keepUpdating = mWallpaperOffset.computeScrollOffset(); 853883f55b1d261862b0de1b43af0b17d351761a9c6Michael Jurka } 854213d96354e7407dba5c9715eb10d04bebd82c395Michael Jurka if (updateNow) { 855213d96354e7407dba5c9715eb10d04bebd82c395Michael Jurka if (mWindowToken != null) { 8566b879f0a5885274a85333531e091283405d490ccAdam Lesinski mWallpaperManager.setWallpaperOffsets(mWindowToken, 8576b879f0a5885274a85333531e091283405d490ccAdam Lesinski mWallpaperOffset.getCurrX(), mWallpaperOffset.getCurrY()); 8586b879f0a5885274a85333531e091283405d490ccAdam Lesinski } 8596b879f0a5885274a85333531e091283405d490ccAdam Lesinski } 860a985e598f6071f4caca15ba3cb6b2cd3e38b217dAdam Cohen if (keepUpdating) { 861a985e598f6071f4caca15ba3cb6b2cd3e38b217dAdam Cohen fastInvalidate(); 862a985e598f6071f4caca15ba3cb6b2cd3e38b217dAdam Cohen } 863a985e598f6071f4caca15ba3cb6b2cd3e38b217dAdam Cohen } 864a985e598f6071f4caca15ba3cb6b2cd3e38b217dAdam Cohen 865a985e598f6071f4caca15ba3cb6b2cd3e38b217dAdam Cohen @Override 866a985e598f6071f4caca15ba3cb6b2cd3e38b217dAdam Cohen protected void updateCurrentPageScroll() { 867a985e598f6071f4caca15ba3cb6b2cd3e38b217dAdam Cohen super.updateCurrentPageScroll(); 868a985e598f6071f4caca15ba3cb6b2cd3e38b217dAdam Cohen computeWallpaperScrollRatio(mCurrentPage); 869a985e598f6071f4caca15ba3cb6b2cd3e38b217dAdam Cohen } 870a985e598f6071f4caca15ba3cb6b2cd3e38b217dAdam Cohen 871a985e598f6071f4caca15ba3cb6b2cd3e38b217dAdam Cohen @Override 872dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka protected void snapToPage(int whichPage) { 8730142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka super.snapToPage(whichPage); 8749171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung computeWallpaperScrollRatio(whichPage); 8759171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung } 876883f55b1d261862b0de1b43af0b17d351761a9c6Michael Jurka 877883f55b1d261862b0de1b43af0b17d351761a9c6Michael Jurka private void computeWallpaperScrollRatio(int page) { 878883f55b1d261862b0de1b43af0b17d351761a9c6Michael Jurka // Here, we determine what the desired scroll would be with and without a layout scale, 879883f55b1d261862b0de1b43af0b17d351761a9c6Michael Jurka // and compute a ratio between the two. This allows us to adjust the wallpaper offset 880883f55b1d261862b0de1b43af0b17d351761a9c6Michael Jurka // as though there is no layout scale. 881883f55b1d261862b0de1b43af0b17d351761a9c6Michael Jurka float layoutScale = mLayoutScale; 882883f55b1d261862b0de1b43af0b17d351761a9c6Michael Jurka int scaled = getChildOffset(page) - getRelativeChildOffset(page); 883883f55b1d261862b0de1b43af0b17d351761a9c6Michael Jurka mLayoutScale = 1.0f; 884883f55b1d261862b0de1b43af0b17d351761a9c6Michael Jurka float unscaled = getChildOffset(page) - getRelativeChildOffset(page); 885dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka mLayoutScale = layoutScale; 8863e7c7634531302271270c8cf418abc959d621cbcMichael Jurka if (scaled > 0) { 8873e7c7634531302271270c8cf418abc959d621cbcMichael Jurka mWallpaperScrollRatio = (1.0f * unscaled) / scaled; 8883e7c7634531302271270c8cf418abc959d621cbcMichael Jurka } else { 889a997ac26664befbd0d5b172e36ef9e8b2c63b435Michael Jurka mWallpaperScrollRatio = 1f; 8903e7c7634531302271270c8cf418abc959d621cbcMichael Jurka } 8913e7c7634531302271270c8cf418abc959d621cbcMichael Jurka } 8925f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka 8935f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka class WallpaperOffsetInterpolator { 8945f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka float mFinalHorizontalWallpaperOffset = 0.0f; 8955f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka float mFinalVerticalWallpaperOffset = 0.5f; 8961b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen float mHorizontalWallpaperOffset = 0.0f; 897ddb821981e0919bbd3b4c9a2b6aa1811d6c86bb6Adam Cohen float mVerticalWallpaperOffset = 0.5f; 898ddb821981e0919bbd3b4c9a2b6aa1811d6c86bb6Adam Cohen long mLastWallpaperOffsetUpdateTime; 899ddb821981e0919bbd3b4c9a2b6aa1811d6c86bb6Adam Cohen boolean mIsMovingFast; 9001b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen boolean mOverrideHorizontalCatchupConstant; 9011b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen float mHorizontalCatchupConstant = 0.35f; 9027247f6315baf16eacb3286f21bd80321385c1defPatrick Dubroy float mVerticalCatchupConstant = 0.35f; 903dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka 904213d96354e7407dba5c9715eb10d04bebd82c395Michael Jurka public WallpaperOffsetInterpolator() { 9050142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 9060142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 9070142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka public void setOverrideHorizontalCatchupConstant(boolean override) { 9080142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka mOverrideHorizontalCatchupConstant = override; 9090142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 9100142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 9110142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka public void setHorizontalCatchupConstant(float f) { 912a985e598f6071f4caca15ba3cb6b2cd3e38b217dAdam Cohen mHorizontalCatchupConstant = f; 913dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } 914dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka 915a985e598f6071f4caca15ba3cb6b2cd3e38b217dAdam Cohen public void setVerticalCatchupConstant(float f) { 916213d96354e7407dba5c9715eb10d04bebd82c395Michael Jurka mVerticalCatchupConstant = f; 917df4b83dd9d6380ab963c62d1f9d1312efc87cb0fWinson Chung } 918df4b83dd9d6380ab963c62d1f9d1312efc87cb0fWinson Chung 919ef0066b52d2754ca0553ec79613c650b5649afaaWinson Chung public boolean computeScrollOffset() { 920ef0066b52d2754ca0553ec79613c650b5649afaaWinson Chung if (Float.compare(mHorizontalWallpaperOffset, mFinalHorizontalWallpaperOffset) == 0 && 9213e7c7634531302271270c8cf418abc959d621cbcMichael Jurka Float.compare(mVerticalWallpaperOffset, mFinalVerticalWallpaperOffset) == 0) { 9223e7c7634531302271270c8cf418abc959d621cbcMichael Jurka mIsMovingFast = false; 9233e7c7634531302271270c8cf418abc959d621cbcMichael Jurka return false; 9243e7c7634531302271270c8cf418abc959d621cbcMichael Jurka } 9253e7c7634531302271270c8cf418abc959d621cbcMichael Jurka boolean isLandscape = mDisplayWidth > mDisplayHeight; 9263e7c7634531302271270c8cf418abc959d621cbcMichael Jurka 9273e7c7634531302271270c8cf418abc959d621cbcMichael Jurka long currentTime = System.currentTimeMillis(); 9283e7c7634531302271270c8cf418abc959d621cbcMichael Jurka long timeSinceLastUpdate = currentTime - mLastWallpaperOffsetUpdateTime; 9290142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka timeSinceLastUpdate = Math.min((long) (1000/30f), timeSinceLastUpdate); 9306b879f0a5885274a85333531e091283405d490ccAdam Lesinski timeSinceLastUpdate = Math.max(1L, timeSinceLastUpdate); 9310142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 932b0b2e6f588367cf40a4270cca81af7d78f8e382eWinson Chung float xdiff = Math.abs(mFinalHorizontalWallpaperOffset - mHorizontalWallpaperOffset); 933b0b2e6f588367cf40a4270cca81af7d78f8e382eWinson Chung if (!mIsMovingFast && xdiff > 0.07) { 934b0b2e6f588367cf40a4270cca81af7d78f8e382eWinson Chung mIsMovingFast = true; 935ef0066b52d2754ca0553ec79613c650b5649afaaWinson Chung } 936ef0066b52d2754ca0553ec79613c650b5649afaaWinson Chung 937ef0066b52d2754ca0553ec79613c650b5649afaaWinson Chung float fractionToCatchUpIn1MsHorizontal; 938213d96354e7407dba5c9715eb10d04bebd82c395Michael Jurka if (mOverrideHorizontalCatchupConstant) { 939dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka fractionToCatchUpIn1MsHorizontal = mHorizontalCatchupConstant; 940dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } else if (mIsMovingFast) { 941dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka fractionToCatchUpIn1MsHorizontal = isLandscape ? 0.5f : 0.75f; 942dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } else { 943dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka // slow 9440142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka fractionToCatchUpIn1MsHorizontal = isLandscape ? 0.27f : 0.5f; 945a985e598f6071f4caca15ba3cb6b2cd3e38b217dAdam Cohen } 946a985e598f6071f4caca15ba3cb6b2cd3e38b217dAdam Cohen float fractionToCatchUpIn1MsVertical = mVerticalCatchupConstant; 947a985e598f6071f4caca15ba3cb6b2cd3e38b217dAdam Cohen 948a985e598f6071f4caca15ba3cb6b2cd3e38b217dAdam Cohen fractionToCatchUpIn1MsHorizontal /= 33f; 949a985e598f6071f4caca15ba3cb6b2cd3e38b217dAdam Cohen fractionToCatchUpIn1MsVertical /= 33f; 9503c4c20fbe682cb4b3ef94f09afe0af09171583f3Michael Jurka 9513c4c20fbe682cb4b3ef94f09afe0af09171583f3Michael Jurka final float UPDATE_THRESHOLD = 0.00001f; 9523c4c20fbe682cb4b3ef94f09afe0af09171583f3Michael Jurka float hOffsetDelta = mFinalHorizontalWallpaperOffset - mHorizontalWallpaperOffset; 9533c4c20fbe682cb4b3ef94f09afe0af09171583f3Michael Jurka float vOffsetDelta = mFinalVerticalWallpaperOffset - mVerticalWallpaperOffset; 9543c4c20fbe682cb4b3ef94f09afe0af09171583f3Michael Jurka boolean jumpToFinalValue = Math.abs(hOffsetDelta) < UPDATE_THRESHOLD && 955dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka Math.abs(vOffsetDelta) < UPDATE_THRESHOLD; 956dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka 957a985e598f6071f4caca15ba3cb6b2cd3e38b217dAdam Cohen // Don't have any lag between workspace and wallpaper on non-large devices 958f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen if (!LauncherApplication.isScreenLarge() || jumpToFinalValue) { 959a985e598f6071f4caca15ba3cb6b2cd3e38b217dAdam Cohen mHorizontalWallpaperOffset = mFinalHorizontalWallpaperOffset; 960a985e598f6071f4caca15ba3cb6b2cd3e38b217dAdam Cohen mVerticalWallpaperOffset = mFinalVerticalWallpaperOffset; 961a985e598f6071f4caca15ba3cb6b2cd3e38b217dAdam Cohen } else { 96279212d81361d1ad8c941c48f8323eb526643ca68Michael Jurka float percentToCatchUpVertical = 9637247f6315baf16eacb3286f21bd80321385c1defPatrick Dubroy Math.min(1.0f, timeSinceLastUpdate * fractionToCatchUpIn1MsVertical); 964cbbaf9862aa160c5e397cb49b554de20981a35feAdam Cohen float percentToCatchUpHorizontal = 965cbbaf9862aa160c5e397cb49b554de20981a35feAdam Cohen Math.min(1.0f, timeSinceLastUpdate * fractionToCatchUpIn1MsHorizontal); 966472b281d5cb4f5660df981a6c912266b9f5703feChet Haase mHorizontalWallpaperOffset += percentToCatchUpHorizontal * hOffsetDelta; 967472b281d5cb4f5660df981a6c912266b9f5703feChet Haase mVerticalWallpaperOffset += percentToCatchUpVertical * vOffsetDelta; 968472b281d5cb4f5660df981a6c912266b9f5703feChet Haase } 9693e7c7634531302271270c8cf418abc959d621cbcMichael Jurka 970472b281d5cb4f5660df981a6c912266b9f5703feChet Haase mLastWallpaperOffsetUpdateTime = System.currentTimeMillis(); 97161033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen return true; 97261033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen } 97361033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen 97461033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen public float getCurrX() { 97561033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen return mHorizontalWallpaperOffset; 976cbbaf9862aa160c5e397cb49b554de20981a35feAdam Cohen } 97761033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen 97861033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen public float getFinalX() { 97979212d81361d1ad8c941c48f8323eb526643ca68Michael Jurka return mFinalHorizontalWallpaperOffset; 98079212d81361d1ad8c941c48f8323eb526643ca68Michael Jurka } 98179212d81361d1ad8c941c48f8323eb526643ca68Michael Jurka 982883f55b1d261862b0de1b43af0b17d351761a9c6Michael Jurka public float getCurrY() { 983883f55b1d261862b0de1b43af0b17d351761a9c6Michael Jurka return mVerticalWallpaperOffset; 984883f55b1d261862b0de1b43af0b17d351761a9c6Michael Jurka } 9853e7c7634531302271270c8cf418abc959d621cbcMichael Jurka 986a985e598f6071f4caca15ba3cb6b2cd3e38b217dAdam Cohen public float getFinalY() { 98779212d81361d1ad8c941c48f8323eb526643ca68Michael Jurka return mFinalVerticalWallpaperOffset; 988dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } 989a985e598f6071f4caca15ba3cb6b2cd3e38b217dAdam Cohen 990dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka public void setFinalX(float x) { 9913c4c20fbe682cb4b3ef94f09afe0af09171583f3Michael Jurka mFinalHorizontalWallpaperOffset = Math.max(0f, Math.min(x, 1.0f)); 9923c4c20fbe682cb4b3ef94f09afe0af09171583f3Michael Jurka } 9933c4c20fbe682cb4b3ef94f09afe0af09171583f3Michael Jurka 994dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka public void setFinalY(float y) { 995dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka mFinalVerticalWallpaperOffset = Math.max(0f, Math.min(y, 1.0f)); 996dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } 99761033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen 99861033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen public void jumpToFinal() { 99961033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen mHorizontalWallpaperOffset = mFinalHorizontalWallpaperOffset; 100061033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen mVerticalWallpaperOffset = mFinalVerticalWallpaperOffset; 100161033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen } 100261033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen } 100361033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen 100461033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen @Override 100561033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen public void computeScroll() { 100661033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen super.computeScroll(); 100761033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen syncWallpaperOffsetWithScroll(); 100861033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen } 100961033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen 1010eed565d5126cb40b2a7ecdf5f6e8ac7a7464007bAdam Cohen void showOutlines() { 1011eed565d5126cb40b2a7ecdf5f6e8ac7a7464007bAdam Cohen if (!isSmall() && !mIsSwitchingState) { 101261033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen if (mChildrenOutlineFadeOutAnimation != null) mChildrenOutlineFadeOutAnimation.cancel(); 1013cbbaf9862aa160c5e397cb49b554de20981a35feAdam Cohen if (mChildrenOutlineFadeInAnimation != null) mChildrenOutlineFadeInAnimation.cancel(); 1014cbbaf9862aa160c5e397cb49b554de20981a35feAdam Cohen mChildrenOutlineFadeInAnimation = ObjectAnimator.ofFloat(this, "childrenOutlineAlpha", 1.0f); 1015cbbaf9862aa160c5e397cb49b554de20981a35feAdam Cohen mChildrenOutlineFadeInAnimation.setDuration(CHILDREN_OUTLINE_FADE_IN_DURATION); 101661033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen mChildrenOutlineFadeInAnimation.start(); 101761033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen } 101861033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen } 101961033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen 102061033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen void hideOutlines() { 102161033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen if (!isSmall() && !mIsSwitchingState) { 102261033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen if (mChildrenOutlineFadeInAnimation != null) mChildrenOutlineFadeInAnimation.cancel(); 102361033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen if (mChildrenOutlineFadeOutAnimation != null) mChildrenOutlineFadeOutAnimation.cancel(); 1024cbbaf9862aa160c5e397cb49b554de20981a35feAdam Cohen mChildrenOutlineFadeOutAnimation = ObjectAnimator.ofFloat(this, "childrenOutlineAlpha", 0.0f); 102561033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen mChildrenOutlineFadeOutAnimation.setDuration(CHILDREN_OUTLINE_FADE_OUT_DURATION); 1026cbbaf9862aa160c5e397cb49b554de20981a35feAdam Cohen mChildrenOutlineFadeOutAnimation.setStartDelay(CHILDREN_OUTLINE_FADE_OUT_DELAY); 1027cbbaf9862aa160c5e397cb49b554de20981a35feAdam Cohen mChildrenOutlineFadeOutAnimation.start(); 1028cbbaf9862aa160c5e397cb49b554de20981a35feAdam Cohen } 102961033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen } 103061033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen 103161033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen public void showOutlinesTemporarily() { 103261033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen if (!mIsPageMoving && !isTouchActive()) { 103361033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen snapToPage(mCurrentPage); 103461033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen } 103561033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen } 103661033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen 103761033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen public void setChildrenOutlineAlpha(float alpha) { 103861033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen mChildrenOutlineAlpha = alpha; 103961033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen for (int i = 0; i < getChildCount(); i++) { 104061033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen CellLayout cl = (CellLayout) getChildAt(i); 104161033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen cl.setBackgroundAlpha(alpha); 104261033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen } 104361033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen } 104461033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen 104561033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen public float getChildrenOutlineAlpha() { 104661033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen return mChildrenOutlineAlpha; 104761033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen } 104861033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen 104961033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen void disableBackground() { 105061033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen mDrawBackground = false; 105161033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen } 105261033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen void enableBackground() { 105361033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen mDrawBackground = true; 105461033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen } 10553e7c7634531302271270c8cf418abc959d621cbcMichael Jurka 10563e7c7634531302271270c8cf418abc959d621cbcMichael Jurka private void animateBackgroundGradient(float finalAlpha, boolean animated) { 10573e7c7634531302271270c8cf418abc959d621cbcMichael Jurka if (mBackground == null) return; 10583e7c7634531302271270c8cf418abc959d621cbcMichael Jurka if (mBackgroundFadeInAnimation != null) { 10593e7c7634531302271270c8cf418abc959d621cbcMichael Jurka mBackgroundFadeInAnimation.cancel(); 10603e7c7634531302271270c8cf418abc959d621cbcMichael Jurka mBackgroundFadeInAnimation = null; 10613e7c7634531302271270c8cf418abc959d621cbcMichael Jurka } 10623e7c7634531302271270c8cf418abc959d621cbcMichael Jurka if (mBackgroundFadeOutAnimation != null) { 10633e7c7634531302271270c8cf418abc959d621cbcMichael Jurka mBackgroundFadeOutAnimation.cancel(); 10643e7c7634531302271270c8cf418abc959d621cbcMichael Jurka mBackgroundFadeOutAnimation = null; 10653e7c7634531302271270c8cf418abc959d621cbcMichael Jurka } 10663e7c7634531302271270c8cf418abc959d621cbcMichael Jurka float startAlpha = getBackgroundAlpha(); 10673e7c7634531302271270c8cf418abc959d621cbcMichael Jurka if (finalAlpha != startAlpha) { 10683e7c7634531302271270c8cf418abc959d621cbcMichael Jurka if (animated) { 10693e7c7634531302271270c8cf418abc959d621cbcMichael Jurka mBackgroundFadeOutAnimation = ValueAnimator.ofFloat(startAlpha, finalAlpha); 10703e7c7634531302271270c8cf418abc959d621cbcMichael Jurka mBackgroundFadeOutAnimation.addUpdateListener(new AnimatorUpdateListener() { 10713e7c7634531302271270c8cf418abc959d621cbcMichael Jurka public void onAnimationUpdate(ValueAnimator animation) { 10723e7c7634531302271270c8cf418abc959d621cbcMichael Jurka setBackgroundAlpha(((Float) animation.getAnimatedValue()).floatValue()); 10733e7c7634531302271270c8cf418abc959d621cbcMichael Jurka } 10743e7c7634531302271270c8cf418abc959d621cbcMichael Jurka }); 10753e7c7634531302271270c8cf418abc959d621cbcMichael Jurka mBackgroundFadeOutAnimation.setInterpolator(new DecelerateInterpolator(1.5f)); 10763e7c7634531302271270c8cf418abc959d621cbcMichael Jurka mBackgroundFadeOutAnimation.setDuration(BACKGROUND_FADE_OUT_DURATION); 10773e7c7634531302271270c8cf418abc959d621cbcMichael Jurka mBackgroundFadeOutAnimation.start(); 10783e7c7634531302271270c8cf418abc959d621cbcMichael Jurka } else { 10793e7c7634531302271270c8cf418abc959d621cbcMichael Jurka setBackgroundAlpha(finalAlpha); 10803e7c7634531302271270c8cf418abc959d621cbcMichael Jurka } 10813e7c7634531302271270c8cf418abc959d621cbcMichael Jurka } 10823e7c7634531302271270c8cf418abc959d621cbcMichael Jurka } 10833e7c7634531302271270c8cf418abc959d621cbcMichael Jurka 10843e7c7634531302271270c8cf418abc959d621cbcMichael Jurka public void setBackgroundAlpha(float alpha) { 10853e7c7634531302271270c8cf418abc959d621cbcMichael Jurka if (alpha != mBackgroundAlpha) { 10863e7c7634531302271270c8cf418abc959d621cbcMichael Jurka mBackgroundAlpha = alpha; 10873e7c7634531302271270c8cf418abc959d621cbcMichael Jurka invalidate(); 10883e7c7634531302271270c8cf418abc959d621cbcMichael Jurka } 10893e7c7634531302271270c8cf418abc959d621cbcMichael Jurka } 10903e7c7634531302271270c8cf418abc959d621cbcMichael Jurka 10913e7c7634531302271270c8cf418abc959d621cbcMichael Jurka public float getBackgroundAlpha() { 10923e7c7634531302271270c8cf418abc959d621cbcMichael Jurka return mBackgroundAlpha; 10933e7c7634531302271270c8cf418abc959d621cbcMichael Jurka } 10943e7c7634531302271270c8cf418abc959d621cbcMichael Jurka 10953e7c7634531302271270c8cf418abc959d621cbcMichael Jurka /** 10963e7c7634531302271270c8cf418abc959d621cbcMichael Jurka * Due to 3D transformations, if two CellLayouts are theoretically touching each other, 10973e7c7634531302271270c8cf418abc959d621cbcMichael Jurka * on the xy plane, when one is rotated along the y-axis, the gap between them is perceived 10983e7c7634531302271270c8cf418abc959d621cbcMichael Jurka * as being larger. This method computes what offset the rotated view should be translated 10993e7c7634531302271270c8cf418abc959d621cbcMichael Jurka * in order to minimize this perceived gap. 11003e7c7634531302271270c8cf418abc959d621cbcMichael Jurka * @param degrees Angle of the view 11013e7c7634531302271270c8cf418abc959d621cbcMichael Jurka * @param width Width of the view 11026b879f0a5885274a85333531e091283405d490ccAdam Lesinski * @param height Height of the view 11033e7c7634531302271270c8cf418abc959d621cbcMichael Jurka * @return Offset to be used in a View.setTranslationX() call 11043e7c7634531302271270c8cf418abc959d621cbcMichael Jurka */ 11053e7c7634531302271270c8cf418abc959d621cbcMichael Jurka private float getOffsetXForRotation(float degrees, int width, int height) { 11063e7c7634531302271270c8cf418abc959d621cbcMichael Jurka mMatrix.reset(); 11073e7c7634531302271270c8cf418abc959d621cbcMichael Jurka mCamera.save(); 11083e7c7634531302271270c8cf418abc959d621cbcMichael Jurka mCamera.rotateY(Math.abs(degrees)); 11093e7c7634531302271270c8cf418abc959d621cbcMichael Jurka mCamera.getMatrix(mMatrix); 11103e7c7634531302271270c8cf418abc959d621cbcMichael Jurka mCamera.restore(); 11113e7c7634531302271270c8cf418abc959d621cbcMichael Jurka 11123e7c7634531302271270c8cf418abc959d621cbcMichael Jurka mMatrix.preTranslate(-width * 0.5f, -height * 0.5f); 11133e7c7634531302271270c8cf418abc959d621cbcMichael Jurka mMatrix.postTranslate(width * 0.5f, height * 0.5f); 11143e7c7634531302271270c8cf418abc959d621cbcMichael Jurka mTempFloat2[0] = width; 11153e7c7634531302271270c8cf418abc959d621cbcMichael Jurka mTempFloat2[1] = height; 11163e7c7634531302271270c8cf418abc959d621cbcMichael Jurka mMatrix.mapPoints(mTempFloat2); 11173e7c7634531302271270c8cf418abc959d621cbcMichael Jurka return (width - mTempFloat2[0]) * (degrees > 0.0f ? 1.0f : -1.0f); 11183e7c7634531302271270c8cf418abc959d621cbcMichael Jurka } 11193e7c7634531302271270c8cf418abc959d621cbcMichael Jurka 1120dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka float backgroundAlphaInterpolator(float r) { 11212b9ff37edb3f5965559b3ff7d37e418b4a2917a1Patrick Dubroy float pivotA = 0.1f; 11220142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka float pivotB = 0.4f; 11234cb3724a2c1e5f278e1531d643accc40fcd8e219Michael Jurka if (r < pivotA) { 11244cb3724a2c1e5f278e1531d643accc40fcd8e219Michael Jurka return 0; 11254cb3724a2c1e5f278e1531d643accc40fcd8e219Michael Jurka } else if (r > pivotB) { 11260142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka return 1.0f; 11274cb3724a2c1e5f278e1531d643accc40fcd8e219Michael Jurka } else { 11284cb3724a2c1e5f278e1531d643accc40fcd8e219Michael Jurka return (r - pivotA)/(pivotB - pivotA); 11290142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 11304cb3724a2c1e5f278e1531d643accc40fcd8e219Michael Jurka } 11314cb3724a2c1e5f278e1531d643accc40fcd8e219Michael Jurka 113221f12b52a54d2658ed14fcf7bb1ca17a198f62beAdam Cohen float overScrollBackgroundAlphaInterpolator(float r) { 113321f12b52a54d2658ed14fcf7bb1ca17a198f62beAdam Cohen float threshold = 0.08f; 113421f12b52a54d2658ed14fcf7bb1ca17a198f62beAdam Cohen 113521f12b52a54d2658ed14fcf7bb1ca17a198f62beAdam Cohen if (r > mOverScrollMaxBackgroundAlpha) { 113621f12b52a54d2658ed14fcf7bb1ca17a198f62beAdam Cohen mOverScrollMaxBackgroundAlpha = r; 11370142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } else if (r < mOverScrollMaxBackgroundAlpha) { 1138b0f28bd9a52fa4e343c8299d1c3e225d8e01c1e9Michael Jurka r = mOverScrollMaxBackgroundAlpha; 11395f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka } 11405f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka 11414cb3724a2c1e5f278e1531d643accc40fcd8e219Michael Jurka return Math.min(r / threshold, 1.0f); 1142b0f28bd9a52fa4e343c8299d1c3e225d8e01c1e9Michael Jurka } 1143b0f28bd9a52fa4e343c8299d1c3e225d8e01c1e9Michael Jurka 1144b0f28bd9a52fa4e343c8299d1c3e225d8e01c1e9Michael Jurka private void screenScrolledLargeUI(int screenCenter) { 1145b0f28bd9a52fa4e343c8299d1c3e225d8e01c1e9Michael Jurka if (isSwitchingState()) return; 1146b0f28bd9a52fa4e343c8299d1c3e225d8e01c1e9Michael Jurka boolean isInOverscroll = false; 11470142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka for (int i = 0; i < getChildCount(); i++) { 1148c0e8fcae492730210b2b8b6d5bb3d65636bad245Michael Jurka CellLayout cl = (CellLayout) getChildAt(i); 1149b0f28bd9a52fa4e343c8299d1c3e225d8e01c1e9Michael Jurka if (cl != null) { 1150dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka float scrollProgress = getScrollProgress(screenCenter, cl, i); 1151dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka float rotation = WORKSPACE_ROTATION * scrollProgress; 11524cb3724a2c1e5f278e1531d643accc40fcd8e219Michael Jurka float translationX = getOffsetXForRotation(rotation, cl.getWidth(), cl.getHeight()); 11534cb3724a2c1e5f278e1531d643accc40fcd8e219Michael Jurka 11544cb3724a2c1e5f278e1531d643accc40fcd8e219Michael Jurka // If the current page (i) is being over scrolled, we use a different 11554cb3724a2c1e5f278e1531d643accc40fcd8e219Michael Jurka // set of rules for setting the background alpha multiplier. 11564cb3724a2c1e5f278e1531d643accc40fcd8e219Michael Jurka if (!isSmall()) { 11579171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung if ((mOverScrollX < 0 && i == 0) || (mOverScrollX > mMaxScrollX && 11589171e6d8a2b7b5aa136617b9779a8bbadc5259f7Winson Chung i == getChildCount() -1)) { 1159b0f28bd9a52fa4e343c8299d1c3e225d8e01c1e9Michael Jurka isInOverscroll = true; 1160c0e8fcae492730210b2b8b6d5bb3d65636bad245Michael Jurka rotation *= -1; 11613c4c20fbe682cb4b3ef94f09afe0af09171583f3Michael Jurka cl.setBackgroundAlphaMultiplier( 11623c4c20fbe682cb4b3ef94f09afe0af09171583f3Michael Jurka overScrollBackgroundAlphaInterpolator(Math.abs(scrollProgress))); 11633c4c20fbe682cb4b3ef94f09afe0af09171583f3Michael Jurka mOverScrollPageIndex = i; 11646b879f0a5885274a85333531e091283405d490ccAdam Lesinski cl.setOverScrollAmount(Math.abs(scrollProgress), i == 0); 11653c4c20fbe682cb4b3ef94f09afe0af09171583f3Michael Jurka cl.setPivotX(cl.getMeasuredWidth() * (i == 0 ? 0.75f : 0.25f)); 1166b0f28bd9a52fa4e343c8299d1c3e225d8e01c1e9Michael Jurka cl.setPivotY(cl.getMeasuredHeight() * 0.5f); 11674cb3724a2c1e5f278e1531d643accc40fcd8e219Michael Jurka cl.setOverscrollTransformsDirty(true); 11684cb3724a2c1e5f278e1531d643accc40fcd8e219Michael Jurka } else if (mOverScrollPageIndex != i) { 1169b0f28bd9a52fa4e343c8299d1c3e225d8e01c1e9Michael Jurka cl.setBackgroundAlphaMultiplier( 11707247f6315baf16eacb3286f21bd80321385c1defPatrick Dubroy backgroundAlphaInterpolator(Math.abs(scrollProgress))); 11715f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka } 1172f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen } 1173f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen cl.setFastTranslationX(translationX); 1174f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen cl.setFastRotationY(rotation); 1175f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen if (mFadeInAdjacentScreens && !isSmall()) { 1176f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen float alpha = 1 - Math.abs(scrollProgress); 1177f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen cl.setFastAlpha(alpha); 1178f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen } 1179f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen cl.fastInvalidate(); 11806b879f0a5885274a85333531e091283405d490ccAdam Lesinski } 1181cbbaf9862aa160c5e397cb49b554de20981a35feAdam Cohen } 11826b879f0a5885274a85333531e091283405d490ccAdam Lesinski if (!isSwitchingState() && !isInOverscroll) { 1183cbbaf9862aa160c5e397cb49b554de20981a35feAdam Cohen ((CellLayout) getChildAt(0)).resetOverscrollTransforms(); 11846b879f0a5885274a85333531e091283405d490ccAdam Lesinski ((CellLayout) getChildAt(getChildCount() - 1)).resetOverscrollTransforms(); 1185cbbaf9862aa160c5e397cb49b554de20981a35feAdam Cohen } 1186cbbaf9862aa160c5e397cb49b554de20981a35feAdam Cohen invalidate(); 118761033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen } 118861033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen 118961033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen private void screenScrolledStandardUI(int screenCenter) { 119061033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen if (mOverScrollX < 0 || mOverScrollX > mMaxScrollX) { 1191cbbaf9862aa160c5e397cb49b554de20981a35feAdam Cohen int index = mOverScrollX < 0 ? 0 : getChildCount() - 1; 119261033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen CellLayout cl = (CellLayout) getChildAt(index); 119361033d3d86fcae1f654f3fbfc9979d131e265d76Adam Cohen float scrollProgress = getScrollProgress(screenCenter, cl, index); 11944cb3724a2c1e5f278e1531d643accc40fcd8e219Michael Jurka cl.setOverScrollAmount(Math.abs(scrollProgress), index == 0); 11956b879f0a5885274a85333531e091283405d490ccAdam Lesinski float rotation = - WORKSPACE_OVERSCROLL_ROTATION * scrollProgress; 11964cb3724a2c1e5f278e1531d643accc40fcd8e219Michael Jurka cl.setCameraDistance(mDensity * CAMERA_DISTANCE); 11974cb3724a2c1e5f278e1531d643accc40fcd8e219Michael Jurka cl.setPivotX(cl.getMeasuredWidth() * (index == 0 ? 0.75f : 0.25f)); 11984cb3724a2c1e5f278e1531d643accc40fcd8e219Michael Jurka cl.setPivotY(cl.getMeasuredHeight() * 0.5f); 11995f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka cl.setRotationY(rotation); 1200f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen cl.setOverscrollTransformsDirty(true); 1201f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen setFadeForOverScroll(Math.abs(scrollProgress)); 12024cb3724a2c1e5f278e1531d643accc40fcd8e219Michael Jurka } else { 1203b0f28bd9a52fa4e343c8299d1c3e225d8e01c1e9Michael Jurka if (mOverscrollFade != 0) { 12046b879f0a5885274a85333531e091283405d490ccAdam Lesinski setFadeForOverScroll(0); 1205c86756c20196e5c907df01fe0fc9193ffb934082Michael Jurka } 1206c86756c20196e5c907df01fe0fc9193ffb934082Michael Jurka // We don't want to mess with the translations during transitions 1207c86756c20196e5c907df01fe0fc9193ffb934082Michael Jurka if (!isSwitchingState()) { 12083c4c20fbe682cb4b3ef94f09afe0af09171583f3Michael Jurka ((CellLayout) getChildAt(0)).resetOverscrollTransforms(); 12093c4c20fbe682cb4b3ef94f09afe0af09171583f3Michael Jurka ((CellLayout) getChildAt(getChildCount() - 1)).resetOverscrollTransforms(); 1210c86756c20196e5c907df01fe0fc9193ffb934082Michael Jurka } 1211dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } 1212dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } 1213dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka 12144be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato @Override 12154be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato protected void screenScrolled(int screenCenter) { 12164be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato if (LauncherApplication.isScreenLarge()) { 12174be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // We don't call super.screenScrolled() here because we handle the adjacent pages alpha 12184be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // ourselves (for efficiency), and there are no scrolling indicators to update. 12194be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato screenScrolledLargeUI(screenCenter); 12204be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato } else { 12214be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato super.screenScrolled(screenCenter); 12224be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato screenScrolledStandardUI(screenCenter); 12234be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato } 12244be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato } 12254be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato 12264be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato @Override 1227bbc60d8e79416e37cbede55c159bf6aaa6c171d5Winson Chung protected void overScroll(float amount) { 1228bbc60d8e79416e37cbede55c159bf6aaa6c171d5Winson Chung if (LauncherApplication.isScreenLarge()) { 12294be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato dampedOverScroll(amount); 12304be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato } else { 12314be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato acceleratedOverScroll(amount); 12324be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato } 12334be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato } 12344be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato 12354be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato protected void onAttachedToWindow() { 12364be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato super.onAttachedToWindow(); 12374be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato mWindowToken = getWindowToken(); 12384be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato computeScroll(); 12394be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato mDragController.setWindowToken(mWindowToken); 12404be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato } 12414be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato 12424be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato protected void onDetachedFromWindow() { 12434be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato mWindowToken = null; 12444be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato } 12454be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato 12464be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato @Override 12474be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 12484be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato if (mFirstLayout && mCurrentPage >= 0 && mCurrentPage < getChildCount()) { 12494be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato mUpdateWallpaperOffsetImmediately = true; 12504be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato } 12514be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato super.onLayout(changed, left, top, right, bottom); 12524be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato 12534be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // if shrinkToBottom() is called on initialization, it has to be deferred 12544be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // until after the first call to onLayout so that it has the correct width 12554be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato if (mSwitchStateAfterFirstLayout) { 12564be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato mSwitchStateAfterFirstLayout = false; 12574be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // shrink can trigger a synchronous onLayout call, so we 12584be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // post this to avoid a stack overflow / tangled onLayout calls 1259a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung post(new Runnable() { 1260a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung public void run() { 1261a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung changeState(mStateAfterFirstLayout, false); 1262a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung } 1263a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung }); 1264a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung } 1265a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung } 1266a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung 1267a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung @Override 1268a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung protected void onDraw(Canvas canvas) { 1269a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung updateWallpaperOffsets(); 1270a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung 1271a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung // Draw the background gradient if necessary 1272a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung if (mBackground != null && mBackgroundAlpha > 0.0f && mDrawBackground) { 1273a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung int alpha = (int) (mBackgroundAlpha * 255); 1274a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung mBackground.setAlpha(alpha); 1275a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung mBackground.setBounds(mScrollX, 0, mScrollX + getMeasuredWidth(), 1276a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung getMeasuredHeight()); 1277a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung mBackground.draw(canvas); 1278a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung } 1279a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung 1280a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung super.onDraw(canvas); 1281a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung } 12824be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato 12834be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato boolean isDrawingBackgroundGradient() { 12844be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato return (mBackground != null && mBackgroundAlpha > 0.0f && mDrawBackground); 12854be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato } 12864be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato 12874be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato public void scrollTo (int x, int y) { 12884be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato super.scrollTo(x, y); 12894be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato syncChildrenLayersEnabledOnVisiblePages(); 12904be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato } 12914be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato 12924be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // This method just applies the value mChildrenLayersEnabled to all the pages that 12938e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy // will be rendered on the next frame. 12944be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // We do this because calling setChildrenLayersEnabled on a view that's not 12954be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // visible/rendered causes slowdowns on some graphics cards 12964be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato private void syncChildrenLayersEnabledOnVisiblePages() { 12974be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato if (mChildrenLayersEnabled) { 129831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project getVisiblePages(mTempVisiblePagesRange); 129931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int leftScreen = mTempVisiblePagesRange[0]; 1300aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung final int rightScreen = mTempVisiblePagesRange[1]; 130131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (leftScreen != -1 && rightScreen != -1) { 13027984c9496bcaeca23ee7fdecc4d4f1bb2467e0f2Bjorn Bringert for (int i = leftScreen; i <= rightScreen; i++) { 130331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project ViewGroup page = (ViewGroup) getPageAt(i); 130431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (page.getVisibility() == VISIBLE && 1305aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung page.getAlpha() > ViewConfiguration.ALPHA_THRESHOLD) { 130631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project ((ViewGroup)getPageAt(i)).setChildrenLayersEnabled(true); 13070142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 1308aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung } 130908ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy } 131031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 131131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 1312cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy 13134be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato @Override 13144be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato protected void dispatchDraw(Canvas canvas) { 13154be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato super.dispatchDraw(canvas); 13164be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato 13174be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato if (mInScrollArea && !LauncherApplication.isScreenLarge()) { 13184be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato final int width = getWidth(); 13198e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy final int height = getHeight(); 13208e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy final int pageHeight = getChildAt(0).getHeight(); 13218e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy 13224be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // Set the height of the outline to be the height of the page 13238e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy final int offset = (height - pageHeight - mPaddingTop - mPaddingBottom) / 2; 13244be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato final int paddingTop = mPaddingTop + offset; 13254be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato final int paddingBottom = mPaddingBottom + offset; 13268e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy 13274be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato final CellLayout leftPage = (CellLayout) getChildAt(mCurrentPage - 1); 13284be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato final CellLayout rightPage = (CellLayout) getChildAt(mCurrentPage + 1); 13294be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato 13304be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato if (leftPage != null && leftPage.getIsDragOverlapping()) { 13314be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato final Drawable d = getResources().getDrawable(R.drawable.page_hover_left_holo); 13324be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato d.setBounds(mScrollX, paddingTop, mScrollX + d.getIntrinsicWidth(), 13334be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato height - paddingBottom); 13344be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato d.draw(canvas); 13354be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato } else if (rightPage != null && rightPage.getIsDragOverlapping()) { 133631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final Drawable d = getResources().getDrawable(R.drawable.page_hover_right_holo); 133731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project d.setBounds(mScrollX + width - d.getIntrinsicWidth(), paddingTop, mScrollX + width, 13380280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka height - paddingBottom); 13390280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka d.draw(canvas); 13400280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 13410280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 134231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 13430280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 13440280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka @Override 13450280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) { 13460280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka if (!mLauncher.isAllAppsVisible()) { 13470280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka final Folder openFolder = getOpenFolder(); 13480280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka if (openFolder != null) { 134931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return openFolder.requestFocus(direction, previouslyFocusedRect); 135031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } else { 1351ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy return super.onRequestFocusInDescendants(direction, previouslyFocusedRect); 1352ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy } 1353ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy } 1354ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy return false; 1355ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy } 1356ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy 1357ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy @Override 1358ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy public int getDescendantFocusability() { 1359ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy if (isSmall()) { 1360ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy return ViewGroup.FOCUS_BLOCK_DESCENDANTS; 1361cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy } 1362cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy return super.getDescendantFocusability(); 1363ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy } 1364ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy 1365ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy @Override 13660280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka public void addFocusables(ArrayList<View> views, int direction, int focusableMode) { 1367cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy if (!mLauncher.isAllAppsVisible()) { 1368cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy final Folder openFolder = getOpenFolder(); 1369cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy if (openFolder != null) { 1370cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy openFolder.addFocusables(views, direction); 1371cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy } else { 1372cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy super.addFocusables(views, direction, focusableMode); 1373cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy } 1374cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy } 1375cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy } 1376cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy 1377cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy public boolean isSmall() { 1378cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy return mState == State.SMALL || mState == State.SPRING_LOADED; 1379cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy } 1380cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy 1381cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy void enableChildrenCache(int fromPage, int toPage) { 13828ae3a62e2e48dfb8f860c8b6e2c7e72b9595d7aaPatrick Dubroy if (fromPage > toPage) { 13838ae3a62e2e48dfb8f860c8b6e2c7e72b9595d7aaPatrick Dubroy final int temp = fromPage; 13848ae3a62e2e48dfb8f860c8b6e2c7e72b9595d7aaPatrick Dubroy fromPage = toPage; 13858ae3a62e2e48dfb8f860c8b6e2c7e72b9595d7aaPatrick Dubroy toPage = temp; 1386cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy } 1387f24312876b097e25cec922edbb58334ed234dcd7Patrick Dubroy 1388f24312876b097e25cec922edbb58334ed234dcd7Patrick Dubroy final int screenCount = getChildCount(); 1389f24312876b097e25cec922edbb58334ed234dcd7Patrick Dubroy 1390f24312876b097e25cec922edbb58334ed234dcd7Patrick Dubroy fromPage = Math.max(fromPage, 0); 1391f24312876b097e25cec922edbb58334ed234dcd7Patrick Dubroy toPage = Math.min(toPage, screenCount - 1); 1392f24312876b097e25cec922edbb58334ed234dcd7Patrick Dubroy 1393f24312876b097e25cec922edbb58334ed234dcd7Patrick Dubroy for (int i = fromPage; i <= toPage; i++) { 1394f24312876b097e25cec922edbb58334ed234dcd7Patrick Dubroy final CellLayout layout = (CellLayout) getChildAt(i); 1395cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy layout.setChildrenDrawnWithCacheEnabled(true); 1396f24312876b097e25cec922edbb58334ed234dcd7Patrick Dubroy layout.setChildrenDrawingCacheEnabled(true); 1397f24312876b097e25cec922edbb58334ed234dcd7Patrick Dubroy } 1398f24312876b097e25cec922edbb58334ed234dcd7Patrick Dubroy } 1399f24312876b097e25cec922edbb58334ed234dcd7Patrick Dubroy 1400f24312876b097e25cec922edbb58334ed234dcd7Patrick Dubroy void clearChildrenCache() { 1401f24312876b097e25cec922edbb58334ed234dcd7Patrick Dubroy final int screenCount = getChildCount(); 1402f24312876b097e25cec922edbb58334ed234dcd7Patrick Dubroy for (int i = 0; i < screenCount; i++) { 1403f24312876b097e25cec922edbb58334ed234dcd7Patrick Dubroy final CellLayout layout = (CellLayout) getChildAt(i); 1404f24312876b097e25cec922edbb58334ed234dcd7Patrick Dubroy layout.setChildrenDrawnWithCacheEnabled(false); 1405f24312876b097e25cec922edbb58334ed234dcd7Patrick Dubroy // In software mode, we don't want the items to continue to be drawn into bitmaps 1406f24312876b097e25cec922edbb58334ed234dcd7Patrick Dubroy if (!isHardwareAccelerated()) { 1407cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy layout.setChildrenDrawingCacheEnabled(false); 1408f24312876b097e25cec922edbb58334ed234dcd7Patrick Dubroy } 1409f24312876b097e25cec922edbb58334ed234dcd7Patrick Dubroy } 14108ae3a62e2e48dfb8f860c8b6e2c7e72b9595d7aaPatrick Dubroy } 1411cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy 1412cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy private void updateChildrenLayersEnabled() { 1413cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy boolean small = isSmall() || mIsSwitchingState; 1414cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy boolean dragging = mAnimatingViewIntoPlace || mIsDragOccuring; 1415cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy boolean enableChildrenLayers = small || dragging || isPageMoving(); 1416cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy 1417cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy if (enableChildrenLayers != mChildrenLayersEnabled) { 1418cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy mChildrenLayersEnabled = enableChildrenLayers; 1419cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy // calling setChildrenLayersEnabled on a view that's not visible/rendered 1420cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy // causes slowdowns on some graphics cards, so we only disable it here and leave 1421cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy // the enabling to dispatchDraw 1422cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy if (!enableChildrenLayers) { 1423cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy for (int i = 0; i < getPageCount(); i++) { 1424cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy ((ViewGroup)getChildAt(i)).setChildrenLayersEnabled(false); 1425cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy } 1426cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy } 14278ae3a62e2e48dfb8f860c8b6e2c7e72b9595d7aaPatrick Dubroy } 14288ae3a62e2e48dfb8f860c8b6e2c7e72b9595d7aaPatrick Dubroy } 14298ae3a62e2e48dfb8f860c8b6e2c7e72b9595d7aaPatrick Dubroy 14308ae3a62e2e48dfb8f860c8b6e2c7e72b9595d7aaPatrick Dubroy protected void onWallpaperTap(MotionEvent ev) { 14318ae3a62e2e48dfb8f860c8b6e2c7e72b9595d7aaPatrick Dubroy final int[] position = mTempCell; 14328ae3a62e2e48dfb8f860c8b6e2c7e72b9595d7aaPatrick Dubroy getLocationOnScreen(position); 14338ae3a62e2e48dfb8f860c8b6e2c7e72b9595d7aaPatrick Dubroy 14348ae3a62e2e48dfb8f860c8b6e2c7e72b9595d7aaPatrick Dubroy int pointerIndex = ev.getActionIndex(); 14358ae3a62e2e48dfb8f860c8b6e2c7e72b9595d7aaPatrick Dubroy position[0] += (int) ev.getX(pointerIndex); 1436cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy position[1] += (int) ev.getY(pointerIndex); 1437cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy 1438cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy mWallpaperManager.sendWallpaperCommand(getWindowToken(), 1439cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy ev.getAction() == MotionEvent.ACTION_UP 1440cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy ? WallpaperManager.COMMAND_TAP : WallpaperManager.COMMAND_SECONDARY_TAP, 1441cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy position[0], position[1], 0, null); 1442cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy } 1443cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy 1444cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy /* 1445cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy * This interpolator emulates the rate at which the perceived scale of an object changes 1446cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy * as its distance from a camera increases. When this interpolator is applied to a scale 1447cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy * animation on a view, it evokes the sense that the object is shrinking due to moving away 1448cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy * from the camera. 1449cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy */ 1450cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy static class ZInterpolator implements TimeInterpolator { 1451cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy private float focalLength; 1452cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy 1453cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy public ZInterpolator(float foc) { 1454cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy focalLength = foc; 1455cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy } 1456cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy 1457cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy public float getInterpolation(float input) { 1458cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy return (1.0f - focalLength / (focalLength + input)) / 1459cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy (1.0f - focalLength / (focalLength + 1.0f)); 1460cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy } 1461cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy } 1462cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy 1463cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy /* 1464cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy * The exact reverse of ZInterpolator. 1465cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy */ 146600acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato static class InverseZInterpolator implements TimeInterpolator { 146700acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato private ZInterpolator zInterpolator; 1468ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy public InverseZInterpolator(float foc) { 1469ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy zInterpolator = new ZInterpolator(foc); 1470ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy } 1471ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy public float getInterpolation(float input) { 1472c0e8fcae492730210b2b8b6d5bb3d65636bad245Michael Jurka return 1 - zInterpolator.getInterpolation(1 - input); 14730280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 14740280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 14750280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 1476d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka /* 14770280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * ZInterpolator compounded with an ease-out. 14780280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka */ 1479a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka static class ZoomOutInterpolator implements TimeInterpolator { 1480c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka private final DecelerateInterpolator decelerate = new DecelerateInterpolator(0.75f); 148131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private final ZInterpolator zInterpolator = new ZInterpolator(0.13f); 1482d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka 1483ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy public float getInterpolation(float input) { 1484ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy return decelerate.getInterpolation(zInterpolator.getInterpolation(input)); 148554fa3b95557c283976e8c1aa8a157b460b0b4513Patrick Dubroy } 148654fa3b95557c283976e8c1aa8a157b460b0b4513Patrick Dubroy } 148754fa3b95557c283976e8c1aa8a157b460b0b4513Patrick Dubroy 148854fa3b95557c283976e8c1aa8a157b460b0b4513Patrick Dubroy /* 148954fa3b95557c283976e8c1aa8a157b460b0b4513Patrick Dubroy * InvereZInterpolator compounded with an ease-out. 149054fa3b95557c283976e8c1aa8a157b460b0b4513Patrick Dubroy */ 149154fa3b95557c283976e8c1aa8a157b460b0b4513Patrick Dubroy static class ZoomInInterpolator implements TimeInterpolator { 149254fa3b95557c283976e8c1aa8a157b460b0b4513Patrick Dubroy private final InverseZInterpolator inverseZInterpolator = new InverseZInterpolator(0.35f); 149354fa3b95557c283976e8c1aa8a157b460b0b4513Patrick Dubroy private final DecelerateInterpolator decelerate = new DecelerateInterpolator(3.0f); 149454fa3b95557c283976e8c1aa8a157b460b0b4513Patrick Dubroy 149554fa3b95557c283976e8c1aa8a157b460b0b4513Patrick Dubroy public float getInterpolation(float input) { 149654fa3b95557c283976e8c1aa8a157b460b0b4513Patrick Dubroy return decelerate.getInterpolation(inverseZInterpolator.getInterpolation(input)); 149754fa3b95557c283976e8c1aa8a157b460b0b4513Patrick Dubroy } 1498cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy } 1499cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy 150054fa3b95557c283976e8c1aa8a157b460b0b4513Patrick Dubroy private final ZoomInInterpolator mZoomInInterpolator = new ZoomInInterpolator(); 1501cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy 1502cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy /* 150354fa3b95557c283976e8c1aa8a157b460b0b4513Patrick Dubroy * 150454fa3b95557c283976e8c1aa8a157b460b0b4513Patrick Dubroy * We call these methods (onDragStartedWithItemSpans/onDragStartedWithSize) whenever we 150554fa3b95557c283976e8c1aa8a157b460b0b4513Patrick Dubroy * start a drag in Launcher, regardless of whether the drag has ever entered the Workspace 150654fa3b95557c283976e8c1aa8a157b460b0b4513Patrick Dubroy * 150754fa3b95557c283976e8c1aa8a157b460b0b4513Patrick Dubroy * These methods mark the appropriate pages as accepting drops (which alters their visual 150854fa3b95557c283976e8c1aa8a157b460b0b4513Patrick Dubroy * appearance). 150954fa3b95557c283976e8c1aa8a157b460b0b4513Patrick Dubroy * 151054fa3b95557c283976e8c1aa8a157b460b0b4513Patrick Dubroy */ 15119438336724b4f8b54c7cdc49c5f01dd9568926ebPatrick Dubroy public void onDragStartedWithItem(View v) { 15129438336724b4f8b54c7cdc49c5f01dd9568926ebPatrick Dubroy final Canvas canvas = new Canvas(); 15139438336724b4f8b54c7cdc49c5f01dd9568926ebPatrick Dubroy 15149438336724b4f8b54c7cdc49c5f01dd9568926ebPatrick Dubroy // We need to add extra padding to the bitmap to make room for the glow effect 15159438336724b4f8b54c7cdc49c5f01dd9568926ebPatrick Dubroy final int bitmapPadding = HolographicOutlineHelper.MAX_OUTER_BLUR_RADIUS; 15169438336724b4f8b54c7cdc49c5f01dd9568926ebPatrick Dubroy 1517cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy // The outline is used to visualize where the item will land if dropped 15189438336724b4f8b54c7cdc49c5f01dd9568926ebPatrick Dubroy mDragOutline = createDragOutline(v, canvas, bitmapPadding); 15199438336724b4f8b54c7cdc49c5f01dd9568926ebPatrick Dubroy } 15209438336724b4f8b54c7cdc49c5f01dd9568926ebPatrick Dubroy 152154fa3b95557c283976e8c1aa8a157b460b0b4513Patrick Dubroy public void onDragStartedWithItem(PendingAddItemInfo info, Bitmap b, Paint alphaClipPaint) { 15229438336724b4f8b54c7cdc49c5f01dd9568926ebPatrick Dubroy final Canvas canvas = new Canvas(); 15239438336724b4f8b54c7cdc49c5f01dd9568926ebPatrick Dubroy 15249438336724b4f8b54c7cdc49c5f01dd9568926ebPatrick Dubroy // We need to add extra padding to the bitmap to make room for the glow effect 15259438336724b4f8b54c7cdc49c5f01dd9568926ebPatrick Dubroy final int bitmapPadding = HolographicOutlineHelper.MAX_OUTER_BLUR_RADIUS; 15269438336724b4f8b54c7cdc49c5f01dd9568926ebPatrick Dubroy 15279438336724b4f8b54c7cdc49c5f01dd9568926ebPatrick Dubroy int[] size = estimateItemSize(info.spanX, info.spanY, info, false); 15289438336724b4f8b54c7cdc49c5f01dd9568926ebPatrick Dubroy 15299438336724b4f8b54c7cdc49c5f01dd9568926ebPatrick Dubroy // The outline is used to visualize where the item will land if dropped 15309438336724b4f8b54c7cdc49c5f01dd9568926ebPatrick Dubroy mDragOutline = createDragOutline(b, canvas, bitmapPadding, size[0], size[1], alphaClipPaint); 153131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 1532cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy 1533cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy // we call this method whenever a drag and drop in Launcher finishes, even if Workspace was 1534ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy // never dragged over 1535ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy public void onDragStopped(boolean success) { 1536ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy // In the success case, DragController has already called onDragExit() 1537cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy if (!success) { 1538cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy doDragExit(null); 153931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 154031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 154131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 1542aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung public void exitWidgetResizeMode() { 1543aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung DragLayer dragLayer = mLauncher.getDragLayer(); 154408ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy dragLayer.clearAllResizeFrames(); 154508ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy } 1546d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka 154708ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy private void initAnimationArrays() { 1548a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung final int childCount = getChildCount(); 1549d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka if (mOldTranslationXs != null) return; 1550d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka mOldTranslationXs = new float[childCount]; 155131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mOldTranslationYs = new float[childCount]; 155231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mOldScaleXs = new float[childCount]; 155318014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka mOldScaleYs = new float[childCount]; 155418014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka mOldBackgroundAlphas = new float[childCount]; 15556569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy mOldBackgroundAlphaMultipliers = new float[childCount]; 1556c0e8fcae492730210b2b8b6d5bb3d65636bad245Michael Jurka mOldAlphas = new float[childCount]; 1557d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka mOldRotationYs = new float[childCount]; 15580280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka mNewTranslationXs = new float[childCount]; 15590280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka mNewTranslationYs = new float[childCount]; 1560440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy mNewScaleXs = new float[childCount]; 1561440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy mNewScaleYs = new float[childCount]; 1562440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy mNewBackgroundAlphas = new float[childCount]; 1563440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy mNewBackgroundAlphaMultipliers = new float[childCount]; 15646569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy mNewAlphas = new float[childCount]; 1565440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy mNewRotationYs = new float[childCount]; 1566440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy } 1567440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy 1568440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy public void changeState(State shrinkState) { 1569440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy changeState(shrinkState, true); 1570440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy } 1571440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy 1572440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy void changeState(final State state, boolean animated) { 1573440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy changeState(state, animated, 0); 1574440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy } 1575440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy 1576440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy void changeState(final State state, boolean animated, int delay) { 15770280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka if (mState == state) { 15780280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka return; 1579440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy } 1580440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy if (mFirstLayout) { 1581440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy // (mFirstLayout == "first layout has not happened yet") 1582440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy // cancel any pending shrinks that were set earlier 1583440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy mSwitchStateAfterFirstLayout = false; 1584440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy mStateAfterFirstLayout = state; 1585440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy return; 1586440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy } 1587440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy 1588440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy // Initialize animation arrays for the first time if necessary 1589440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy initAnimationArrays(); 1590440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy 1591440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy // Cancel any running transition animations 1592440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy if (mAnimator != null) mAnimator.cancel(); 15936569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy mAnimator = new AnimatorSet(); 1594a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung 1595580e27748137ff08599aa719d106b31215a28353Winson Chung // Stop any scrolling, move to the current page right away 1596580e27748137ff08599aa719d106b31215a28353Winson Chung setCurrentPage((mNextPage != INVALID_PAGE) ? mNextPage : mCurrentPage); 1597580e27748137ff08599aa719d106b31215a28353Winson Chung 1598580e27748137ff08599aa719d106b31215a28353Winson Chung final State oldState = mState; 1599580e27748137ff08599aa719d106b31215a28353Winson Chung final boolean oldStateIsNormal = (oldState == State.NORMAL); 1600580e27748137ff08599aa719d106b31215a28353Winson Chung final boolean oldStateIsSmall = (oldState == State.SMALL); 1601580e27748137ff08599aa719d106b31215a28353Winson Chung mState = state; 1602580e27748137ff08599aa719d106b31215a28353Winson Chung final boolean stateIsNormal = (state == State.NORMAL); 1603580e27748137ff08599aa719d106b31215a28353Winson Chung final boolean stateIsSpringLoaded = (state == State.SPRING_LOADED); 1604580e27748137ff08599aa719d106b31215a28353Winson Chung final boolean stateIsSmall = (state == State.SMALL); 1605580e27748137ff08599aa719d106b31215a28353Winson Chung float finalScaleFactor = 1.0f; 1606580e27748137ff08599aa719d106b31215a28353Winson Chung float finalBackgroundAlpha = stateIsSpringLoaded ? 1.0f : 0f; 1607580e27748137ff08599aa719d106b31215a28353Winson Chung float translationX = 0; 1608580e27748137ff08599aa719d106b31215a28353Winson Chung float translationY = 0; 1609580e27748137ff08599aa719d106b31215a28353Winson Chung boolean zoomIn = true; 1610580e27748137ff08599aa719d106b31215a28353Winson Chung 1611580e27748137ff08599aa719d106b31215a28353Winson Chung if (state != State.NORMAL) { 1612580e27748137ff08599aa719d106b31215a28353Winson Chung finalScaleFactor = mSpringLoadedShrinkFactor - (stateIsSmall ? 0.1f : 0); 1613580e27748137ff08599aa719d106b31215a28353Winson Chung if (oldStateIsNormal && stateIsSmall) { 1614580e27748137ff08599aa719d106b31215a28353Winson Chung zoomIn = false; 1615580e27748137ff08599aa719d106b31215a28353Winson Chung setLayoutScale(finalScaleFactor); 1616580e27748137ff08599aa719d106b31215a28353Winson Chung updateChildrenLayersEnabled(); 1617580e27748137ff08599aa719d106b31215a28353Winson Chung } else { 1618580e27748137ff08599aa719d106b31215a28353Winson Chung finalBackgroundAlpha = 1.0f; 1619a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung setLayoutScale(finalScaleFactor); 1620a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung } 1621a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung } else { 1622a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung setLayoutScale(1.0f); 162368846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung } 1624a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung 1625a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung final int duration = zoomIn ? 1626a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung getResources().getInteger(R.integer.config_workspaceUnshrinkTime) : 1627a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung getResources().getInteger(R.integer.config_appsCustomizeWorkspaceShrinkTime); 1628a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung for (int i = 0; i < getChildCount(); i++) { 1629a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung final CellLayout cl = (CellLayout) getChildAt(i); 1630a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung float rotation = 0f; 1631a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung float initialAlpha = cl.getAlpha(); 1632580e27748137ff08599aa719d106b31215a28353Winson Chung float finalAlphaMultiplierValue = 1f; 1633580e27748137ff08599aa719d106b31215a28353Winson Chung float finalAlpha = (!mFadeInAdjacentScreens || stateIsSpringLoaded || 1634580e27748137ff08599aa719d106b31215a28353Winson Chung (i == mCurrentPage)) ? 1f : 0f; 1635580e27748137ff08599aa719d106b31215a28353Winson Chung 1636580e27748137ff08599aa719d106b31215a28353Winson Chung // Determine the pages alpha during the state transition 1637580e27748137ff08599aa719d106b31215a28353Winson Chung if ((oldStateIsSmall && stateIsNormal) || 1638580e27748137ff08599aa719d106b31215a28353Winson Chung (oldStateIsNormal && stateIsSmall)) { 1639580e27748137ff08599aa719d106b31215a28353Winson Chung // To/from workspace - only show the current page unless the transition is not 1640580e27748137ff08599aa719d106b31215a28353Winson Chung // animated and the animation end callback below doesn't run 1641580e27748137ff08599aa719d106b31215a28353Winson Chung if (i == mCurrentPage || !animated) { 1642580e27748137ff08599aa719d106b31215a28353Winson Chung finalAlpha = 1f; 1643580e27748137ff08599aa719d106b31215a28353Winson Chung finalAlphaMultiplierValue = 0f; 1644580e27748137ff08599aa719d106b31215a28353Winson Chung } else { 1645580e27748137ff08599aa719d106b31215a28353Winson Chung initialAlpha = 0f; 1646580e27748137ff08599aa719d106b31215a28353Winson Chung finalAlpha = 0f; 1647580e27748137ff08599aa719d106b31215a28353Winson Chung } 1648a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung } 1649a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung 1650a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung // Update the rotation of the screen (don't apply rotation on Phone UI) 1651a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung if (LauncherApplication.isScreenLarge()) { 165268846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung if (i < mCurrentPage) { 165368846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung rotation = WORKSPACE_ROTATION; 165468846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung } else if (i > mCurrentPage) { 165568846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung rotation = -WORKSPACE_ROTATION; 165668846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung } 1657a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung } 165868846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung 165968846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung // If the screen is not xlarge, then don't rotate the CellLayouts 166068846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung // NOTE: If we don't update the side pages alpha, then we should not hide the side 166168846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung // pages. see unshrink(). 166268846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung if (LauncherApplication.isScreenLarge()) { 1663a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung translationX = getOffsetXForRotation(rotation, cl.getWidth(), cl.getHeight()); 166468846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung } 1665580e27748137ff08599aa719d106b31215a28353Winson Chung 1666a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung mOldAlphas[i] = initialAlpha; 1667a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung mNewAlphas[i] = finalAlpha; 1668a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung if (animated) { 1669a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung mOldTranslationXs[i] = cl.getTranslationX(); 1670580e27748137ff08599aa719d106b31215a28353Winson Chung mOldTranslationYs[i] = cl.getTranslationY(); 1671a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung mOldScaleXs[i] = cl.getScaleX(); 1672a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung mOldScaleYs[i] = cl.getScaleY(); 1673a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung mOldBackgroundAlphas[i] = cl.getBackgroundAlpha(); 1674a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung mOldBackgroundAlphaMultipliers[i] = cl.getBackgroundAlphaMultiplier(); 167555cef262f97749300c2f6e764da0b00cbcb78879Winson Chung mOldRotationYs[i] = cl.getRotationY(); 167668846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung 167768846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung mNewTranslationXs[i] = translationX; 167868846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung mNewTranslationYs[i] = translationY; 167968846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung mNewScaleXs[i] = finalScaleFactor; 168068846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung mNewScaleYs[i] = finalScaleFactor; 168168846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung mNewBackgroundAlphas[i] = finalBackgroundAlpha; 1682580e27748137ff08599aa719d106b31215a28353Winson Chung mNewBackgroundAlphaMultipliers[i] = finalAlphaMultiplierValue; 1683580e27748137ff08599aa719d106b31215a28353Winson Chung mNewRotationYs[i] = rotation; 1684580e27748137ff08599aa719d106b31215a28353Winson Chung } else { 1685580e27748137ff08599aa719d106b31215a28353Winson Chung cl.setTranslationX(translationX); 1686580e27748137ff08599aa719d106b31215a28353Winson Chung cl.setTranslationY(translationY); 1687580e27748137ff08599aa719d106b31215a28353Winson Chung cl.setScaleX(finalScaleFactor); 1688580e27748137ff08599aa719d106b31215a28353Winson Chung cl.setScaleY(finalScaleFactor); 1689580e27748137ff08599aa719d106b31215a28353Winson Chung cl.setBackgroundAlpha(finalBackgroundAlpha); 169068846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung cl.setBackgroundAlphaMultiplier(finalAlphaMultiplierValue); 169168846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung cl.setAlpha(finalAlpha); 169268846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung cl.setRotationY(rotation); 1693580e27748137ff08599aa719d106b31215a28353Winson Chung mChangeStateAnimationListener.onAnimationEnd(null); 169468846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung } 169568846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung } 169668846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung 169768846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung if (animated) { 169868846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung ValueAnimator animWithInterpolator = 169968846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung ValueAnimator.ofFloat(0f, 1f).setDuration(duration); 1700580e27748137ff08599aa719d106b31215a28353Winson Chung 170168846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung if (zoomIn) { 170268846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung animWithInterpolator.setInterpolator(mZoomInInterpolator); 170368846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung } 170468846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung 170568846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung animWithInterpolator.addListener(new AnimatorListenerAdapter() { 170668846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung @Override 170768846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung public void onAnimationEnd(android.animation.Animator animation) { 170868846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung // The above code to determine initialAlpha and finalAlpha will ensure that only 170968846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung // the current page is visible during (and subsequently, after) the transition 171068846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung // animation. If fade adjacent pages is disabled, then re-enable the page 171168846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung // visibility after the transition animation. 171268846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung if (!mFadeInAdjacentScreens && stateIsNormal && oldStateIsSmall) { 171368846fdce6c01bbe474bd0c8307e1ccaac161cbcWinson Chung for (int i = 0; i < getChildCount(); i++) { 171455cef262f97749300c2f6e764da0b00cbcb78879Winson Chung final CellLayout cl = (CellLayout) getChildAt(i); 1715a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung cl.setAlpha(1f); 1716a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung } 1717a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung } 1718580e27748137ff08599aa719d106b31215a28353Winson Chung } 1719a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung }); 1720a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung animWithInterpolator.addUpdateListener(new LauncherAnimatorUpdateListener() { 1721a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung public void onAnimationUpdate(float a, float b) { 1722a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung mTransitionProgress = b; 1723a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung if (b == 0f) { 1724a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung // an optimization, but not required 1725a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung return; 1726a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung } 1727a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung invalidate(); 1728a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung for (int i = 0; i < getChildCount(); i++) { 17294516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka final CellLayout cl = (CellLayout) getChildAt(i); 17304516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka cl.fastInvalidate(); 17314516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka cl.setFastTranslationX(a * mOldTranslationXs[i] + b * mNewTranslationXs[i]); 17324516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka cl.setFastTranslationY(a * mOldTranslationYs[i] + b * mNewTranslationYs[i]); 17334516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka cl.setFastScaleX(a * mOldScaleXs[i] + b * mNewScaleXs[i]); 17344516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka cl.setFastScaleY(a * mOldScaleYs[i] + b * mNewScaleYs[i]); 17354516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka cl.setFastBackgroundAlpha( 17364516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka a * mOldBackgroundAlphas[i] + b * mNewBackgroundAlphas[i]); 17374516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka cl.setBackgroundAlphaMultiplier(a * mOldBackgroundAlphaMultipliers[i] + 17384516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka b * mNewBackgroundAlphaMultipliers[i]); 17394516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka cl.setFastAlpha(a * mOldAlphas[i] + b * mNewAlphas[i]); 17404516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka } 17414516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka syncChildrenLayersEnabledOnVisiblePages(); 17424516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka } 17434516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka }); 17444516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka 1745d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka ValueAnimator rotationAnim = 17464516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka ValueAnimator.ofFloat(0f, 1f).setDuration(duration); 17474516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka rotationAnim.setInterpolator(new DecelerateInterpolator(2.0f)); 17484516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka rotationAnim.addUpdateListener(new LauncherAnimatorUpdateListener() { 17494516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka public void onAnimationUpdate(float a, float b) { 17504516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka if (b == 0f) { 17514516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka // an optimization, but not required 17524516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka return; 17534516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka } 17544516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka for (int i = 0; i < getChildCount(); i++) { 17554516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka final CellLayout cl = (CellLayout) getChildAt(i); 17564516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka cl.setFastRotationY(a * mOldRotationYs[i] + b * mNewRotationYs[i]); 17574516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka } 17584516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka } 17594516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka }); 17604516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka 17614516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka mAnimator.playTogether(animWithInterpolator, rotationAnim); 17624516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka mAnimator.setStartDelay(delay); 17634516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka // If we call this when we're not animated, onAnimationEnd is never called on 17644516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka // the listener; make sure we only use the listener when we're actually animating 17654516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka mAnimator.addListener(mChangeStateAnimationListener); 17664516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka mAnimator.start(); 17674516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka } 17684516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka 17694516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka if (stateIsSpringLoaded) { 17704516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka // Right now we're covered by Apps Customize 17714516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka // Show the background gradient immediately, so the gradient will 17724516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka // be showing once AppsCustomize disappears 17734516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka animateBackgroundGradient(getResources().getInteger( 17744516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka R.integer.config_appsCustomizeSpringLoadedBgAlpha) / 100f, false); 17750280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } else { 17760280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // Fade the background gradient away 17774516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka animateBackgroundGradient(0f, true); 17784516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka } 17794516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka syncChildrenLayersEnabledOnVisiblePages(); 17804516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka } 17814516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka 17824516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka /** 17834516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka * Draw the View v into the given Canvas. 17844516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka * 17854516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka * @param v the view to draw 17864516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka * @param destCanvas the canvas to draw on 17874516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka * @param padding the horizontal and vertical padding to use when drawing 17884516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka */ 17894516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka private void drawDragView(View v, Canvas destCanvas, int padding, boolean pruneToDrawable) { 17904516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka final Rect clipRect = mTempRect; 17914516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka v.getDrawingRect(clipRect); 17924516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka 17934516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka boolean textVisible = false; 17944516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka 17954516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka destCanvas.save(); 17964516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka if (v instanceof TextView && pruneToDrawable) { 17974516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka Drawable d = ((TextView) v).getCompoundDrawables()[1]; 17984516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka clipRect.set(0, 0, d.getIntrinsicWidth() + padding, d.getIntrinsicHeight() + padding); 17994516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka destCanvas.translate(padding / 2, padding / 2); 18004516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka d.draw(destCanvas); 18014516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka } else { 18024516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka if (v instanceof FolderIcon) { 18034516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka // For FolderIcons the text can bleed into the icon area, and so we need to 18044516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka // hide the text completely (which can't be achieved by clipping). 18054516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka if (((FolderIcon) v).getTextVisible()) { 18064516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka ((FolderIcon) v).setTextVisible(false); 18074516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka textVisible = true; 18084516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka } 18094516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka } else if (v instanceof BubbleTextView) { 18104516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka final BubbleTextView tv = (BubbleTextView) v; 18114516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka clipRect.bottom = tv.getExtendedPaddingTop() - (int) BubbleTextView.PADDING_V + 18124516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka tv.getLayout().getLineTop(0); 18134516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka } else if (v instanceof TextView) { 18144516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka final TextView tv = (TextView) v; 1815a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka clipRect.bottom = tv.getExtendedPaddingTop() - tv.getCompoundDrawablePadding() + 18164516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka tv.getLayout().getLineTop(0); 18174516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka } 18184516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka destCanvas.translate(-v.getScrollX() + padding / 2, -v.getScrollY() + padding / 2); 18194516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka destCanvas.clipRect(clipRect, Op.REPLACE); 18204516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka v.draw(destCanvas); 18214516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka 18224516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka // Restore text visibility of FolderIcon if necessary 18234516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka if (textVisible) { 18244516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka ((FolderIcon) v).setTextVisible(true); 18254516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka } 18264516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka } 18274516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka destCanvas.restore(); 18284516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka } 1829a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka 1830a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka /** 18310280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * Returns a new bitmap to show when the given View is being dragged around. 18324516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka * Responsibility for the bitmap is transferred to the caller. 1833a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka */ 1834a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka public Bitmap createDragBitmap(View v, Canvas canvas, int padding) { 1835a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka final int outlineColor = getResources().getColor(android.R.color.holo_blue_light); 18364516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka Bitmap b; 18374516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka 18384516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka if (v instanceof TextView) { 1839a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka Drawable d = ((TextView) v).getCompoundDrawables()[1]; 18404516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka b = Bitmap.createBitmap(d.getIntrinsicWidth() + padding, 18414516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka d.getIntrinsicHeight() + padding, Bitmap.Config.ARGB_8888); 18420280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } else { 18434516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka b = Bitmap.createBitmap( 18444516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka v.getWidth() + padding, v.getHeight() + padding, Bitmap.Config.ARGB_8888); 18454516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka } 18464516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka 18474516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka canvas.setBitmap(b); 18484516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka drawDragView(v, canvas, padding, true); 18494516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka mOutlineHelper.applyOuterBlur(b, canvas, outlineColor); 18504516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka canvas.drawColor(mDragViewMultiplyColor, PorterDuff.Mode.MULTIPLY); 18514516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka canvas.setBitmap(null); 18524516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka 18534516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka return b; 18544516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka } 18554516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka 18564516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka /** 18574516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka * Returns a new bitmap to be used as the object outline, e.g. to visualize the drop location. 18584516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka * Responsibility for the bitmap is transferred to the caller. 18594516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka */ 18604516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka private Bitmap createDragOutline(View v, Canvas canvas, int padding) { 18614516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka final int outlineColor = getResources().getColor(android.R.color.holo_blue_light); 18624516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka final Bitmap b = Bitmap.createBitmap( 18634516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka v.getWidth() + padding, v.getHeight() + padding, Bitmap.Config.ARGB_8888); 18644516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka 18650280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka canvas.setBitmap(b); 1866a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka drawDragView(v, canvas, padding, true); 1867a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka mOutlineHelper.applyMediumExpensiveOutlineWithBlur(b, canvas, outlineColor, outlineColor); 18684516c11039d77066281f69f9b5d30fdaf1bc05aeMichael Jurka canvas.setBitmap(null); 1869a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka return b; 1870a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka } 1871a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka 1872a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka /** 1873440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy * Returns a new bitmap to be used as the object outline, e.g. to visualize the drop location. 1874440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy * Responsibility for the bitmap is transferred to the caller. 1875d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka */ 1876d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka private Bitmap createDragOutline(Bitmap orig, Canvas canvas, int padding, int w, int h, 1877d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka Paint alphaClipPaint) { 1878d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka final int outlineColor = getResources().getColor(android.R.color.holo_blue_light); 1879d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka final Bitmap b = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); 1880d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka canvas.setBitmap(b); 1881d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka 1882d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka Rect src = new Rect(0, 0, orig.getWidth(), orig.getHeight()); 1883d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka float scaleFactor = Math.min((w - padding) / (float) orig.getWidth(), 1884d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka (h - padding) / (float) orig.getHeight()); 1885d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka int scaledWidth = (int) (scaleFactor * orig.getWidth()); 1886d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka int scaledHeight = (int) (scaleFactor * orig.getHeight()); 1887d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka Rect dst = new Rect(0, 0, scaledWidth, scaledHeight); 1888d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka 1889d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka // center the image 1890d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka dst.offset((w - scaledWidth) / 2, (h - scaledHeight) / 2); 1891d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka 1892d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka canvas.drawBitmap(orig, src, dst, null); 1893d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka mOutlineHelper.applyMediumExpensiveOutlineWithBlur(b, canvas, outlineColor, outlineColor, 1894d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka alphaClipPaint); 1895d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka canvas.setBitmap(null); 1896d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka 1897d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka return b; 1898d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka } 1899d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka 1900d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka /** 1901d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka * Creates a drag outline to represent a drop (that we don't have the actual information for 1902d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka * yet). May be changed in the future to alter the drop outline slightly depending on the 1903d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka * clip description mime data. 1904d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka */ 1905d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka private Bitmap createExternalDragOutline(Canvas canvas, int padding) { 1906d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka Resources r = getResources(); 1907d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka final int outlineColor = r.getColor(android.R.color.holo_blue_light); 1908a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka final int iconWidth = r.getDimensionPixelSize(R.dimen.workspace_cell_width); 1909d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka final int iconHeight = r.getDimensionPixelSize(R.dimen.workspace_cell_height); 1910d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka final int rectRadius = r.getDimensionPixelSize(R.dimen.external_drop_icon_rect_radius); 1911d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka final int inset = (int) (Math.min(iconWidth, iconHeight) * 0.2f); 1912d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka final Bitmap b = Bitmap.createBitmap( 1913d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka iconWidth + padding, iconHeight + padding, Bitmap.Config.ARGB_8888); 1914d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka 1915d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka canvas.setBitmap(b); 1916d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka canvas.drawRoundRect(new RectF(inset, inset, iconWidth - inset, iconHeight - inset), 1917d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka rectRadius, rectRadius, mExternalDragOutlinePaint); 1918d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka mOutlineHelper.applyMediumExpensiveOutlineWithBlur(b, canvas, outlineColor, outlineColor); 1919d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka canvas.setBitmap(null); 1920d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka return b; 1921d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka } 1922d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka 1923a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka void startDrag(CellLayout.CellInfo cellInfo) { 19241262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy View child = cellInfo.cell; 1925d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka 1926d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka // Make sure the drag was started by a long press as opposed to a long click. 1927d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka if (!child.isInTouchMode()) { 1928d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka return; 1929a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung } 1930d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka 19311262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy mDragInfo = cellInfo; 19326569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy child.setVisibility(GONE); 1933d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka 1934d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka child.clearFocus(); 1935d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka child.setPressed(false); 1936d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka 1937d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka final Canvas canvas = new Canvas(); 1938d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka 1939d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka // We need to add extra padding to the bitmap to make room for the glow effect 1940d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka final int bitmapPadding = HolographicOutlineHelper.MAX_OUTER_BLUR_RADIUS; 1941d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka 1942d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka // The outline is used to visualize where the item will land if dropped 19431262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy mDragOutline = createDragOutline(child, canvas, bitmapPadding); 1944976ebec9e31643d3513f9f0de2b433d9aa186ce9Patrick Dubroy beginDragShared(child, this); 194531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 194631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 1947aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung public void beginDragShared(View child, DragSource source) { 1948aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung Resources r = getResources(); 19496569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 19500280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // We need to add extra padding to the bitmap to make room for the glow effect 19516569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy final int bitmapPadding = HolographicOutlineHelper.MAX_OUTER_BLUR_RADIUS; 19521262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy 19531262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy // The drag bitmap follows the touch point around on the screen 19541262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy final Bitmap b = createDragBitmap(child, new Canvas(), bitmapPadding); 195508ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy 195631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int bmpWidth = b.getWidth(); 195731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 1958aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung mLauncher.getDragLayer().getLocationInDragLayer(child, mTempXY); 1959aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung final int dragLayerX = (int) mTempXY[0] + (child.getWidth() - bmpWidth) / 2; 196031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int dragLayerY = mTempXY[1] - bitmapPadding / 2; 196131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 1962aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung Point dragVisualizeOffset = null; 1963a34abf8c781485b788fddacb352d586bffca886cWinson Chung Rect dragRect = null; 1964a34abf8c781485b788fddacb352d586bffca886cWinson Chung if (child instanceof BubbleTextView || child instanceof PagedViewIcon) { 1965a34abf8c781485b788fddacb352d586bffca886cWinson Chung int iconSize = r.getDimensionPixelSize(R.dimen.app_icon_size); 1966a34abf8c781485b788fddacb352d586bffca886cWinson Chung int iconPaddingTop = r.getDimensionPixelSize(R.dimen.app_icon_padding_top); 1967a34abf8c781485b788fddacb352d586bffca886cWinson Chung int top = child.getPaddingTop(); 1968a34abf8c781485b788fddacb352d586bffca886cWinson Chung int left = (bmpWidth - iconSize) / 2; 1969a34abf8c781485b788fddacb352d586bffca886cWinson Chung int right = left + iconSize; 1970a34abf8c781485b788fddacb352d586bffca886cWinson Chung int bottom = top + iconSize; 19712b9ff37edb3f5965559b3ff7d37e418b4a2917a1Patrick Dubroy dragLayerY += top; 19722b9ff37edb3f5965559b3ff7d37e418b4a2917a1Patrick Dubroy // Note: The drag region is used to calculate drag layer offsets, but the 19732b9ff37edb3f5965559b3ff7d37e418b4a2917a1Patrick Dubroy // dragVisualizeOffset in addition to the dragRect (the size) to position the outline. 19742b9ff37edb3f5965559b3ff7d37e418b4a2917a1Patrick Dubroy dragVisualizeOffset = new Point(-bitmapPadding / 2, iconPaddingTop - bitmapPadding / 2); 19752b9ff37edb3f5965559b3ff7d37e418b4a2917a1Patrick Dubroy dragRect = new Rect(left, top, right, bottom); 19762b9ff37edb3f5965559b3ff7d37e418b4a2917a1Patrick Dubroy } else if (child instanceof FolderIcon) { 19772b9ff37edb3f5965559b3ff7d37e418b4a2917a1Patrick Dubroy int previewSize = r.getDimensionPixelSize(R.dimen.folder_preview_size); 19782b9ff37edb3f5965559b3ff7d37e418b4a2917a1Patrick Dubroy dragRect = new Rect(0, 0, child.getWidth(), previewSize); 19792b9ff37edb3f5965559b3ff7d37e418b4a2917a1Patrick Dubroy } 19802b9ff37edb3f5965559b3ff7d37e418b4a2917a1Patrick Dubroy 19810280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // Clear the pressed state if necessary 198255cef262f97749300c2f6e764da0b00cbcb78879Winson Chung if (child instanceof BubbleTextView) { 19832b9ff37edb3f5965559b3ff7d37e418b4a2917a1Patrick Dubroy BubbleTextView icon = (BubbleTextView) child; 19842b9ff37edb3f5965559b3ff7d37e418b4a2917a1Patrick Dubroy icon.clearPressedOrFocusedBackground(); 19850280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 19862b9ff37edb3f5965559b3ff7d37e418b4a2917a1Patrick Dubroy 19872b9ff37edb3f5965559b3ff7d37e418b4a2917a1Patrick Dubroy mDragController.startDrag(b, dragLayerX, dragLayerY, source, child.getTag(), 19882b9ff37edb3f5965559b3ff7d37e418b4a2917a1Patrick Dubroy DragController.DRAG_ACTION_MOVE, dragVisualizeOffset, dragRect); 19890280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka b.recycle(); 19904be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato } 19914be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato 1992aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung void addApplicationShortcut(ShortcutInfo info, CellLayout target, long container, int screen, 1993aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung int cellX, int cellY, boolean insertAtFirst, int intersectX, int intersectY) { 19940280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka View view = mLauncher.createShortcut(R.layout.application, target, (ShortcutInfo) info); 19950280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 19960280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka final int[] cellXY = new int[2]; 19970280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka target.findCellForSpanThatIntersects(cellXY, 1, 1, intersectX, intersectY); 19980280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka addInScreen(view, container, screen, cellXY[0], cellXY[1], 1, 1, insertAtFirst); 19990280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka LauncherModel.addOrMoveItemInDatabase(mLauncher, info, container, screen, cellXY[0], 20000280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka cellXY[1]); 20010280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 20020280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 20030280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka public boolean transitionStateShouldAllowDrop() { 200455cef262f97749300c2f6e764da0b00cbcb78879Winson Chung return (!isSwitchingState() || mTransitionProgress > 0.5f); 20050280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 20060280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 20070280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka /** 20080280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * {@inheritDoc} 20090280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka */ 20100280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka public boolean acceptDrop(DragObject d) { 20110280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // If it's an external drop (e.g. from All Apps), check if it should be accepted 20120280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka if (d.dragSource != this) { 20130280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // Don't accept the drop if we're not over a screen at time of drop 20140280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka if (mDragTargetLayout == null) { 20150280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka return false; 201618014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka } 20170280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka if (!transitionStateShouldAllowDrop()) return false; 20180280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 20190280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka mDragViewVisualCenter = getDragViewVisualCenter(d.x, d.y, d.xOffset, d.yOffset, 20200280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka d.dragView, mDragViewVisualCenter); 202131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 202231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // We want the point to be mapped to the dragTarget. 2023af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka if (mLauncher.isHotseatLayout(mDragTargetLayout)) { 202431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mapPointFromSelfToSibling(mLauncher.getHotseat(), mDragViewVisualCenter); 202531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } else { 202631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mapPointFromSelfToChild(mDragTargetLayout, mDragViewVisualCenter, null); 202731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 2028e48e7c1a62e6a367803dca62c8fce9de57121b0fJoe Onorato 202931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int spanX = 1; 2030aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung int spanY = 1; 203131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project View ignoreView = null; 2032aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung if (mDragInfo != null) { 2033aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung final CellLayout.CellInfo dragCellInfo = mDragInfo; 203431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project spanX = dragCellInfo.spanX; 203531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project spanY = dragCellInfo.spanY; 203631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project ignoreView = dragCellInfo.cell; 2037c9a961952d1a057029874f8426b90181f6876034Michael Jurka } else { 2038af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka final ItemInfo dragInfo = (ItemInfo) d.dragInfo; 203931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project spanX = dragInfo.spanX; 20400280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka spanY = dragInfo.spanY; 204131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 204231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 20436569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy mTargetCell = findNearestArea((int) mDragViewVisualCenter[0], 20446569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy (int) mDragViewVisualCenter[1], spanX, spanY, mDragTargetLayout, mTargetCell); 20450280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka if (willCreateUserFolder((ItemInfo) d.dragInfo, mDragTargetLayout, mTargetCell, true)) { 20466569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy return true; 2047bbc60d8e79416e37cbede55c159bf6aaa6c171d5Winson Chung } 2048bbc60d8e79416e37cbede55c159bf6aaa6c171d5Winson Chung if (willAddToExistingUserFolder((ItemInfo) d.dragInfo, mDragTargetLayout, 2049aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung mTargetCell)) { 2050aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung return true; 2051aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung } 205218014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka 20536569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy // Don't accept the drop if there's no room for the item 205431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (!mDragTargetLayout.findCellForSpanIgnoring(null, spanX, spanY, ignoreView)) { 2055af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka // Don't show the message if we are dropping on the AllApps button and the hotseat 20560280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // is full 2057aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung if (mTargetCell != null && mLauncher.isHotseatLayout(mDragTargetLayout)) { 2058af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka Hotseat hotseat = mLauncher.getHotseat(); 205931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (Hotseat.isAllAppsButtonRank( 2060aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung hotseat.getOrderInHotseat(mTargetCell[0], mTargetCell[1]))) { 206170864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey return false; 206270864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey } 206370864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey } 206470864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey 206570864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey mLauncher.showOutOfSpaceMessage(); 2066d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka return false; 2067d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka } 20680142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 206970864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey return true; 207070864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey } 207131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 207270864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey boolean willCreateUserFolder(ItemInfo info, CellLayout target, int[] targetCell, 20730280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka boolean considerTimeout) { 20740280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka View dropOverView = target.getChildAt(targetCell[0], targetCell[1]); 20750280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 20760280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka boolean hasntMoved = false; 20770280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka if (mDragInfo != null) { 20780280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka CellLayout cellParent = getParentCellLayoutForView(mDragInfo.cell); 20790280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka hasntMoved = (mDragInfo.cellX == targetCell[0] && 20800280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka mDragInfo.cellY == targetCell[1]) && (cellParent == target); 20810280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 20820280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 208370864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey if (dropOverView == null || hasntMoved || (considerTimeout && !mCreateUserFolderOnDrop)) { 208470864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey return false; 20856a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka } 208670864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey 20876569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy boolean aboveShortcut = (dropOverView.getTag() instanceof ShortcutInfo); 20885f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka boolean willBecomeShortcut = 20895f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION || 20906569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy info.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT); 209170864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey 20920280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka return (aboveShortcut && willBecomeShortcut); 2093fc9f07d42511231a26fa182c32e2efaa0f41d478Michael Jurka } 209470864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey 2095aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung boolean willAddToExistingUserFolder(Object dragInfo, CellLayout target, int[] targetCell) { 20968f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy View dropOverView = target.getChildAt(targetCell[0], targetCell[1]); 20978f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy if (dropOverView instanceof FolderIcon) { 20988f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy FolderIcon fi = (FolderIcon) dropOverView; 20998f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy if (fi.acceptDrop(dragInfo)) { 21000142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka return true; 21018f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy } 21028f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy } 210331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return false; 210431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 210531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 210631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project boolean createUserFolderIfNecessary(View newView, long container, CellLayout target, 210700acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato int[] targetCell, boolean external, DragView dragView, Runnable postAnimationRunnable) { 210800acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato View v = target.getChildAt(targetCell[0], targetCell[1]); 210931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project boolean hasntMoved = false; 211031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (mDragInfo != null) { 211131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project CellLayout cellParent = getParentCellLayoutForView(mDragInfo.cell); 2112aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung hasntMoved = (mDragInfo.cellX == targetCell[0] && 211331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mDragInfo.cellY == targetCell[1]) && (cellParent == target); 211431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 211531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 211600acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato if (v == null || hasntMoved || !mCreateUserFolderOnDrop) return false; 211700acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato mCreateUserFolderOnDrop = false; 211800acb123c5100f06b8e89e8ec8978ebafc6f6d26Joe Onorato final int screen = (targetCell == null) ? mDragInfo.screen : indexOfChild(target); 2119aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 212031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project boolean aboveShortcut = (v.getTag() instanceof ShortcutInfo); 2121ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy boolean willBecomeShortcut = (newView.getTag() instanceof ShortcutInfo); 2122cd68ff5b88de9b5136ff5a9ef698e4db2fc5db66Patrick Dubroy 212331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (aboveShortcut && willBecomeShortcut) { 212431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project ShortcutInfo sourceInfo = (ShortcutInfo) newView.getTag(); 21254be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato ShortcutInfo destInfo = (ShortcutInfo) v.getTag(); 212631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // if the drag started here, we need to remove it from the workspace 212731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (!external) { 212831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project getParentCellLayoutForView(mDragInfo.cell).removeView(mDragInfo.cell); 21290280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 21300280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 21310280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka Rect folderLocation = new Rect(); 21320280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka float scale = mLauncher.getDragLayer().getDescendantRectRelativeToSelf(v, folderLocation); 21330142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka target.removeView(v); 21340142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 21350142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka FolderIcon fi = 21360142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka mLauncher.addFolder(target, container, screen, targetCell[0], targetCell[1]); 21370142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka destInfo.cellX = -1; 21380142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka destInfo.cellY = -1; 21390142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka sourceInfo.cellX = -1; 214031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project sourceInfo.cellY = -1; 2141c0e8fcae492730210b2b8b6d5bb3d65636bad245Michael Jurka 21420142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka // If the dragView is null, we can't animate 214331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project boolean animate = dragView != null; 214431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (animate) { 214531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project fi.performCreateAnimation(destInfo, v, sourceInfo, dragView, folderLocation, scale, 21460142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka postAnimationRunnable); 214731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } else { 2148c0e8fcae492730210b2b8b6d5bb3d65636bad245Michael Jurka fi.addItem(destInfo); 21490142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka fi.addItem(sourceInfo); 215031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 215131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return true; 2152138a04170d964da9cdec228e95b976875ae52481Karl Rosaen } 21531262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy return false; 21541262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy } 2155d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka 2156d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka boolean addToExistingFolderIfNecessary(View newView, CellLayout target, int[] targetCell, 215754fa3b95557c283976e8c1aa8a157b460b0b4513Patrick Dubroy DragObject d, boolean external) { 215854fa3b95557c283976e8c1aa8a157b460b0b4513Patrick Dubroy View dropOverView = target.getChildAt(targetCell[0], targetCell[1]); 215954fa3b95557c283976e8c1aa8a157b460b0b4513Patrick Dubroy if (dropOverView instanceof FolderIcon) { 216054fa3b95557c283976e8c1aa8a157b460b0b4513Patrick Dubroy FolderIcon fi = (FolderIcon) dropOverView; 216154fa3b95557c283976e8c1aa8a157b460b0b4513Patrick Dubroy if (fi.acceptDrop(d.dragInfo)) { 216254fa3b95557c283976e8c1aa8a157b460b0b4513Patrick Dubroy fi.onDrop(d); 216354fa3b95557c283976e8c1aa8a157b460b0b4513Patrick Dubroy 21641262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy // if the drag started here, we need to remove it from the workspace 21650207c522472d7252f146f4d39efa456ca5248c6bPatrick Dubroy if (!external) { 21660207c522472d7252f146f4d39efa456ca5248c6bPatrick Dubroy getParentCellLayoutForView(mDragInfo.cell).removeView(mDragInfo.cell); 21670207c522472d7252f146f4d39efa456ca5248c6bPatrick Dubroy } 21680207c522472d7252f146f4d39efa456ca5248c6bPatrick Dubroy return true; 2169d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka } 21701262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy } 21711262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy return false; 21721262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy } 217308ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy 217408ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy public void onDrop(DragObject d) { 217508ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy mDragViewVisualCenter = getDragViewVisualCenter(d.x, d.y, d.xOffset, d.yOffset, d.dragView, 217608ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy mDragViewVisualCenter); 217708ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy 217808ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy // We want the point to be mapped to the dragTarget. 217908ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy if (mDragTargetLayout != null) { 21801262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy if (mLauncher.isHotseatLayout(mDragTargetLayout)) { 21811262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy mapPointFromSelfToSibling(mLauncher.getHotseat(), mDragViewVisualCenter); 2182d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka } else { 2183d718d6a7ba424b600052a147e5633a201a04ccb7Michael Jurka mapPointFromSelfToChild(mDragTargetLayout, mDragViewVisualCenter, null); 218454fa3b95557c283976e8c1aa8a157b460b0b4513Patrick Dubroy } 218508ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy } 21861262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy 21871262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy CellLayout dropTargetLayout = mDragTargetLayout; 21881262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy 218931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int snapScreen = -1; 2190dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka if (d.dragSource != this) { 219131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int[] touchXY = new int[] { (int) mDragViewVisualCenter[0], 219231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project (int) mDragViewVisualCenter[1] }; 219331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project onDropExternal(touchXY, d.dragInfo, dropTargetLayout, false, d); 219431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } else if (mDragInfo != null) { 219531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final View cell = mDragInfo.cell; 219631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 219731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (dropTargetLayout != null) { 219831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // Move internally 2199aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung boolean hasMovedLayouts = (getParentCellLayoutForView(cell) != dropTargetLayout); 220031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project boolean hasMovedIntoHotseat = mLauncher.isHotseatLayout(dropTargetLayout); 220131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project long container = hasMovedIntoHotseat ? 220231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project LauncherSettings.Favorites.CONTAINER_HOTSEAT : 220331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project LauncherSettings.Favorites.CONTAINER_DESKTOP; 220431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int screen = (mTargetCell[0] < 0) ? 220531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mDragInfo.screen : indexOfChild(dropTargetLayout); 220631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int spanX = mDragInfo != null ? mDragInfo.spanX : 1; 220731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int spanY = mDragInfo != null ? mDragInfo.spanY : 1; 220831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // First we find the cell nearest to point at which the item is 220931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // dropped, without any consideration to whether there is an item there. 221031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mTargetCell = findNearestArea((int) mDragViewVisualCenter[0], (int) 221131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mDragViewVisualCenter[1], spanX, spanY, dropTargetLayout, mTargetCell); 221231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // If the item being dropped is a shortcut and the nearest drop 221331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // cell also contains a shortcut, then create a folder with the two shortcuts. 221431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (!mInScrollArea && createUserFolderIfNecessary(cell, container, 221531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project dropTargetLayout, mTargetCell, false, d.dragView, null)) { 221631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return; 221731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 221831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 221931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (addToExistingFolderIfNecessary(cell, dropTargetLayout, mTargetCell, d, false)) { 222031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return; 222131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 222231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 222331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // Aside from the special case where we're dropping a shortcut onto a shortcut, 222464e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato // we need to find the nearest cell location that is vacant 2225dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka mTargetCell = findNearestVacantArea((int) mDragViewVisualCenter[0], 22265c16f3ecd6b47bff3abbe40deb3d39c66a3b0012Romain Guy (int) mDragViewVisualCenter[1], mDragInfo.spanX, mDragInfo.spanY, cell, 2227629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy dropTargetLayout, mTargetCell); 2228574d20ec84551370987dde530c27ec493bdef564Romain Guy 222964e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato if (mCurrentPage != screen && !hasMovedIntoHotseat) { 223064e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato snapScreen = screen; 223164e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato snapToPage(screen); 223264e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato } 223364e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato 223464e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato if (mTargetCell[0] >= 0 && mTargetCell[1] >= 0) { 2235dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka if (hasMovedLayouts) { 223631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // Reparent the view 2237629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy getParentCellLayoutForView(cell).removeView(cell); 2238629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy addInScreen(cell, container, screen, mTargetCell[0], mTargetCell[1], 2239629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy mDragInfo.spanX, mDragInfo.spanY); 2240629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy } 2241629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy 2242629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy // update the item's position after drop 2243aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung final ItemInfo info = (ItemInfo) cell.getTag(); 2244629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy CellLayout.LayoutParams lp = (CellLayout.LayoutParams) cell.getLayoutParams(); 2245629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy dropTargetLayout.onMove(cell, mTargetCell[0], mTargetCell[1]); 2246629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy lp.cellX = mTargetCell[0]; 2247629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy lp.cellY = mTargetCell[1]; 2248aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung cell.setId(LauncherModel.getCellLayoutChildId(container, mDragInfo.screen, 22490589f0f66ce498512c6ee47482c649d88294c9d0Joe Onorato mTargetCell[0], mTargetCell[1], mDragInfo.spanX, mDragInfo.spanY)); 22500589f0f66ce498512c6ee47482c649d88294c9d0Joe Onorato 2251629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy if (container != LauncherSettings.Favorites.CONTAINER_HOTSEAT && 2252629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy cell instanceof LauncherAppWidgetHostView) { 2253aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung final CellLayout cellLayout = dropTargetLayout; 225464e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato // We post this call so that the widget has a chance to be placed 225564e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato // in its final location 225664e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato 225764e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato final LauncherAppWidgetHostView hostView = (LauncherAppWidgetHostView) cell; 225864e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato AppWidgetProviderInfo pinfo = hostView.getAppWidgetInfo(); 225964e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato if (pinfo.resizeMode != AppWidgetProviderInfo.RESIZE_NONE) { 226064e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato final Runnable resizeRunnable = new Runnable() { 2261629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy public void run() { 2262629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy DragLayer dragLayer = mLauncher.getDragLayer(); 2263629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy dragLayer.addResizeFrame(info, hostView, cellLayout); 22640589f0f66ce498512c6ee47482c649d88294c9d0Joe Onorato } 22650589f0f66ce498512c6ee47482c649d88294c9d0Joe Onorato }; 2266629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy post(new Runnable() { 2267629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy public void run() { 2268aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung if (!isPageMoving()) { 2269629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy resizeRunnable.run(); 22700589f0f66ce498512c6ee47482c649d88294c9d0Joe Onorato } else { 2271629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy mDelayedResizeRunnable = resizeRunnable; 2272629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy } 2273aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung } 227464e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato }); 227564e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato } 227664e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato } 227764e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato 227873013bf94f49ffbacba2b8300f6a2dd4eeebbd13Brad Fitzpatrick LauncherModel.moveItemInDatabase(mLauncher, info, container, screen, lp.cellX, 227964e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato lp.cellY); 228064e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato } 228164e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato } 2282629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy 2283629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy final CellLayout parent = (CellLayout) cell.getParent().getParent(); 2284aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 2285629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy // Prepare it to be animated into its new position 2286629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy // This must be called after the view has been re-parented 2287629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy final Runnable disableHardwareLayersRunnable = new Runnable() { 2288aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung @Override 2289aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung public void run() { 2290629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy mAnimatingViewIntoPlace = false; 2291629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy updateChildrenLayersEnabled(); 2292629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy } 2293629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy }; 2294629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy mAnimatingViewIntoPlace = true; 2295629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy if (d.dragView.hasDrawn()) { 2296629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy int duration = snapScreen < 0 ? -1 : ADJACENT_SCREEN_DROP_DURATION; 2297f11079b11e98912ed56546eaa300efd06c6eb917Joe Onorato setFinalScrollForPageChange(snapScreen); 229864e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato mLauncher.getDragLayer().animateViewIntoPosition(d.dragView, cell, duration, 229964e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato disableHardwareLayersRunnable); 230064e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato resetFinalScrollForPageChange(snapScreen); 2301aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung } else { 230264e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato cell.setVisibility(VISIBLE); 230364e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato } 2304629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy parent.onDropChild(cell); 2305629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy } 2306629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy } 2307629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy 2308629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy public void setFinalScrollForPageChange(int screen) { 2309e1cc6c3745c9ba721b6ab888d74c9d9e1d13ea6aDaniel Sandler if (screen >= 0) { 231064e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato mSavedScrollX = getScrollX(); 231164e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato CellLayout cl = (CellLayout) getChildAt(screen); 231264e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato mSavedTranslationX = cl.getTranslationX(); 2313aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung mSavedRotationY = cl.getRotationY(); 231464e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato final int newX = getChildOffset(screen) - getRelativeChildOffset(screen); 231564e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato setScrollX(newX); 2316629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy cl.setTranslationX(0f); 2317574d20ec84551370987dde530c27ec493bdef564Romain Guy cl.setRotationY(0f); 2318574d20ec84551370987dde530c27ec493bdef564Romain Guy } 2319aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung } 2320629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy 2321629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy public void resetFinalScrollForPageChange(int screen) { 2322629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy if (screen >= 0) { 2323629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy CellLayout cl = (CellLayout) getChildAt(screen); 2324629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy setScrollX(mSavedScrollX); 2325629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy cl.setTranslationX(mSavedTranslationX); 2326629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy cl.setRotationY(mSavedRotationY); 2327574d20ec84551370987dde530c27ec493bdef564Romain Guy } 2328aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung } 2329629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy 2330629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy public void getViewLocationRelativeToSelf(View v, int[] location) { 2331629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy getLocationInWindow(location); 23325c16f3ecd6b47bff3abbe40deb3d39c66a3b0012Romain Guy int x = location[0]; 233331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int y = location[1]; 2334629de3ef739883c0962423cc0c3a26299f162d3dRomain Guy 233531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project v.getLocationInWindow(location); 233631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int vX = location[0]; 2337f96811cdf564469a7a654a0c876288c9fd14f35eThe Android Open Source Project int vY = location[1]; 233864e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato 2339dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka location[0] = vX - x; 2340dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka location[1] = vY - y; 2341f96811cdf564469a7a654a0c876288c9fd14f35eThe Android Open Source Project } 2342f96811cdf564469a7a654a0c876288c9fd14f35eThe Android Open Source Project 2343f96811cdf564469a7a654a0c876288c9fd14f35eThe Android Open Source Project public void onDragEnter(DragObject d) { 2344f96811cdf564469a7a654a0c876288c9fd14f35eThe Android Open Source Project if (mDragTargetLayout != null) { 2345f96811cdf564469a7a654a0c876288c9fd14f35eThe Android Open Source Project mDragTargetLayout.setIsDragOverlapping(false); 23460589f0f66ce498512c6ee47482c649d88294c9d0Joe Onorato mDragTargetLayout.onDragExit(); 23470589f0f66ce498512c6ee47482c649d88294c9d0Joe Onorato } 2348f96811cdf564469a7a654a0c876288c9fd14f35eThe Android Open Source Project mDragTargetLayout = getCurrentDropLayout(); 2349f96811cdf564469a7a654a0c876288c9fd14f35eThe Android Open Source Project mDragTargetLayout.setIsDragOverlapping(true); 2350f96811cdf564469a7a654a0c876288c9fd14f35eThe Android Open Source Project mDragTargetLayout.onDragEnter(); 2351f96811cdf564469a7a654a0c876288c9fd14f35eThe Android Open Source Project 2352f96811cdf564469a7a654a0c876288c9fd14f35eThe Android Open Source Project // Because we don't have space in the Phone UI (the CellLayouts run to the edge) we 2353f96811cdf564469a7a654a0c876288c9fd14f35eThe Android Open Source Project // don't need to show the outlines 235464e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato if (LauncherApplication.isScreenLarge()) { 235564e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato showOutlines(); 2356aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung } 235764e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato } 235864e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato 235964e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato private void doDragExit(DragObject d) { 236064e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato // Clean up folders 236164e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato cleanupFolderCreation(d); 236264e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato 236364e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato // Reset the scroll area and previous drag target 236464e6be78dc72e1a89fe8fb95c502586f9260df28Joe Onorato onResetScrollArea(); 2365f96811cdf564469a7a654a0c876288c9fd14f35eThe Android Open Source Project 2366f96811cdf564469a7a654a0c876288c9fd14f35eThe Android Open Source Project if (mDragTargetLayout != null) { 2367f96811cdf564469a7a654a0c876288c9fd14f35eThe Android Open Source Project mDragTargetLayout.setIsDragOverlapping(false); 2368f96811cdf564469a7a654a0c876288c9fd14f35eThe Android Open Source Project mDragTargetLayout.onDragExit(); 2369f96811cdf564469a7a654a0c876288c9fd14f35eThe Android Open Source Project } 2370f96811cdf564469a7a654a0c876288c9fd14f35eThe Android Open Source Project mLastDragOverView = null; 237114f122bf847e50a3e7730ccbe57abc25d086a01bJoe Onorato mSpringLoadedDragController.cancel(); 2372c0e8fcae492730210b2b8b6d5bb3d65636bad245Michael Jurka 2373c0e8fcae492730210b2b8b6d5bb3d65636bad245Michael Jurka if (!mIsPageMoving) { 2374c0e8fcae492730210b2b8b6d5bb3d65636bad245Michael Jurka hideOutlines(); 2375c0e8fcae492730210b2b8b6d5bb3d65636bad245Michael Jurka } 2376c45b16862918a0c6c253bba12032165b030565afJoe Onorato } 23770142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 2378c45b16862918a0c6c253bba12032165b030565afJoe Onorato public void onDragExit(DragObject d) { 23790142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka doDragExit(d); 238031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 238131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 23828a73c51ee87b6d9b12daba188034889caf7a905bRomain Guy public DropTarget getDropTargetDelegate(DragObject d) { 23838a73c51ee87b6d9b12daba188034889caf7a905bRomain Guy return null; 23848a73c51ee87b6d9b12daba188034889caf7a905bRomain Guy } 23850142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 23860142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka /** 23878a73c51ee87b6d9b12daba188034889caf7a905bRomain Guy * Tests to see if the drop will be accepted by Launcher, and if so, includes additional data 23888a73c51ee87b6d9b12daba188034889caf7a905bRomain Guy * in the returned structure related to the widgets that match the drop (or a null list if it is 23890142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka * a shortcut drop). If the drop is not accepted then a null structure is returned. 23900142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka */ 23910142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka private Pair<Integer, List<WidgetMimeTypeHandlerData>> validateDrag(DragEvent event) { 239231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final LauncherModel model = mLauncher.getModel(); 23930142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka final ClipDescription desc = event.getClipDescription(); 23940142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka final int mimeTypeCount = desc.getMimeTypeCount(); 239531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int i = 0; i < mimeTypeCount; ++i) { 23960142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka final String mimeType = desc.getMimeType(i); 239731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (mimeType.equals(InstallShortcutReceiver.SHORTCUT_MIMETYPE)) { 2398 return new Pair<Integer, List<WidgetMimeTypeHandlerData>>(i, null); 2399 } else { 2400 final List<WidgetMimeTypeHandlerData> widgets = 2401 model.resolveWidgetsForMimeType(mContext, mimeType); 2402 if (widgets.size() > 0) { 2403 return new Pair<Integer, List<WidgetMimeTypeHandlerData>>(i, widgets); 2404 } 2405 } 2406 } 2407 return null; 2408 } 2409 2410 /** 2411 * Global drag and drop handler 2412 */ 2413 @Override 2414 public boolean onDragEvent(DragEvent event) { 2415 final ClipDescription desc = event.getClipDescription(); 2416 final CellLayout layout = (CellLayout) getChildAt(mCurrentPage); 2417 final int[] pos = new int[2]; 2418 layout.getLocationOnScreen(pos); 2419 // We need to offset the drag coordinates to layout coordinate space 2420 final int x = (int) event.getX() - pos[0]; 2421 final int y = (int) event.getY() - pos[1]; 2422 2423 switch (event.getAction()) { 2424 case DragEvent.ACTION_DRAG_STARTED: { 2425 // Validate this drag 2426 Pair<Integer, List<WidgetMimeTypeHandlerData>> test = validateDrag(event); 2427 if (test != null) { 2428 boolean isShortcut = (test.second == null); 2429 if (isShortcut) { 2430 // Check if we have enough space on this screen to add a new shortcut 2431 if (!layout.findCellForSpan(pos, 1, 1)) { 2432 mLauncher.showOutOfSpaceMessage(); 2433 return false; 2434 } 2435 } 2436 } else { 2437 // Show error message if we couldn't accept any of the items 2438 Toast.makeText(mContext, mContext.getString(R.string.external_drop_widget_error), 2439 Toast.LENGTH_SHORT).show(); 2440 return false; 2441 } 2442 2443 // Create the drag outline 2444 // We need to add extra padding to the bitmap to make room for the glow effect 2445 final Canvas canvas = new Canvas(); 2446 final int bitmapPadding = HolographicOutlineHelper.MAX_OUTER_BLUR_RADIUS; 2447 mDragOutline = createExternalDragOutline(canvas, bitmapPadding); 2448 2449 // Show the current page outlines to indicate that we can accept this drop 2450 showOutlines(); 2451 layout.onDragEnter(); 2452 layout.visualizeDropLocation(null, mDragOutline, x, y, 1, 1, null, null); 2453 2454 return true; 2455 } 2456 case DragEvent.ACTION_DRAG_LOCATION: 2457 // Visualize the drop location 2458 layout.visualizeDropLocation(null, mDragOutline, x, y, 1, 1, null, null); 2459 return true; 2460 case DragEvent.ACTION_DROP: { 2461 // Try and add any shortcuts 2462 final LauncherModel model = mLauncher.getModel(); 2463 final ClipData data = event.getClipData(); 2464 2465 // We assume that the mime types are ordered in descending importance of 2466 // representation. So we enumerate the list of mime types and alert the 2467 // user if any widgets can handle the drop. Only the most preferred 2468 // representation will be handled. 2469 pos[0] = x; 2470 pos[1] = y; 2471 Pair<Integer, List<WidgetMimeTypeHandlerData>> test = validateDrag(event); 2472 if (test != null) { 2473 final int index = test.first; 2474 final List<WidgetMimeTypeHandlerData> widgets = test.second; 2475 final boolean isShortcut = (widgets == null); 2476 final String mimeType = desc.getMimeType(index); 2477 if (isShortcut) { 2478 final Intent intent = data.getItemAt(index).getIntent(); 2479 Object info = model.infoFromShortcutIntent(mContext, intent, data.getIcon()); 2480 if (info != null) { 2481 onDropExternal(new int[] { x, y }, info, layout, false); 2482 } 2483 } else { 2484 if (widgets.size() == 1) { 2485 // If there is only one item, then go ahead and add and configure 2486 // that widget 2487 final AppWidgetProviderInfo widgetInfo = widgets.get(0).widgetInfo; 2488 final PendingAddWidgetInfo createInfo = 2489 new PendingAddWidgetInfo(widgetInfo, mimeType, data); 2490 mLauncher.addAppWidgetFromDrop(createInfo, 2491 LauncherSettings.Favorites.CONTAINER_DESKTOP, mCurrentPage, null, pos); 2492 } else { 2493 // Show the widget picker dialog if there is more than one widget 2494 // that can handle this data type 2495 final InstallWidgetReceiver.WidgetListAdapter adapter = 2496 new InstallWidgetReceiver.WidgetListAdapter(mLauncher, mimeType, 2497 data, widgets, layout, mCurrentPage, pos); 2498 final AlertDialog.Builder builder = 2499 new AlertDialog.Builder(mContext); 2500 builder.setAdapter(adapter, adapter); 2501 builder.setCancelable(true); 2502 builder.setTitle(mContext.getString( 2503 R.string.external_drop_widget_pick_title)); 2504 builder.setIcon(R.drawable.ic_no_applications); 2505 builder.show(); 2506 } 2507 } 2508 } 2509 return true; 2510 } 2511 case DragEvent.ACTION_DRAG_ENDED: 2512 // Hide the page outlines after the drop 2513 layout.onDragExit(); 2514 hideOutlines(); 2515 return true; 2516 } 2517 return super.onDragEvent(event); 2518 } 2519 2520 /* 2521 * 2522 * Convert the 2D coordinate xy from the parent View's coordinate space to this CellLayout's 2523 * coordinate space. The argument xy is modified with the return result. 2524 * 2525 */ 2526 void mapPointFromSelfToChild(View v, float[] xy) { 2527 mapPointFromSelfToChild(v, xy, null); 2528 } 2529 2530 /* 2531 * 2532 * Convert the 2D coordinate xy from the parent View's coordinate space to this CellLayout's 2533 * coordinate space. The argument xy is modified with the return result. 2534 * 2535 * if cachedInverseMatrix is not null, this method will just use that matrix instead of 2536 * computing it itself; we use this to avoid redundant matrix inversions in 2537 * findMatchingPageForDragOver 2538 * 2539 */ 2540 void mapPointFromSelfToChild(View v, float[] xy, Matrix cachedInverseMatrix) { 2541 if (cachedInverseMatrix == null) { 2542 v.getMatrix().invert(mTempInverseMatrix); 2543 cachedInverseMatrix = mTempInverseMatrix; 2544 } 2545 xy[0] = xy[0] + mScrollX - v.getLeft(); 2546 xy[1] = xy[1] + mScrollY - v.getTop(); 2547 cachedInverseMatrix.mapPoints(xy); 2548 } 2549 2550 /* 2551 * Maps a point from the Workspace's coordinate system to another sibling view's. (Workspace 2552 * covers the full screen) 2553 */ 2554 void mapPointFromSelfToSibling(View v, float[] xy) { 2555 xy[0] = xy[0] - v.getLeft(); 2556 xy[1] = xy[1] - v.getTop(); 2557 } 2558 2559 /* 2560 * 2561 * Convert the 2D coordinate xy from this CellLayout's coordinate space to 2562 * the parent View's coordinate space. The argument xy is modified with the return result. 2563 * 2564 */ 2565 void mapPointFromChildToSelf(View v, float[] xy) { 2566 v.getMatrix().mapPoints(xy); 2567 xy[0] -= (mScrollX - v.getLeft()); 2568 xy[1] -= (mScrollY - v.getTop()); 2569 } 2570 2571 static private float squaredDistance(float[] point1, float[] point2) { 2572 float distanceX = point1[0] - point2[0]; 2573 float distanceY = point2[1] - point2[1]; 2574 return distanceX * distanceX + distanceY * distanceY; 2575 } 2576 2577 /* 2578 * 2579 * Returns true if the passed CellLayout cl overlaps with dragView 2580 * 2581 */ 2582 boolean overlaps(CellLayout cl, DragView dragView, 2583 int dragViewX, int dragViewY, Matrix cachedInverseMatrix) { 2584 // Transform the coordinates of the item being dragged to the CellLayout's coordinates 2585 final float[] draggedItemTopLeft = mTempDragCoordinates; 2586 draggedItemTopLeft[0] = dragViewX; 2587 draggedItemTopLeft[1] = dragViewY; 2588 final float[] draggedItemBottomRight = mTempDragBottomRightCoordinates; 2589 draggedItemBottomRight[0] = draggedItemTopLeft[0] + dragView.getDragRegionWidth(); 2590 draggedItemBottomRight[1] = draggedItemTopLeft[1] + dragView.getDragRegionHeight(); 2591 2592 // Transform the dragged item's top left coordinates 2593 // to the CellLayout's local coordinates 2594 mapPointFromSelfToChild(cl, draggedItemTopLeft, cachedInverseMatrix); 2595 float overlapRegionLeft = Math.max(0f, draggedItemTopLeft[0]); 2596 float overlapRegionTop = Math.max(0f, draggedItemTopLeft[1]); 2597 2598 if (overlapRegionLeft <= cl.getWidth() && overlapRegionTop >= 0) { 2599 // Transform the dragged item's bottom right coordinates 2600 // to the CellLayout's local coordinates 2601 mapPointFromSelfToChild(cl, draggedItemBottomRight, cachedInverseMatrix); 2602 float overlapRegionRight = Math.min(cl.getWidth(), draggedItemBottomRight[0]); 2603 float overlapRegionBottom = Math.min(cl.getHeight(), draggedItemBottomRight[1]); 2604 2605 if (overlapRegionRight >= 0 && overlapRegionBottom <= cl.getHeight()) { 2606 float overlap = (overlapRegionRight - overlapRegionLeft) * 2607 (overlapRegionBottom - overlapRegionTop); 2608 if (overlap > 0) { 2609 return true; 2610 } 2611 } 2612 } 2613 return false; 2614 } 2615 2616 /* 2617 * 2618 * This method returns the CellLayout that is currently being dragged to. In order to drag 2619 * to a CellLayout, either the touch point must be directly over the CellLayout, or as a second 2620 * strategy, we see if the dragView is overlapping any CellLayout and choose the closest one 2621 * 2622 * Return null if no CellLayout is currently being dragged over 2623 * 2624 */ 2625 private CellLayout findMatchingPageForDragOver( 2626 DragView dragView, float originX, float originY, boolean exact) { 2627 // We loop through all the screens (ie CellLayouts) and see which ones overlap 2628 // with the item being dragged and then choose the one that's closest to the touch point 2629 final int screenCount = getChildCount(); 2630 CellLayout bestMatchingScreen = null; 2631 float smallestDistSoFar = Float.MAX_VALUE; 2632 2633 for (int i = 0; i < screenCount; i++) { 2634 CellLayout cl = (CellLayout) getChildAt(i); 2635 2636 final float[] touchXy = {originX, originY}; 2637 // Transform the touch coordinates to the CellLayout's local coordinates 2638 // If the touch point is within the bounds of the cell layout, we can return immediately 2639 cl.getMatrix().invert(mTempInverseMatrix); 2640 mapPointFromSelfToChild(cl, touchXy, mTempInverseMatrix); 2641 2642 if (touchXy[0] >= 0 && touchXy[0] <= cl.getWidth() && 2643 touchXy[1] >= 0 && touchXy[1] <= cl.getHeight()) { 2644 return cl; 2645 } 2646 2647 if (!exact) { 2648 // Get the center of the cell layout in screen coordinates 2649 final float[] cellLayoutCenter = mTempCellLayoutCenterCoordinates; 2650 cellLayoutCenter[0] = cl.getWidth()/2; 2651 cellLayoutCenter[1] = cl.getHeight()/2; 2652 mapPointFromChildToSelf(cl, cellLayoutCenter); 2653 2654 touchXy[0] = originX; 2655 touchXy[1] = originY; 2656 2657 // Calculate the distance between the center of the CellLayout 2658 // and the touch point 2659 float dist = squaredDistance(touchXy, cellLayoutCenter); 2660 2661 if (dist < smallestDistSoFar) { 2662 smallestDistSoFar = dist; 2663 bestMatchingScreen = cl; 2664 } 2665 } 2666 } 2667 return bestMatchingScreen; 2668 } 2669 2670 // This is used to compute the visual center of the dragView. This point is then 2671 // used to visualize drop locations and determine where to drop an item. The idea is that 2672 // the visual center represents the user's interpretation of where the item is, and hence 2673 // is the appropriate point to use when determining drop location. 2674 private float[] getDragViewVisualCenter(int x, int y, int xOffset, int yOffset, 2675 DragView dragView, float[] recycle) { 2676 float res[]; 2677 if (recycle == null) { 2678 res = new float[2]; 2679 } else { 2680 res = recycle; 2681 } 2682 2683 // First off, the drag view has been shifted in a way that is not represented in the 2684 // x and y values or the x/yOffsets. Here we account for that shift. 2685 x += getResources().getDimensionPixelSize(R.dimen.dragViewOffsetX); 2686 y += getResources().getDimensionPixelSize(R.dimen.dragViewOffsetY); 2687 2688 // These represent the visual top and left of drag view if a dragRect was provided. 2689 // If a dragRect was not provided, then they correspond to the actual view left and 2690 // top, as the dragRect is in that case taken to be the entire dragView. 2691 // R.dimen.dragViewOffsetY. 2692 int left = x - xOffset; 2693 int top = y - yOffset; 2694 2695 // In order to find the visual center, we shift by half the dragRect 2696 res[0] = left + dragView.getDragRegion().width() / 2; 2697 res[1] = top + dragView.getDragRegion().height() / 2; 2698 2699 return res; 2700 } 2701 2702 private boolean isDragWidget(DragObject d) { 2703 return (d.dragInfo instanceof LauncherAppWidgetInfo || 2704 d.dragInfo instanceof PendingAddWidgetInfo); 2705 } 2706 private boolean isExternalDragWidget(DragObject d) { 2707 return d.dragSource != this && isDragWidget(d); 2708 } 2709 2710 public void onDragOver(DragObject d) { 2711 // Skip drag over events while we are dragging over side pages 2712 if (mInScrollArea) return; 2713 if (mIsSwitchingState) return; 2714 2715 Rect r = new Rect(); 2716 CellLayout layout = null; 2717 ItemInfo item = (ItemInfo) d.dragInfo; 2718 2719 // Ensure that we have proper spans for the item that we are dropping 2720 if (item.spanX < 0 || item.spanY < 0) throw new RuntimeException("Improper spans found"); 2721 mDragViewVisualCenter = getDragViewVisualCenter(d.x, d.y, d.xOffset, d.yOffset, 2722 d.dragView, mDragViewVisualCenter); 2723 2724 // Identify whether we have dragged over a side page 2725 if (isSmall()) { 2726 if (mLauncher.getHotseat() != null && !isExternalDragWidget(d)) { 2727 mLauncher.getHotseat().getHitRect(r); 2728 if (r.contains(d.x, d.y)) { 2729 layout = mLauncher.getHotseat().getLayout(); 2730 } 2731 } 2732 if (layout == null) { 2733 layout = findMatchingPageForDragOver(d.dragView, d.x, d.y, false); 2734 } 2735 if (layout != mDragTargetLayout) { 2736 // Cancel all intermediate folder states 2737 cleanupFolderCreation(d); 2738 2739 if (mDragTargetLayout != null) { 2740 mDragTargetLayout.setIsDragOverlapping(false); 2741 mDragTargetLayout.onDragExit(); 2742 } 2743 mDragTargetLayout = layout; 2744 if (mDragTargetLayout != null) { 2745 mDragTargetLayout.setIsDragOverlapping(true); 2746 mDragTargetLayout.onDragEnter(); 2747 } else { 2748 mLastDragOverView = null; 2749 } 2750 2751 boolean isInSpringLoadedMode = (mState == State.SPRING_LOADED); 2752 if (isInSpringLoadedMode) { 2753 if (mLauncher.isHotseatLayout(layout)) { 2754 mSpringLoadedDragController.cancel(); 2755 } else { 2756 mSpringLoadedDragController.setAlarm(mDragTargetLayout); 2757 } 2758 } 2759 } 2760 } else { 2761 // Test to see if we are over the hotseat otherwise just use the current page 2762 if (mLauncher.getHotseat() != null && !isDragWidget(d)) { 2763 mLauncher.getHotseat().getHitRect(r); 2764 if (r.contains(d.x, d.y)) { 2765 layout = mLauncher.getHotseat().getLayout(); 2766 } 2767 } 2768 if (layout == null) { 2769 layout = getCurrentDropLayout(); 2770 } 2771 if (layout != mDragTargetLayout) { 2772 if (mDragTargetLayout != null) { 2773 mDragTargetLayout.setIsDragOverlapping(false); 2774 mDragTargetLayout.onDragExit(); 2775 } 2776 mDragTargetLayout = layout; 2777 mDragTargetLayout.setIsDragOverlapping(true); 2778 mDragTargetLayout.onDragEnter(); 2779 } 2780 } 2781 2782 // Handle the drag over 2783 if (mDragTargetLayout != null) { 2784 final View child = (mDragInfo == null) ? null : mDragInfo.cell; 2785 2786 // We want the point to be mapped to the dragTarget. 2787 if (mLauncher.isHotseatLayout(mDragTargetLayout)) { 2788 mapPointFromSelfToSibling(mLauncher.getHotseat(), mDragViewVisualCenter); 2789 } else { 2790 mapPointFromSelfToChild(mDragTargetLayout, mDragViewVisualCenter, null); 2791 } 2792 ItemInfo info = (ItemInfo) d.dragInfo; 2793 2794 mTargetCell = findNearestArea((int) mDragViewVisualCenter[0], 2795 (int) mDragViewVisualCenter[1], 1, 1, mDragTargetLayout, mTargetCell); 2796 final View dragOverView = mDragTargetLayout.getChildAt(mTargetCell[0], 2797 mTargetCell[1]); 2798 2799 boolean userFolderPending = willCreateUserFolder(info, mDragTargetLayout, 2800 mTargetCell, false); 2801 boolean isOverFolder = dragOverView instanceof FolderIcon; 2802 if (dragOverView != mLastDragOverView) { 2803 cancelFolderCreation(); 2804 if (mLastDragOverView != null && mLastDragOverView instanceof FolderIcon) { 2805 ((FolderIcon) mLastDragOverView).onDragExit(d.dragInfo); 2806 } 2807 } 2808 2809 if (userFolderPending && dragOverView != mLastDragOverView) { 2810 mFolderCreationAlarm.setOnAlarmListener(new 2811 FolderCreationAlarmListener(mDragTargetLayout, mTargetCell[0], mTargetCell[1])); 2812 mFolderCreationAlarm.setAlarm(FOLDER_CREATION_TIMEOUT); 2813 } 2814 2815 if (dragOverView != mLastDragOverView && isOverFolder) { 2816 ((FolderIcon) dragOverView).onDragEnter(d.dragInfo); 2817 if (mDragTargetLayout != null) { 2818 mDragTargetLayout.clearDragOutlines(); 2819 } 2820 } 2821 mLastDragOverView = dragOverView; 2822 2823 if (!mCreateUserFolderOnDrop && !isOverFolder) { 2824 mDragTargetLayout.visualizeDropLocation(child, mDragOutline, 2825 (int) mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1], 2826 item.spanX, item.spanY, d.dragView.getDragVisualizeOffset(), 2827 d.dragView.getDragRegion()); 2828 } 2829 } 2830 } 2831 2832 private void cleanupFolderCreation(DragObject d) { 2833 if (mDragFolderRingAnimator != null && mCreateUserFolderOnDrop) { 2834 mDragFolderRingAnimator.animateToNaturalState(); 2835 } 2836 if (mLastDragOverView != null && mLastDragOverView instanceof FolderIcon) { 2837 if (d != null) { 2838 ((FolderIcon) mLastDragOverView).onDragExit(d.dragInfo); 2839 } 2840 } 2841 mFolderCreationAlarm.cancelAlarm(); 2842 } 2843 2844 private void cancelFolderCreation() { 2845 if (mDragFolderRingAnimator != null && mCreateUserFolderOnDrop) { 2846 mDragFolderRingAnimator.animateToNaturalState(); 2847 } 2848 mCreateUserFolderOnDrop = false; 2849 mFolderCreationAlarm.cancelAlarm(); 2850 } 2851 2852 class FolderCreationAlarmListener implements OnAlarmListener { 2853 CellLayout layout; 2854 int cellX; 2855 int cellY; 2856 2857 public FolderCreationAlarmListener(CellLayout layout, int cellX, int cellY) { 2858 this.layout = layout; 2859 this.cellX = cellX; 2860 this.cellY = cellY; 2861 } 2862 2863 public void onAlarm(Alarm alarm) { 2864 if (mDragFolderRingAnimator == null) { 2865 mDragFolderRingAnimator = new FolderRingAnimator(mLauncher, null); 2866 } 2867 mDragFolderRingAnimator.setCell(cellX, cellY); 2868 mDragFolderRingAnimator.setCellLayout(layout); 2869 mDragFolderRingAnimator.animateToAcceptState(); 2870 layout.showFolderAccept(mDragFolderRingAnimator); 2871 layout.clearDragOutlines(); 2872 mCreateUserFolderOnDrop = true; 2873 } 2874 } 2875 2876 @Override 2877 public void getHitRect(Rect outRect) { 2878 // We want the workspace to have the whole area of the display (it will find the correct 2879 // cell layout to drop to in the existing drag/drop logic. 2880 outRect.set(0, 0, mDisplayWidth, mDisplayHeight); 2881 } 2882 2883 /** 2884 * Add the item specified by dragInfo to the given layout. 2885 * @return true if successful 2886 */ 2887 public boolean addExternalItemToScreen(ItemInfo dragInfo, CellLayout layout) { 2888 if (layout.findCellForSpan(mTempEstimate, dragInfo.spanX, dragInfo.spanY)) { 2889 onDropExternal(dragInfo.dropPos, (ItemInfo) dragInfo, (CellLayout) layout, false); 2890 return true; 2891 } 2892 mLauncher.showOutOfSpaceMessage(); 2893 return false; 2894 } 2895 2896 private void onDropExternal(int[] touchXY, Object dragInfo, 2897 CellLayout cellLayout, boolean insertAtFirst) { 2898 onDropExternal(touchXY, dragInfo, cellLayout, insertAtFirst, null); 2899 } 2900 2901 /** 2902 * Drop an item that didn't originate on one of the workspace screens. 2903 * It may have come from Launcher (e.g. from all apps or customize), or it may have 2904 * come from another app altogether. 2905 * 2906 * NOTE: This can also be called when we are outside of a drag event, when we want 2907 * to add an item to one of the workspace screens. 2908 */ 2909 private void onDropExternal(final int[] touchXY, final Object dragInfo, 2910 final CellLayout cellLayout, boolean insertAtFirst, DragObject d) { 2911 final Runnable exitSpringLoadedRunnable = new Runnable() { 2912 @Override 2913 public void run() { 2914 mLauncher.exitSpringLoadedDragModeDelayed(true, false); 2915 } 2916 }; 2917 2918 ItemInfo info = (ItemInfo) dragInfo; 2919 int spanX = info.spanX; 2920 int spanY = info.spanY; 2921 if (mDragInfo != null) { 2922 spanX = mDragInfo.spanX; 2923 spanY = mDragInfo.spanY; 2924 } 2925 2926 final long container = mLauncher.isHotseatLayout(cellLayout) ? 2927 LauncherSettings.Favorites.CONTAINER_HOTSEAT : 2928 LauncherSettings.Favorites.CONTAINER_DESKTOP; 2929 final int screen = indexOfChild(cellLayout); 2930 if (!mLauncher.isHotseatLayout(cellLayout) && screen != mCurrentPage 2931 && mState != State.SPRING_LOADED) { 2932 snapToPage(screen); 2933 } 2934 2935 if (info instanceof PendingAddItemInfo) { 2936 final PendingAddItemInfo pendingInfo = (PendingAddItemInfo) dragInfo; 2937 2938 boolean findNearestVacantCell = true; 2939 if (pendingInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) { 2940 mTargetCell = findNearestArea((int) touchXY[0], (int) touchXY[1], spanX, spanY, 2941 cellLayout, mTargetCell); 2942 if (willCreateUserFolder((ItemInfo) d.dragInfo, mDragTargetLayout, mTargetCell, 2943 true) || willAddToExistingUserFolder((ItemInfo) d.dragInfo, 2944 mDragTargetLayout, mTargetCell)) { 2945 findNearestVacantCell = false; 2946 } 2947 } 2948 if (findNearestVacantCell) { 2949 mTargetCell = findNearestVacantArea(touchXY[0], touchXY[1], spanX, spanY, null, 2950 cellLayout, mTargetCell); 2951 } 2952 2953 Runnable onAnimationCompleteRunnable = new Runnable() { 2954 @Override 2955 public void run() { 2956 // When dragging and dropping from customization tray, we deal with creating 2957 // widgets/shortcuts/folders in a slightly different way 2958 switch (pendingInfo.itemType) { 2959 case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET: 2960 mLauncher.addAppWidgetFromDrop((PendingAddWidgetInfo) pendingInfo, 2961 container, screen, mTargetCell, null); 2962 break; 2963 case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT: 2964 mLauncher.processShortcutFromDrop(pendingInfo.componentName, 2965 container, screen, mTargetCell, null); 2966 break; 2967 default: 2968 throw new IllegalStateException("Unknown item type: " + 2969 pendingInfo.itemType); 2970 } 2971 cellLayout.onDragExit(); 2972 } 2973 }; 2974 2975 // Now we animate the dragView, (ie. the widget or shortcut preview) into its final 2976 // location and size on the home screen. 2977 RectF r = estimateItemPosition(cellLayout, pendingInfo, 2978 mTargetCell[0], mTargetCell[1], spanX, spanY); 2979 int loc[] = new int[2]; 2980 loc[0] = (int) r.left; 2981 loc[1] = (int) r.top; 2982 setFinalTransitionTransform(cellLayout); 2983 float cellLayoutScale = 2984 mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(cellLayout, loc); 2985 resetTransitionTransform(cellLayout); 2986 2987 float dragViewScale = Math.min(r.width() / d.dragView.getMeasuredWidth(), 2988 r.height() / d.dragView.getMeasuredHeight()); 2989 // The animation will scale the dragView about its center, so we need to center about 2990 // the final location. 2991 loc[0] -= (d.dragView.getMeasuredWidth() - cellLayoutScale * r.width()) / 2; 2992 loc[1] -= (d.dragView.getMeasuredHeight() - cellLayoutScale * r.height()) / 2; 2993 2994 mLauncher.getDragLayer().animateViewIntoPosition(d.dragView, loc, 2995 dragViewScale * cellLayoutScale, onAnimationCompleteRunnable); 2996 } else { 2997 // This is for other drag/drop cases, like dragging from All Apps 2998 View view = null; 2999 3000 switch (info.itemType) { 3001 case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION: 3002 case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT: 3003 if (info.container == NO_ID && info instanceof ApplicationInfo) { 3004 // Came from all apps -- make a copy 3005 info = new ShortcutInfo((ApplicationInfo) info); 3006 } 3007 view = mLauncher.createShortcut(R.layout.application, cellLayout, 3008 (ShortcutInfo) info); 3009 break; 3010 case LauncherSettings.Favorites.ITEM_TYPE_FOLDER: 3011 view = FolderIcon.fromXml(R.layout.folder_icon, mLauncher, cellLayout, 3012 (FolderInfo) info, mIconCache); 3013 break; 3014 default: 3015 throw new IllegalStateException("Unknown item type: " + info.itemType); 3016 } 3017 3018 // First we find the cell nearest to point at which the item is 3019 // dropped, without any consideration to whether there is an item there. 3020 if (touchXY != null) { 3021 mTargetCell = findNearestArea((int) touchXY[0], (int) touchXY[1], spanX, spanY, 3022 cellLayout, mTargetCell); 3023 d.postAnimationRunnable = exitSpringLoadedRunnable; 3024 if (createUserFolderIfNecessary(view, container, cellLayout, mTargetCell, true, 3025 d.dragView, d.postAnimationRunnable)) { 3026 return; 3027 } 3028 if (addToExistingFolderIfNecessary(view, cellLayout, mTargetCell, d, true)) { 3029 return; 3030 } 3031 } 3032 3033 if (touchXY != null) { 3034 // when dragging and dropping, just find the closest free spot 3035 mTargetCell = findNearestVacantArea(touchXY[0], touchXY[1], 1, 1, null, 3036 cellLayout, mTargetCell); 3037 } else { 3038 cellLayout.findCellForSpan(mTargetCell, 1, 1); 3039 } 3040 addInScreen(view, container, screen, mTargetCell[0], mTargetCell[1], info.spanX, 3041 info.spanY, insertAtFirst); 3042 cellLayout.onDropChild(view); 3043 CellLayout.LayoutParams lp = (CellLayout.LayoutParams) view.getLayoutParams(); 3044 cellLayout.getChildrenLayout().measureChild(view); 3045 3046 LauncherModel.addOrMoveItemInDatabase(mLauncher, info, container, screen, 3047 lp.cellX, lp.cellY); 3048 3049 if (d.dragView != null) { 3050 // We wrap the animation call in the temporary set and reset of the current 3051 // cellLayout to its final transform -- this means we animate the drag view to 3052 // the correct final location. 3053 setFinalTransitionTransform(cellLayout); 3054 mLauncher.getDragLayer().animateViewIntoPosition(d.dragView, view, 3055 exitSpringLoadedRunnable); 3056 resetTransitionTransform(cellLayout); 3057 } 3058 } 3059 } 3060 3061 public void setFinalTransitionTransform(CellLayout layout) { 3062 if (isSwitchingState()) { 3063 int index = indexOfChild(layout); 3064 mCurrentScaleX = layout.getScaleX(); 3065 mCurrentScaleY = layout.getScaleY(); 3066 mCurrentTranslationX = layout.getTranslationX(); 3067 mCurrentTranslationY = layout.getTranslationY(); 3068 mCurrentRotationY = layout.getRotationY(); 3069 layout.setScaleX(mNewScaleXs[index]); 3070 layout.setScaleY(mNewScaleYs[index]); 3071 layout.setTranslationX(mNewTranslationXs[index]); 3072 layout.setTranslationY(mNewTranslationYs[index]); 3073 layout.setRotationY(mNewRotationYs[index]); 3074 } 3075 } 3076 public void resetTransitionTransform(CellLayout layout) { 3077 if (isSwitchingState()) { 3078 mCurrentScaleX = layout.getScaleX(); 3079 mCurrentScaleY = layout.getScaleY(); 3080 mCurrentTranslationX = layout.getTranslationX(); 3081 mCurrentTranslationY = layout.getTranslationY(); 3082 mCurrentRotationY = layout.getRotationY(); 3083 layout.setScaleX(mCurrentScaleX); 3084 layout.setScaleY(mCurrentScaleY); 3085 layout.setTranslationX(mCurrentTranslationX); 3086 layout.setTranslationY(mCurrentTranslationY); 3087 layout.setRotationY(mCurrentRotationY); 3088 } 3089 } 3090 3091 /** 3092 * Return the current {@link CellLayout}, correctly picking the destination 3093 * screen while a scroll is in progress. 3094 */ 3095 public CellLayout getCurrentDropLayout() { 3096 return (CellLayout) getChildAt(mNextPage == INVALID_PAGE ? mCurrentPage : mNextPage); 3097 } 3098 3099 /** 3100 * Return the current CellInfo describing our current drag; this method exists 3101 * so that Launcher can sync this object with the correct info when the activity is created/ 3102 * destroyed 3103 * 3104 */ 3105 public CellLayout.CellInfo getDragInfo() { 3106 return mDragInfo; 3107 } 3108 3109 /** 3110 * Calculate the nearest cell where the given object would be dropped. 3111 * 3112 * pixelX and pixelY should be in the coordinate system of layout 3113 */ 3114 private int[] findNearestVacantArea(int pixelX, int pixelY, 3115 int spanX, int spanY, View ignoreView, CellLayout layout, int[] recycle) { 3116 return layout.findNearestVacantArea( 3117 pixelX, pixelY, spanX, spanY, ignoreView, recycle); 3118 } 3119 3120 /** 3121 * Calculate the nearest cell where the given object would be dropped. 3122 * 3123 * pixelX and pixelY should be in the coordinate system of layout 3124 */ 3125 private int[] findNearestArea(int pixelX, int pixelY, 3126 int spanX, int spanY, CellLayout layout, int[] recycle) { 3127 return layout.findNearestArea( 3128 pixelX, pixelY, spanX, spanY, recycle); 3129 } 3130 3131 void setup(DragController dragController) { 3132 mSpringLoadedDragController = new SpringLoadedDragController(mLauncher); 3133 mDragController = dragController; 3134 3135 // hardware layers on children are enabled on startup, but should be disabled until 3136 // needed 3137 updateChildrenLayersEnabled(); 3138 setWallpaperDimension(); 3139 } 3140 3141 /** 3142 * Called at the end of a drag which originated on the workspace. 3143 */ 3144 public void onDropCompleted(View target, DragObject d, boolean success) { 3145 if (success) { 3146 if (target != this) { 3147 if (mDragInfo != null) { 3148 getParentCellLayoutForView(mDragInfo.cell).removeView(mDragInfo.cell); 3149 if (mDragInfo.cell instanceof DropTarget) { 3150 mDragController.removeDropTarget((DropTarget) mDragInfo.cell); 3151 } 3152 } 3153 } 3154 } else if (mDragInfo != null) { 3155 // NOTE: When 'success' is true, onDragExit is called by the DragController before 3156 // calling onDropCompleted(). We call it ourselves here, but maybe this should be 3157 // moved into DragController.cancelDrag(). 3158 doDragExit(null); 3159 CellLayout cellLayout; 3160 if (mLauncher.isHotseatLayout(target)) { 3161 cellLayout = mLauncher.getHotseat().getLayout(); 3162 } else { 3163 cellLayout = (CellLayout) getChildAt(mDragInfo.screen); 3164 } 3165 cellLayout.onDropChild(mDragInfo.cell); 3166 } 3167 if (d.cancelled && mDragInfo.cell != null) { 3168 mDragInfo.cell.setVisibility(VISIBLE); 3169 } 3170 mDragOutline = null; 3171 mDragInfo = null; 3172 } 3173 3174 public boolean isDropEnabled() { 3175 return true; 3176 } 3177 3178 @Override 3179 protected void onRestoreInstanceState(Parcelable state) { 3180 super.onRestoreInstanceState(state); 3181 Launcher.setScreen(mCurrentPage); 3182 } 3183 3184 @Override 3185 public void scrollLeft() { 3186 if (!isSmall() && !mIsSwitchingState) { 3187 super.scrollLeft(); 3188 } 3189 Folder openFolder = getOpenFolder(); 3190 if (openFolder != null) { 3191 openFolder.completeDragExit(); 3192 } 3193 } 3194 3195 @Override 3196 public void scrollRight() { 3197 if (!isSmall() && !mIsSwitchingState) { 3198 super.scrollRight(); 3199 } 3200 Folder openFolder = getOpenFolder(); 3201 if (openFolder != null) { 3202 openFolder.completeDragExit(); 3203 } 3204 } 3205 3206 @Override 3207 public boolean onEnterScrollArea(int x, int y, int direction) { 3208 // Ignore the scroll area if we are dragging over the hot seat 3209 if (mLauncher.getHotseat() != null) { 3210 Rect r = new Rect(); 3211 mLauncher.getHotseat().getHitRect(r); 3212 if (r.contains(x, y)) { 3213 return false; 3214 } 3215 } 3216 3217 boolean result = false; 3218 if (!isSmall() && !mIsSwitchingState) { 3219 mInScrollArea = true; 3220 3221 final int page = mCurrentPage + (direction == DragController.SCROLL_LEFT ? -1 : 1); 3222 final CellLayout layout = (CellLayout) getChildAt(page); 3223 cancelFolderCreation(); 3224 3225 if (layout != null) { 3226 // Exit the current layout and mark the overlapping layout 3227 if (mDragTargetLayout != null) { 3228 mDragTargetLayout.setIsDragOverlapping(false); 3229 mDragTargetLayout.onDragExit(); 3230 } 3231 mDragTargetLayout = layout; 3232 mDragTargetLayout.setIsDragOverlapping(true); 3233 3234 // Workspace is responsible for drawing the edge glow on adjacent pages, 3235 // so we need to redraw the workspace when this may have changed. 3236 invalidate(); 3237 result = true; 3238 } 3239 } 3240 return result; 3241 } 3242 3243 @Override 3244 public boolean onExitScrollArea() { 3245 boolean result = false; 3246 if (mInScrollArea) { 3247 if (mDragTargetLayout != null) { 3248 // Unmark the overlapping layout and re-enter the current layout 3249 mDragTargetLayout.setIsDragOverlapping(false); 3250 mDragTargetLayout = getCurrentDropLayout(); 3251 mDragTargetLayout.onDragEnter(); 3252 3253 // Workspace is responsible for drawing the edge glow on adjacent pages, 3254 // so we need to redraw the workspace when this may have changed. 3255 invalidate(); 3256 result = true; 3257 } 3258 mInScrollArea = false; 3259 } 3260 return result; 3261 } 3262 3263 private void onResetScrollArea() { 3264 if (mDragTargetLayout != null) { 3265 // Unmark the overlapping layout 3266 mDragTargetLayout.setIsDragOverlapping(false); 3267 3268 // Workspace is responsible for drawing the edge glow on adjacent pages, 3269 // so we need to redraw the workspace when this may have changed. 3270 invalidate(); 3271 } 3272 mInScrollArea = false; 3273 } 3274 3275 /** 3276 * Returns a specific CellLayout 3277 */ 3278 CellLayout getParentCellLayoutForView(View v) { 3279 ArrayList<CellLayout> layouts = getWorkspaceAndHotseatCellLayouts(); 3280 for (CellLayout layout : layouts) { 3281 if (layout.getChildrenLayout().indexOfChild(v) > -1) { 3282 return layout; 3283 } 3284 } 3285 return null; 3286 } 3287 3288 /** 3289 * Returns a list of all the CellLayouts in the workspace. 3290 */ 3291 ArrayList<CellLayout> getWorkspaceAndHotseatCellLayouts() { 3292 ArrayList<CellLayout> layouts = new ArrayList<CellLayout>(); 3293 int screenCount = getChildCount(); 3294 for (int screen = 0; screen < screenCount; screen++) { 3295 layouts.add(((CellLayout) getChildAt(screen))); 3296 } 3297 if (mLauncher.getHotseat() != null) { 3298 layouts.add(mLauncher.getHotseat().getLayout()); 3299 } 3300 return layouts; 3301 } 3302 3303 /** 3304 * We should only use this to search for specific children. Do not use this method to modify 3305 * CellLayoutChildren directly. 3306 */ 3307 ArrayList<CellLayoutChildren> getWorkspaceAndHotseatCellLayoutChildren() { 3308 ArrayList<CellLayoutChildren> childrenLayouts = new ArrayList<CellLayoutChildren>(); 3309 int screenCount = getChildCount(); 3310 for (int screen = 0; screen < screenCount; screen++) { 3311 childrenLayouts.add(((CellLayout) getChildAt(screen)).getChildrenLayout()); 3312 } 3313 if (mLauncher.getHotseat() != null) { 3314 childrenLayouts.add(mLauncher.getHotseat().getLayout().getChildrenLayout()); 3315 } 3316 return childrenLayouts; 3317 } 3318 3319 public Folder getFolderForTag(Object tag) { 3320 ArrayList<CellLayoutChildren> childrenLayouts = getWorkspaceAndHotseatCellLayoutChildren(); 3321 for (CellLayoutChildren layout: childrenLayouts) { 3322 int count = layout.getChildCount(); 3323 for (int i = 0; i < count; i++) { 3324 View child = layout.getChildAt(i); 3325 if (child instanceof Folder) { 3326 Folder f = (Folder) child; 3327 if (f.getInfo() == tag && f.getInfo().opened) { 3328 return f; 3329 } 3330 } 3331 } 3332 } 3333 return null; 3334 } 3335 3336 public View getViewForTag(Object tag) { 3337 ArrayList<CellLayoutChildren> childrenLayouts = getWorkspaceAndHotseatCellLayoutChildren(); 3338 for (CellLayoutChildren layout: childrenLayouts) { 3339 int count = layout.getChildCount(); 3340 for (int i = 0; i < count; i++) { 3341 View child = layout.getChildAt(i); 3342 if (child.getTag() == tag) { 3343 return child; 3344 } 3345 } 3346 } 3347 return null; 3348 } 3349 3350 void clearDropTargets() { 3351 ArrayList<CellLayoutChildren> childrenLayouts = getWorkspaceAndHotseatCellLayoutChildren(); 3352 for (CellLayoutChildren layout: childrenLayouts) { 3353 int childCount = layout.getChildCount(); 3354 for (int j = 0; j < childCount; j++) { 3355 View v = layout.getChildAt(j); 3356 if (v instanceof DropTarget) { 3357 mDragController.removeDropTarget((DropTarget) v); 3358 } 3359 } 3360 } 3361 } 3362 3363 void removeItems(final ArrayList<ApplicationInfo> apps) { 3364 final AppWidgetManager widgets = AppWidgetManager.getInstance(getContext()); 3365 3366 final HashSet<String> packageNames = new HashSet<String>(); 3367 final int appCount = apps.size(); 3368 for (int i = 0; i < appCount; i++) { 3369 packageNames.add(apps.get(i).componentName.getPackageName()); 3370 } 3371 3372 ArrayList<CellLayout> cellLayouts = getWorkspaceAndHotseatCellLayouts(); 3373 for (final CellLayout layoutParent: cellLayouts) { 3374 final ViewGroup layout = layoutParent.getChildrenLayout(); 3375 3376 // Avoid ANRs by treating each screen separately 3377 post(new Runnable() { 3378 public void run() { 3379 final ArrayList<View> childrenToRemove = new ArrayList<View>(); 3380 childrenToRemove.clear(); 3381 3382 int childCount = layout.getChildCount(); 3383 for (int j = 0; j < childCount; j++) { 3384 final View view = layout.getChildAt(j); 3385 Object tag = view.getTag(); 3386 3387 if (tag instanceof ShortcutInfo) { 3388 final ShortcutInfo info = (ShortcutInfo) tag; 3389 final Intent intent = info.intent; 3390 final ComponentName name = intent.getComponent(); 3391 3392 if (Intent.ACTION_MAIN.equals(intent.getAction()) && name != null) { 3393 for (String packageName: packageNames) { 3394 if (packageName.equals(name.getPackageName())) { 3395 LauncherModel.deleteItemFromDatabase(mLauncher, info); 3396 childrenToRemove.add(view); 3397 } 3398 } 3399 } 3400 } else if (tag instanceof FolderInfo) { 3401 final FolderInfo info = (FolderInfo) tag; 3402 final ArrayList<ShortcutInfo> contents = info.contents; 3403 final int contentsCount = contents.size(); 3404 final ArrayList<ShortcutInfo> appsToRemoveFromFolder = 3405 new ArrayList<ShortcutInfo>(); 3406 3407 for (int k = 0; k < contentsCount; k++) { 3408 final ShortcutInfo appInfo = contents.get(k); 3409 final Intent intent = appInfo.intent; 3410 final ComponentName name = intent.getComponent(); 3411 3412 if (Intent.ACTION_MAIN.equals(intent.getAction()) && name != null) { 3413 for (String packageName: packageNames) { 3414 if (packageName.equals(name.getPackageName())) { 3415 appsToRemoveFromFolder.add(appInfo); 3416 } 3417 } 3418 } 3419 } 3420 for (ShortcutInfo item: appsToRemoveFromFolder) { 3421 info.remove(item); 3422 LauncherModel.deleteItemFromDatabase(mLauncher, item); 3423 } 3424 } else if (tag instanceof LauncherAppWidgetInfo) { 3425 final LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) tag; 3426 final AppWidgetProviderInfo provider = 3427 widgets.getAppWidgetInfo(info.appWidgetId); 3428 if (provider != null) { 3429 for (String packageName: packageNames) { 3430 if (packageName.equals(provider.provider.getPackageName())) { 3431 LauncherModel.deleteItemFromDatabase(mLauncher, info); 3432 childrenToRemove.add(view); 3433 } 3434 } 3435 } 3436 } 3437 } 3438 3439 childCount = childrenToRemove.size(); 3440 for (int j = 0; j < childCount; j++) { 3441 View child = childrenToRemove.get(j); 3442 // Note: We can not remove the view directly from CellLayoutChildren as this 3443 // does not re-mark the spaces as unoccupied. 3444 layoutParent.removeViewInLayout(child); 3445 if (child instanceof DropTarget) { 3446 mDragController.removeDropTarget((DropTarget)child); 3447 } 3448 } 3449 3450 if (childCount > 0) { 3451 layout.requestLayout(); 3452 layout.invalidate(); 3453 } 3454 } 3455 }); 3456 } 3457 } 3458 3459 void updateShortcuts(ArrayList<ApplicationInfo> apps) { 3460 ArrayList<CellLayoutChildren> childrenLayouts = getWorkspaceAndHotseatCellLayoutChildren(); 3461 for (CellLayoutChildren layout: childrenLayouts) { 3462 int childCount = layout.getChildCount(); 3463 for (int j = 0; j < childCount; j++) { 3464 final View view = layout.getChildAt(j); 3465 Object tag = view.getTag(); 3466 if (tag instanceof ShortcutInfo) { 3467 ShortcutInfo info = (ShortcutInfo)tag; 3468 // We need to check for ACTION_MAIN otherwise getComponent() might 3469 // return null for some shortcuts (for instance, for shortcuts to 3470 // web pages.) 3471 final Intent intent = info.intent; 3472 final ComponentName name = intent.getComponent(); 3473 if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION && 3474 Intent.ACTION_MAIN.equals(intent.getAction()) && name != null) { 3475 final int appCount = apps.size(); 3476 for (int k = 0; k < appCount; k++) { 3477 ApplicationInfo app = apps.get(k); 3478 if (app.componentName.equals(name)) { 3479 info.setIcon(mIconCache.getIcon(info.intent)); 3480 ((TextView)view).setCompoundDrawablesWithIntrinsicBounds(null, 3481 new FastBitmapDrawable(info.getIcon(mIconCache)), 3482 null, null); 3483 } 3484 } 3485 } 3486 } 3487 } 3488 } 3489 } 3490 3491 void moveToDefaultScreen(boolean animate) { 3492 if (!isSmall()) { 3493 if (animate) { 3494 snapToPage(mDefaultPage); 3495 } else { 3496 setCurrentPage(mDefaultPage); 3497 } 3498 } 3499 getChildAt(mDefaultPage).requestFocus(); 3500 } 3501 3502 @Override 3503 public void syncPages() { 3504 } 3505 3506 @Override 3507 public void syncPageItems(int page, boolean immediate) { 3508 } 3509 3510 @Override 3511 protected String getCurrentPageDescription() { 3512 int page = (mNextPage != INVALID_PAGE) ? mNextPage : mCurrentPage; 3513 return String.format(mContext.getString(R.string.workspace_scroll_format), 3514 page + 1, getChildCount()); 3515 } 3516 3517 public void getLocationInDragLayer(int[] loc) { 3518 mLauncher.getDragLayer().getLocationInDragLayer(this, loc); 3519 } 3520 3521 void setFadeForOverScroll(float fade) { 3522 if (!isScrollingIndicatorEnabled()) return; 3523 3524 mOverscrollFade = fade; 3525 float reducedFade = 0.5f + 0.5f * (1 - fade); 3526 final ViewGroup parent = (ViewGroup) getParent(); 3527 final ImageView qsbDivider = (ImageView) (parent.findViewById(R.id.qsb_divider)); 3528 final ImageView dockDivider = (ImageView) (parent.findViewById(R.id.dock_divider)); 3529 final ImageView scrollIndicator = getScrollingIndicator(); 3530 3531 cancelScrollingIndicatorAnimations(); 3532 if (qsbDivider != null) qsbDivider.setAlpha(reducedFade); 3533 if (dockDivider != null) dockDivider.setAlpha(reducedFade); 3534 scrollIndicator.setAlpha(1 - fade); 3535 } 3536} 3537