The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2008 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
Joe Onorato | a590252 | 2009-07-30 13:37:37 -0700 | [diff] [blame] | 17 | package com.android.launcher2; |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 18 | |
Michael Jurka | af44209 | 2010-06-10 17:01:57 -0700 | [diff] [blame] | 19 | import com.android.launcher.R; |
Adam Powell | 495f289 | 2010-04-16 16:40:55 -0700 | [diff] [blame] | 20 | |
Michael Jurka | 0280c3b | 2010-09-17 15:00:07 -0700 | [diff] [blame] | 21 | import android.animation.Animator; |
Patrick Dubroy | ce34a97 | 2010-10-19 10:34:32 -0700 | [diff] [blame] | 22 | import android.animation.Animator.AnimatorListener; |
Michael Jurka | 1801479 | 2010-10-14 09:01:34 -0700 | [diff] [blame] | 23 | import android.animation.AnimatorListenerAdapter; |
Chet Haase | b1254a6 | 2010-09-07 13:35:00 -0700 | [diff] [blame] | 24 | import android.animation.AnimatorSet; |
Michael Jurka | 0280c3b | 2010-09-17 15:00:07 -0700 | [diff] [blame] | 25 | import android.animation.ObjectAnimator; |
| 26 | import android.animation.PropertyValuesHolder; |
Dianne Hackborn | 8f57395 | 2009-08-10 23:21:09 -0700 | [diff] [blame] | 27 | import android.app.WallpaperManager; |
Romain Guy | 629de3e | 2010-01-13 12:20:59 -0800 | [diff] [blame] | 28 | import android.appwidget.AppWidgetManager; |
| 29 | import android.appwidget.AppWidgetProviderInfo; |
Adam Powell | 495f289 | 2010-04-16 16:40:55 -0700 | [diff] [blame] | 30 | import android.content.ComponentName; |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 31 | import android.content.Context; |
| 32 | import android.content.Intent; |
Adam Powell | 495f289 | 2010-04-16 16:40:55 -0700 | [diff] [blame] | 33 | import android.content.pm.PackageManager; |
Romain Guy | 5c16f3e | 2010-01-12 17:24:58 -0800 | [diff] [blame] | 34 | import android.content.pm.ProviderInfo; |
Patrick Dubroy | 7247f63 | 2010-08-04 16:02:59 -0700 | [diff] [blame] | 35 | import android.content.res.Resources; |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 36 | import android.content.res.TypedArray; |
Joe Onorato | 4be866d | 2010-10-10 11:26:02 -0700 | [diff] [blame] | 37 | import android.graphics.Bitmap; |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 38 | import android.graphics.Canvas; |
Michael Jurka | a63c452 | 2010-08-19 13:52:27 -0700 | [diff] [blame] | 39 | import android.graphics.Matrix; |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 40 | import android.graphics.Rect; |
Joe Onorato | 4be866d | 2010-10-10 11:26:02 -0700 | [diff] [blame] | 41 | import android.graphics.Region.Op; |
The Android Open Source Project | f96811c | 2009-03-18 17:39:48 -0700 | [diff] [blame] | 42 | import android.graphics.drawable.Drawable; |
Romain Guy | 5c16f3e | 2010-01-12 17:24:58 -0800 | [diff] [blame] | 43 | import android.net.Uri; |
Joe Onorato | 956091b | 2010-02-19 12:47:40 -0800 | [diff] [blame] | 44 | import android.os.IBinder; |
Adam Powell | 495f289 | 2010-04-16 16:40:55 -0700 | [diff] [blame] | 45 | import android.os.Parcelable; |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 46 | import android.util.AttributeSet; |
Daniel Sandler | 291ad12 | 2010-05-24 16:03:53 -0400 | [diff] [blame] | 47 | import android.util.Log; |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 48 | import android.view.MotionEvent; |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 49 | import android.view.View; |
The Android Open Source Project | f96811c | 2009-03-18 17:39:48 -0700 | [diff] [blame] | 50 | import android.widget.TextView; |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 51 | |
Michael Jurka | af44209 | 2010-06-10 17:01:57 -0700 | [diff] [blame] | 52 | import java.util.ArrayList; |
| 53 | import java.util.HashSet; |
Romain Guy | edcce09 | 2010-03-04 13:03:17 -0800 | [diff] [blame] | 54 | |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 55 | /** |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 56 | * The workspace is a wide area with a wallpaper and a finite number of pages. |
| 57 | * Each page contains a number of icons, folders or widgets the user can |
Winson Chung | aafa03c | 2010-06-11 17:34:16 -0700 | [diff] [blame] | 58 | * interact with. A workspace is meant to be used with a fixed width only. |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 59 | */ |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 60 | public class Workspace extends SmoothPagedView |
Michael Jurka | dee0589 | 2010-07-27 10:01:56 -0700 | [diff] [blame] | 61 | implements DropTarget, DragSource, DragScroller, View.OnTouchListener { |
Romain Guy | e47f55c | 2009-11-11 19:21:22 -0800 | [diff] [blame] | 62 | @SuppressWarnings({"UnusedDeclaration"}) |
Joe Onorato | 3a8820b | 2009-11-10 15:06:42 -0800 | [diff] [blame] | 63 | private static final String TAG = "Launcher.Workspace"; |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 64 | |
Michael Jurka | dee0589 | 2010-07-27 10:01:56 -0700 | [diff] [blame] | 65 | // This is how much the workspace shrinks when we enter all apps or |
| 66 | // customization mode |
| 67 | private static final float SHRINK_FACTOR = 0.16f; |
Adam Cohen | a985e59 | 2010-09-09 11:23:48 -0700 | [diff] [blame] | 68 | |
Adam Cohen | f34bab5 | 2010-09-30 14:11:56 -0700 | [diff] [blame] | 69 | // Y rotation to apply to the workspace screens |
| 70 | private static final float WORKSPACE_ROTATION = 12.5f; |
Adam Cohen | a985e59 | 2010-09-09 11:23:48 -0700 | [diff] [blame] | 71 | |
| 72 | // These are extra scale factors to apply to the mini home screens |
| 73 | // so as to achieve the desired transform |
| 74 | private static final float EXTRA_SCALE_FACTOR_0 = 0.97f; |
| 75 | private static final float EXTRA_SCALE_FACTOR_1 = 1.0f; |
Adam Cohen | e54cec8 | 2010-09-13 18:19:55 -0700 | [diff] [blame] | 76 | private static final float EXTRA_SCALE_FACTOR_2 = 1.08f; |
Adam Cohen | a985e59 | 2010-09-09 11:23:48 -0700 | [diff] [blame] | 77 | |
Adam Cohen | f34bab5 | 2010-09-30 14:11:56 -0700 | [diff] [blame] | 78 | private static final int BACKGROUND_FADE_OUT_DELAY = 300; |
| 79 | private static final int BACKGROUND_FADE_OUT_DURATION = 300; |
| 80 | private static final int BACKGROUND_FADE_IN_DURATION = 100; |
| 81 | |
Michael Jurka | 3e7c763 | 2010-10-02 16:01:03 -0700 | [diff] [blame] | 82 | // These animators are used to fade the background |
Chet Haase | 472b281 | 2010-10-14 07:02:04 -0700 | [diff] [blame] | 83 | private ObjectAnimator mBackgroundFadeInAnimation; |
| 84 | private ObjectAnimator mBackgroundFadeOutAnimation; |
Adam Cohen | f34bab5 | 2010-09-30 14:11:56 -0700 | [diff] [blame] | 85 | private float mBackgroundAlpha = 0; |
| 86 | |
Dianne Hackborn | 8f57395 | 2009-08-10 23:21:09 -0700 | [diff] [blame] | 87 | private final WallpaperManager mWallpaperManager; |
Winson Chung | aafa03c | 2010-06-11 17:34:16 -0700 | [diff] [blame] | 88 | |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 89 | private int mDefaultPage; |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 90 | |
Michael Jurka | 79212d8 | 2010-07-30 16:36:20 -0700 | [diff] [blame] | 91 | private boolean mWaitingToShrinkToBottom = false; |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 92 | |
Adam Cohen | 21f12b5 | 2010-10-07 17:15:37 -0700 | [diff] [blame] | 93 | private boolean mPageMoving = false; |
| 94 | |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 95 | /** |
| 96 | * CellInfo for the cell that is currently being dragged |
| 97 | */ |
| 98 | private CellLayout.CellInfo mDragInfo; |
Winson Chung | aafa03c | 2010-06-11 17:34:16 -0700 | [diff] [blame] | 99 | |
Jeff Sharkey | 7086428 | 2009-04-07 21:08:40 -0700 | [diff] [blame] | 100 | /** |
| 101 | * Target drop area calculated during last acceptDrop call. |
| 102 | */ |
| 103 | private int[] mTargetCell = null; |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 104 | |
Patrick Dubroy | 6569f2c | 2010-07-12 14:25:18 -0700 | [diff] [blame] | 105 | /** |
| 106 | * The CellLayout that is currently being dragged over |
| 107 | */ |
| 108 | private CellLayout mDragTargetLayout = null; |
| 109 | |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 110 | private Launcher mLauncher; |
Joe Onorato | 0589f0f | 2010-02-08 13:44:00 -0800 | [diff] [blame] | 111 | private IconCache mIconCache; |
Joe Onorato | 00acb12 | 2009-08-04 16:04:30 -0400 | [diff] [blame] | 112 | private DragController mDragController; |
Winson Chung | aafa03c | 2010-06-11 17:34:16 -0700 | [diff] [blame] | 113 | |
Michael Jurka | 4516c11 | 2010-10-07 15:13:47 -0700 | [diff] [blame] | 114 | // These are temporary variables to prevent having to allocate a new object just to |
| 115 | // return an (x, y) value from helper functions. Do NOT use them to maintain other state. |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 116 | private int[] mTempCell = new int[2]; |
Jeff Sharkey | 7086428 | 2009-04-07 21:08:40 -0700 | [diff] [blame] | 117 | private int[] mTempEstimate = new int[2]; |
Michael Jurka | 0280c3b | 2010-09-17 15:00:07 -0700 | [diff] [blame] | 118 | private float[] mTempOriginXY = new float[2]; |
Michael Jurka | a63c452 | 2010-08-19 13:52:27 -0700 | [diff] [blame] | 119 | private float[] mTempDragCoordinates = new float[2]; |
Michael Jurka | 4516c11 | 2010-10-07 15:13:47 -0700 | [diff] [blame] | 120 | private float[] mTempTouchCoordinates = new float[2]; |
| 121 | private float[] mTempCellLayoutCenterCoordinates = new float[2]; |
Michael Jurka | a63c452 | 2010-08-19 13:52:27 -0700 | [diff] [blame] | 122 | private float[] mTempDragBottomRightCoordinates = new float[2]; |
Michael Jurka | 0280c3b | 2010-09-17 15:00:07 -0700 | [diff] [blame] | 123 | private Matrix mTempInverseMatrix = new Matrix(); |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 124 | |
Adam Cohen | d22015c | 2010-07-26 22:02:18 -0700 | [diff] [blame] | 125 | private static final int DEFAULT_CELL_COUNT_X = 4; |
| 126 | private static final int DEFAULT_CELL_COUNT_Y = 4; |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 127 | |
Romain Guy | 8a73c51 | 2009-11-09 19:19:59 -0800 | [diff] [blame] | 128 | private Drawable mPreviousIndicator; |
| 129 | private Drawable mNextIndicator; |
Winson Chung | aafa03c | 2010-06-11 17:34:16 -0700 | [diff] [blame] | 130 | |
Patrick Dubroy | 1262e36 | 2010-10-06 15:49:50 -0700 | [diff] [blame] | 131 | // State variable that indicates whether the pages are small (ie when you're |
Michael Jurka | dee0589 | 2010-07-27 10:01:56 -0700 | [diff] [blame] | 132 | // in all apps or customize mode) |
Michael Jurka | c0e8fca | 2010-10-06 16:41:29 -0700 | [diff] [blame] | 133 | private boolean mIsSmall = false; |
| 134 | private boolean mIsInUnshrinkAnimation = false; |
Chet Haase | b1254a6 | 2010-09-07 13:35:00 -0700 | [diff] [blame] | 135 | private AnimatorListener mUnshrinkAnimationListener; |
Michael Jurka | 3e7c763 | 2010-10-02 16:01:03 -0700 | [diff] [blame] | 136 | private enum ShrinkPosition { |
| 137 | SHRINK_TO_TOP, SHRINK_TO_MIDDLE, SHRINK_TO_BOTTOM_HIDDEN, SHRINK_TO_BOTTOM_VISIBLE }; |
| 138 | private ShrinkPosition mShrunkenState; |
Michael Jurka | dee0589 | 2010-07-27 10:01:56 -0700 | [diff] [blame] | 139 | |
Patrick Dubroy | 1262e36 | 2010-10-06 15:49:50 -0700 | [diff] [blame] | 140 | private boolean mInScrollArea = false; |
| 141 | |
Patrick Dubroy | 8e58e91 | 2010-10-14 13:21:48 -0700 | [diff] [blame] | 142 | private final HolographicOutlineHelper mOutlineHelper = new HolographicOutlineHelper(); |
Joe Onorato | 4be866d | 2010-10-10 11:26:02 -0700 | [diff] [blame] | 143 | private Bitmap mDragOutline = null; |
Patrick Dubroy | 8e58e91 | 2010-10-14 13:21:48 -0700 | [diff] [blame] | 144 | private final Rect mTempRect = new Rect(); |
| 145 | private final int[] mTempXY = new int[2]; |
Joe Onorato | 4be866d | 2010-10-10 11:26:02 -0700 | [diff] [blame] | 146 | |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 147 | /** |
| 148 | * Used to inflate the Workspace from XML. |
| 149 | * |
| 150 | * @param context The application's context. |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 151 | * @param attrs The attributes set containing the Workspace's customization values. |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 152 | */ |
| 153 | public Workspace(Context context, AttributeSet attrs) { |
| 154 | this(context, attrs, 0); |
| 155 | } |
| 156 | |
| 157 | /** |
| 158 | * Used to inflate the Workspace from XML. |
| 159 | * |
| 160 | * @param context The application's context. |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 161 | * @param attrs The attributes set containing the Workspace's customization values. |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 162 | * @param defStyle Unused. |
| 163 | */ |
| 164 | public Workspace(Context context, AttributeSet attrs, int defStyle) { |
| 165 | super(context, attrs, defStyle); |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 166 | mContentIsRefreshable = false; |
Michael Jurka | 5f1c509 | 2010-09-03 14:15:02 -0700 | [diff] [blame] | 167 | |
| 168 | if (!LauncherApplication.isScreenXLarge()) { |
| 169 | mFadeInAdjacentScreens = false; |
| 170 | } |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 171 | |
Dianne Hackborn | 8f57395 | 2009-08-10 23:21:09 -0700 | [diff] [blame] | 172 | mWallpaperManager = WallpaperManager.getInstance(context); |
Winson Chung | aafa03c | 2010-06-11 17:34:16 -0700 | [diff] [blame] | 173 | |
| 174 | TypedArray a = context.obtainStyledAttributes(attrs, |
| 175 | R.styleable.Workspace, defStyle, 0); |
Adam Cohen | d22015c | 2010-07-26 22:02:18 -0700 | [diff] [blame] | 176 | int cellCountX = a.getInt(R.styleable.Workspace_cellCountX, DEFAULT_CELL_COUNT_X); |
| 177 | int cellCountY = a.getInt(R.styleable.Workspace_cellCountY, DEFAULT_CELL_COUNT_Y); |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 178 | mDefaultPage = a.getInt(R.styleable.Workspace_defaultScreen, 1); |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 179 | a.recycle(); |
| 180 | |
Adam Cohen | d22015c | 2010-07-26 22:02:18 -0700 | [diff] [blame] | 181 | LauncherModel.updateWorkspaceLayoutCells(cellCountX, cellCountY); |
Joe Onorato | 0d44e94 | 2009-11-16 18:20:51 -0800 | [diff] [blame] | 182 | setHapticFeedbackEnabled(false); |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 183 | |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 184 | initWorkspace(); |
| 185 | } |
| 186 | |
| 187 | /** |
| 188 | * Initializes various states for this workspace. |
| 189 | */ |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 190 | protected void initWorkspace() { |
Joe Onorato | 0589f0f | 2010-02-08 13:44:00 -0800 | [diff] [blame] | 191 | Context context = getContext(); |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 192 | mCurrentPage = mDefaultPage; |
| 193 | Launcher.setScreen(mCurrentPage); |
Joe Onorato | 0589f0f | 2010-02-08 13:44:00 -0800 | [diff] [blame] | 194 | LauncherApplication app = (LauncherApplication)context.getApplicationContext(); |
| 195 | mIconCache = app.getIconCache(); |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 196 | |
Chet Haase | 472b281 | 2010-10-14 07:02:04 -0700 | [diff] [blame] | 197 | mUnshrinkAnimationListener = new AnimatorListenerAdapter() { |
Michael Jurka | c0e8fca | 2010-10-06 16:41:29 -0700 | [diff] [blame] | 198 | public void onAnimationStart(Animator animation) { |
| 199 | mIsInUnshrinkAnimation = true; |
| 200 | } |
Chet Haase | b1254a6 | 2010-09-07 13:35:00 -0700 | [diff] [blame] | 201 | public void onAnimationEnd(Animator animation) { |
Michael Jurka | c0e8fca | 2010-10-06 16:41:29 -0700 | [diff] [blame] | 202 | mIsInUnshrinkAnimation = false; |
Michael Jurka | dee0589 | 2010-07-27 10:01:56 -0700 | [diff] [blame] | 203 | } |
Michael Jurka | dee0589 | 2010-07-27 10:01:56 -0700 | [diff] [blame] | 204 | }; |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 205 | |
| 206 | mSnapVelocity = 600; |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 207 | } |
| 208 | |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 209 | @Override |
Adam Cohen | f34bab5 | 2010-09-30 14:11:56 -0700 | [diff] [blame] | 210 | protected int getScrollMode() { |
| 211 | if (LauncherApplication.isScreenXLarge()) { |
| 212 | return SmoothPagedView.QUINTIC_MODE; |
| 213 | } else { |
| 214 | return SmoothPagedView.OVERSHOOT_MODE; |
| 215 | } |
| 216 | } |
| 217 | |
| 218 | @Override |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 219 | public void addView(View child, int index, LayoutParams params) { |
| 220 | if (!(child instanceof CellLayout)) { |
| 221 | throw new IllegalArgumentException("A Workspace can only have CellLayout children."); |
| 222 | } |
Adam Cohen | 21f12b5 | 2010-10-07 17:15:37 -0700 | [diff] [blame] | 223 | ((CellLayout) child).setOnInterceptTouchListener(this); |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 224 | super.addView(child, index, params); |
| 225 | } |
| 226 | |
| 227 | @Override |
| 228 | public void addView(View child) { |
| 229 | if (!(child instanceof CellLayout)) { |
| 230 | throw new IllegalArgumentException("A Workspace can only have CellLayout children."); |
| 231 | } |
Adam Cohen | 21f12b5 | 2010-10-07 17:15:37 -0700 | [diff] [blame] | 232 | ((CellLayout) child).setOnInterceptTouchListener(this); |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 233 | super.addView(child); |
| 234 | } |
| 235 | |
| 236 | @Override |
| 237 | public void addView(View child, int index) { |
| 238 | if (!(child instanceof CellLayout)) { |
| 239 | throw new IllegalArgumentException("A Workspace can only have CellLayout children."); |
| 240 | } |
Adam Cohen | 21f12b5 | 2010-10-07 17:15:37 -0700 | [diff] [blame] | 241 | ((CellLayout) child).setOnInterceptTouchListener(this); |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 242 | super.addView(child, index); |
| 243 | } |
| 244 | |
| 245 | @Override |
| 246 | public void addView(View child, int width, int height) { |
| 247 | if (!(child instanceof CellLayout)) { |
| 248 | throw new IllegalArgumentException("A Workspace can only have CellLayout children."); |
| 249 | } |
Adam Cohen | 21f12b5 | 2010-10-07 17:15:37 -0700 | [diff] [blame] | 250 | ((CellLayout) child).setOnInterceptTouchListener(this); |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 251 | super.addView(child, width, height); |
| 252 | } |
| 253 | |
| 254 | @Override |
| 255 | public void addView(View child, LayoutParams params) { |
| 256 | if (!(child instanceof CellLayout)) { |
| 257 | throw new IllegalArgumentException("A Workspace can only have CellLayout children."); |
| 258 | } |
Adam Cohen | 21f12b5 | 2010-10-07 17:15:37 -0700 | [diff] [blame] | 259 | ((CellLayout) child).setOnInterceptTouchListener(this); |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 260 | super.addView(child, params); |
| 261 | } |
| 262 | |
| 263 | /** |
| 264 | * @return The open folder on the current screen, or null if there is none |
| 265 | */ |
| 266 | Folder getOpenFolder() { |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 267 | CellLayout currentPage = (CellLayout) getChildAt(mCurrentPage); |
| 268 | int count = currentPage.getChildCount(); |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 269 | for (int i = 0; i < count; i++) { |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 270 | View child = currentPage.getChildAt(i); |
Winson Chung | aafa03c | 2010-06-11 17:34:16 -0700 | [diff] [blame] | 271 | if (child instanceof Folder) { |
| 272 | Folder folder = (Folder) child; |
| 273 | if (folder.getInfo().opened) |
| 274 | return folder; |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 275 | } |
| 276 | } |
| 277 | return null; |
| 278 | } |
| 279 | |
| 280 | ArrayList<Folder> getOpenFolders() { |
Michael Jurka | dee0589 | 2010-07-27 10:01:56 -0700 | [diff] [blame] | 281 | final int screenCount = getChildCount(); |
| 282 | ArrayList<Folder> folders = new ArrayList<Folder>(screenCount); |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 283 | |
Michael Jurka | dee0589 | 2010-07-27 10:01:56 -0700 | [diff] [blame] | 284 | for (int screen = 0; screen < screenCount; screen++) { |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 285 | CellLayout currentPage = (CellLayout) getChildAt(screen); |
| 286 | int count = currentPage.getChildCount(); |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 287 | for (int i = 0; i < count; i++) { |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 288 | View child = currentPage.getChildAt(i); |
Winson Chung | aafa03c | 2010-06-11 17:34:16 -0700 | [diff] [blame] | 289 | if (child instanceof Folder) { |
| 290 | Folder folder = (Folder) child; |
| 291 | if (folder.getInfo().opened) |
| 292 | folders.add(folder); |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 293 | break; |
| 294 | } |
| 295 | } |
| 296 | } |
| 297 | |
| 298 | return folders; |
| 299 | } |
| 300 | |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 301 | boolean isDefaultPageShowing() { |
| 302 | return mCurrentPage == mDefaultPage; |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 303 | } |
| 304 | |
| 305 | /** |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 306 | * Sets the current screen. |
| 307 | * |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 308 | * @param currentPage |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 309 | */ |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 310 | @Override |
| 311 | void setCurrentPage(int currentPage) { |
| 312 | super.setCurrentPage(currentPage); |
| 313 | updateWallpaperOffset(mScrollX); |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 314 | } |
| 315 | |
| 316 | /** |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 317 | * Adds the specified child in the specified screen. The position and dimension of |
| 318 | * the child are defined by x, y, spanX and spanY. |
| 319 | * |
| 320 | * @param child The child to add in one of the workspace's screens. |
| 321 | * @param screen The screen in which to add the child. |
| 322 | * @param x The X position of the child in the screen's grid. |
| 323 | * @param y The Y position of the child in the screen's grid. |
| 324 | * @param spanX The number of cells spanned horizontally by the child. |
| 325 | * @param spanY The number of cells spanned vertically by the child. |
| 326 | */ |
| 327 | void addInScreen(View child, int screen, int x, int y, int spanX, int spanY) { |
| 328 | addInScreen(child, screen, x, y, spanX, spanY, false); |
| 329 | } |
| 330 | |
Winson Chung | aafa03c | 2010-06-11 17:34:16 -0700 | [diff] [blame] | 331 | void addInFullScreen(View child, int screen) { |
| 332 | addInScreen(child, screen, 0, 0, -1, -1); |
| 333 | } |
| 334 | |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 335 | /** |
| 336 | * Adds the specified child in the specified screen. The position and dimension of |
| 337 | * the child are defined by x, y, spanX and spanY. |
| 338 | * |
| 339 | * @param child The child to add in one of the workspace's screens. |
| 340 | * @param screen The screen in which to add the child. |
| 341 | * @param x The X position of the child in the screen's grid. |
| 342 | * @param y The Y position of the child in the screen's grid. |
| 343 | * @param spanX The number of cells spanned horizontally by the child. |
| 344 | * @param spanY The number of cells spanned vertically by the child. |
| 345 | * @param insert When true, the child is inserted at the beginning of the children list. |
| 346 | */ |
| 347 | void addInScreen(View child, int screen, int x, int y, int spanX, int spanY, boolean insert) { |
| 348 | if (screen < 0 || screen >= getChildCount()) { |
Daniel Sandler | 291ad12 | 2010-05-24 16:03:53 -0400 | [diff] [blame] | 349 | Log.e(TAG, "The screen must be >= 0 and < " + getChildCount() |
| 350 | + " (was " + screen + "); skipping child"); |
| 351 | return; |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 352 | } |
| 353 | |
| 354 | final CellLayout group = (CellLayout) getChildAt(screen); |
| 355 | CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams(); |
| 356 | if (lp == null) { |
| 357 | lp = new CellLayout.LayoutParams(x, y, spanX, spanY); |
| 358 | } else { |
| 359 | lp.cellX = x; |
| 360 | lp.cellY = y; |
| 361 | lp.cellHSpan = spanX; |
| 362 | lp.cellVSpan = spanY; |
| 363 | } |
Winson Chung | aafa03c | 2010-06-11 17:34:16 -0700 | [diff] [blame] | 364 | |
Patrick Dubroy | 6569f2c | 2010-07-12 14:25:18 -0700 | [diff] [blame] | 365 | // Get the canonical child id to uniquely represent this view in this screen |
Michael Jurka | 845ba3b | 2010-09-28 17:09:46 -0700 | [diff] [blame] | 366 | int childId = LauncherModel.getCellLayoutChildId(-1, screen, x, y, spanX, spanY); |
Winson Chung | aafa03c | 2010-06-11 17:34:16 -0700 | [diff] [blame] | 367 | if (!group.addViewToCellLayout(child, insert ? 0 : -1, childId, lp)) { |
| 368 | // TODO: This branch occurs when the workspace is adding views |
| 369 | // outside of the defined grid |
Patrick Dubroy | 6569f2c | 2010-07-12 14:25:18 -0700 | [diff] [blame] | 370 | // maybe we should be deleting these items from the LauncherModel? |
Winson Chung | aafa03c | 2010-06-11 17:34:16 -0700 | [diff] [blame] | 371 | Log.w(TAG, "Failed to add to item at (" + lp.cellX + "," + lp.cellY + ") to CellLayout"); |
| 372 | } |
| 373 | |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 374 | if (!(child instanceof Folder)) { |
Joe Onorato | 0d44e94 | 2009-11-16 18:20:51 -0800 | [diff] [blame] | 375 | child.setHapticFeedbackEnabled(false); |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 376 | child.setOnLongClickListener(mLongClickListener); |
| 377 | } |
Joe Onorato | 00acb12 | 2009-08-04 16:04:30 -0400 | [diff] [blame] | 378 | if (child instanceof DropTarget) { |
Winson Chung | aafa03c | 2010-06-11 17:34:16 -0700 | [diff] [blame] | 379 | mDragController.addDropTarget((DropTarget) child); |
Joe Onorato | 00acb12 | 2009-08-04 16:04:30 -0400 | [diff] [blame] | 380 | } |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 381 | } |
| 382 | |
Michael Jurka | dee0589 | 2010-07-27 10:01:56 -0700 | [diff] [blame] | 383 | public boolean onTouch(View v, MotionEvent event) { |
| 384 | // this is an intercepted event being forwarded from a cell layout |
Michael Jurka | c0e8fca | 2010-10-06 16:41:29 -0700 | [diff] [blame] | 385 | if (mIsSmall || mIsInUnshrinkAnimation) { |
Patrick Dubroy | 2b9ff37 | 2010-09-07 17:49:27 -0700 | [diff] [blame] | 386 | mLauncher.onWorkspaceClick((CellLayout) v); |
Michael Jurka | 9622622 | 2010-08-20 00:54:40 -0700 | [diff] [blame] | 387 | return true; |
Adam Cohen | 21f12b5 | 2010-10-07 17:15:37 -0700 | [diff] [blame] | 388 | } else if (!mPageMoving) { |
| 389 | if (v == getChildAt(mCurrentPage - 1)) { |
| 390 | snapToPage(mCurrentPage - 1); |
| 391 | return true; |
| 392 | } else if (v == getChildAt(mCurrentPage + 1)) { |
| 393 | snapToPage(mCurrentPage + 1); |
| 394 | return true; |
| 395 | } |
Michael Jurka | dee0589 | 2010-07-27 10:01:56 -0700 | [diff] [blame] | 396 | } |
| 397 | return false; |
Michael Jurka | 0e26059 | 2010-06-30 17:07:39 -0700 | [diff] [blame] | 398 | } |
| 399 | |
Michael Jurka | 5f1c509 | 2010-09-03 14:15:02 -0700 | [diff] [blame] | 400 | @Override |
| 401 | public boolean dispatchUnhandledMove(View focused, int direction) { |
Michael Jurka | c0e8fca | 2010-10-06 16:41:29 -0700 | [diff] [blame] | 402 | if (mIsSmall || mIsInUnshrinkAnimation) { |
Michael Jurka | 5f1c509 | 2010-09-03 14:15:02 -0700 | [diff] [blame] | 403 | // when the home screens are shrunken, shouldn't allow side-scrolling |
| 404 | return false; |
| 405 | } |
| 406 | return super.dispatchUnhandledMove(focused, direction); |
| 407 | } |
| 408 | |
| 409 | @Override |
| 410 | public boolean onInterceptTouchEvent(MotionEvent ev) { |
Michael Jurka | c0e8fca | 2010-10-06 16:41:29 -0700 | [diff] [blame] | 411 | if (mIsSmall || mIsInUnshrinkAnimation) { |
Michael Jurka | 5f1c509 | 2010-09-03 14:15:02 -0700 | [diff] [blame] | 412 | // when the home screens are shrunken, shouldn't allow side-scrolling |
| 413 | return false; |
| 414 | } |
| 415 | return super.onInterceptTouchEvent(ev); |
| 416 | } |
| 417 | |
Michael Jurka | 1adf539 | 2010-10-18 18:10:22 -0700 | [diff] [blame] | 418 | @Override |
| 419 | protected void determineScrollingStart(MotionEvent ev) { |
| 420 | if (!mIsSmall && !mIsInUnshrinkAnimation) super.determineScrollingStart(ev); |
| 421 | } |
| 422 | |
Patrick Dubroy | 1262e36 | 2010-10-06 15:49:50 -0700 | [diff] [blame] | 423 | protected void onPageBeginMoving() { |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 424 | if (mNextPage != INVALID_PAGE) { |
| 425 | // we're snapping to a particular screen |
Michael Jurka | 16fed41 | 2010-10-01 16:12:03 -0700 | [diff] [blame] | 426 | enableChildrenCache(mCurrentPage, mNextPage); |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 427 | } else { |
| 428 | // this is when user is actively dragging a particular screen, they might |
| 429 | // swipe it either left or right (but we won't advance by more than one screen) |
Michael Jurka | 16fed41 | 2010-10-01 16:12:03 -0700 | [diff] [blame] | 430 | enableChildrenCache(mCurrentPage - 1, mCurrentPage + 1); |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 431 | } |
Adam Cohen | f34bab5 | 2010-09-30 14:11:56 -0700 | [diff] [blame] | 432 | showOutlines(); |
Adam Cohen | 21f12b5 | 2010-10-07 17:15:37 -0700 | [diff] [blame] | 433 | mPageMoving = true; |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 434 | } |
| 435 | |
Patrick Dubroy | 1262e36 | 2010-10-06 15:49:50 -0700 | [diff] [blame] | 436 | protected void onPageEndMoving() { |
Michael Jurka | 16fed41 | 2010-10-01 16:12:03 -0700 | [diff] [blame] | 437 | clearChildrenCache(); |
Patrick Dubroy | 1262e36 | 2010-10-06 15:49:50 -0700 | [diff] [blame] | 438 | // Hide the outlines, as long as we're not dragging |
| 439 | if (!mDragController.dragging()) { |
| 440 | hideOutlines(); |
| 441 | } |
Adam Cohen | 21f12b5 | 2010-10-07 17:15:37 -0700 | [diff] [blame] | 442 | mPageMoving = false; |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 443 | } |
| 444 | |
| 445 | @Override |
| 446 | protected void notifyPageSwitchListener() { |
| 447 | super.notifyPageSwitchListener(); |
| 448 | |
| 449 | if (mPreviousIndicator != null) { |
| 450 | // if we know the next page, we show the indication for it right away; it looks |
| 451 | // weird if the indicators are lagging |
| 452 | int page = mNextPage; |
| 453 | if (page == INVALID_PAGE) { |
| 454 | page = mCurrentPage; |
| 455 | } |
| 456 | mPreviousIndicator.setLevel(page); |
| 457 | mNextIndicator.setLevel(page); |
| 458 | } |
| 459 | Launcher.setScreen(mCurrentPage); |
| 460 | }; |
| 461 | |
Dianne Hackborn | 8f57395 | 2009-08-10 23:21:09 -0700 | [diff] [blame] | 462 | private void updateWallpaperOffset() { |
Romain Guy | 798300c | 2009-08-11 14:43:29 -0700 | [diff] [blame] | 463 | updateWallpaperOffset(getChildAt(getChildCount() - 1).getRight() - (mRight - mLeft)); |
| 464 | } |
| 465 | |
| 466 | private void updateWallpaperOffset(int scrollRange) { |
Winson Chung | 86f7753 | 2010-08-24 11:08:22 -0700 | [diff] [blame] | 467 | final boolean isStaticWallpaper = (mWallpaperManager != null) && |
| 468 | (mWallpaperManager.getWallpaperInfo() == null); |
| 469 | if (LauncherApplication.isScreenXLarge() && !isStaticWallpaper) { |
| 470 | IBinder token = getWindowToken(); |
| 471 | if (token != null) { |
| 472 | mWallpaperManager.setWallpaperOffsetSteps(1.0f / (getChildCount() - 1), 0 ); |
| 473 | mWallpaperManager.setWallpaperOffsets(getWindowToken(), |
| 474 | Math.max(0.f, Math.min(mScrollX/(float)scrollRange, 1.f)), 0); |
| 475 | } |
Joe Onorato | 956091b | 2010-02-19 12:47:40 -0800 | [diff] [blame] | 476 | } |
Dianne Hackborn | 8f57395 | 2009-08-10 23:21:09 -0700 | [diff] [blame] | 477 | } |
Winson Chung | aafa03c | 2010-06-11 17:34:16 -0700 | [diff] [blame] | 478 | |
Adam Cohen | f34bab5 | 2010-09-30 14:11:56 -0700 | [diff] [blame] | 479 | public void showOutlines() { |
Michael Jurka | 3e7c763 | 2010-10-02 16:01:03 -0700 | [diff] [blame] | 480 | if (!mIsSmall && !mIsInUnshrinkAnimation) { |
| 481 | if (mBackgroundFadeOutAnimation != null) mBackgroundFadeOutAnimation.cancel(); |
| 482 | if (mBackgroundFadeInAnimation != null) mBackgroundFadeInAnimation.cancel(); |
Chet Haase | 472b281 | 2010-10-14 07:02:04 -0700 | [diff] [blame] | 483 | mBackgroundFadeInAnimation = ObjectAnimator.ofFloat(this, "backgroundAlpha", 1.0f); |
| 484 | mBackgroundFadeInAnimation.setDuration(BACKGROUND_FADE_IN_DURATION); |
Michael Jurka | 3e7c763 | 2010-10-02 16:01:03 -0700 | [diff] [blame] | 485 | mBackgroundFadeInAnimation.start(); |
| 486 | } |
Adam Cohen | f34bab5 | 2010-09-30 14:11:56 -0700 | [diff] [blame] | 487 | } |
| 488 | |
| 489 | public void hideOutlines() { |
Michael Jurka | 3e7c763 | 2010-10-02 16:01:03 -0700 | [diff] [blame] | 490 | if (!mIsSmall && !mIsInUnshrinkAnimation) { |
| 491 | if (mBackgroundFadeInAnimation != null) mBackgroundFadeInAnimation.cancel(); |
| 492 | if (mBackgroundFadeOutAnimation != null) mBackgroundFadeOutAnimation.cancel(); |
Chet Haase | 472b281 | 2010-10-14 07:02:04 -0700 | [diff] [blame] | 493 | mBackgroundFadeOutAnimation = ObjectAnimator.ofFloat(this, "backgroundAlpha", 0.0f); |
| 494 | mBackgroundFadeOutAnimation.setDuration(BACKGROUND_FADE_OUT_DURATION); |
Michael Jurka | 3e7c763 | 2010-10-02 16:01:03 -0700 | [diff] [blame] | 495 | mBackgroundFadeOutAnimation.setStartDelay(BACKGROUND_FADE_OUT_DELAY); |
| 496 | mBackgroundFadeOutAnimation.start(); |
| 497 | } |
Adam Cohen | f34bab5 | 2010-09-30 14:11:56 -0700 | [diff] [blame] | 498 | } |
| 499 | |
| 500 | public void setBackgroundAlpha(float alpha) { |
| 501 | mBackgroundAlpha = alpha; |
| 502 | for (int i = 0; i < getChildCount(); i++) { |
| 503 | CellLayout cl = (CellLayout) getChildAt(i); |
| 504 | cl.setBackgroundAlpha(alpha); |
| 505 | } |
| 506 | } |
| 507 | |
| 508 | public float getBackgroundAlpha() { |
| 509 | return mBackgroundAlpha; |
| 510 | } |
| 511 | |
| 512 | @Override |
| 513 | protected void screenScrolled(int screenCenter) { |
Adam Cohen | 21f12b5 | 2010-10-07 17:15:37 -0700 | [diff] [blame] | 514 | final int halfScreenSize = getMeasuredWidth() / 2; |
| 515 | for (int i = 0; i < getChildCount(); i++) { |
Adam Cohen | f34bab5 | 2010-09-30 14:11:56 -0700 | [diff] [blame] | 516 | View v = getChildAt(i); |
| 517 | if (v != null) { |
Adam Cohen | 21f12b5 | 2010-10-07 17:15:37 -0700 | [diff] [blame] | 518 | int totalDistance = v.getMeasuredWidth() + mPageSpacing; |
| 519 | int delta = screenCenter - (getChildOffset(i) - |
| 520 | getRelativeChildOffset(i) + halfScreenSize); |
Adam Cohen | f34bab5 | 2010-09-30 14:11:56 -0700 | [diff] [blame] | 521 | |
Adam Cohen | 21f12b5 | 2010-10-07 17:15:37 -0700 | [diff] [blame] | 522 | float scrollProgress = delta/(totalDistance*1.0f); |
| 523 | scrollProgress = Math.min(scrollProgress, 1.0f); |
| 524 | scrollProgress = Math.max(scrollProgress, -1.0f); |
Adam Cohen | f34bab5 | 2010-09-30 14:11:56 -0700 | [diff] [blame] | 525 | |
Adam Cohen | 21f12b5 | 2010-10-07 17:15:37 -0700 | [diff] [blame] | 526 | float rotation = WORKSPACE_ROTATION * scrollProgress; |
| 527 | v.setRotationY(rotation); |
Adam Cohen | f34bab5 | 2010-09-30 14:11:56 -0700 | [diff] [blame] | 528 | } |
| 529 | } |
| 530 | } |
| 531 | |
Joe Onorato | 00acb12 | 2009-08-04 16:04:30 -0400 | [diff] [blame] | 532 | protected void onAttachedToWindow() { |
| 533 | super.onAttachedToWindow(); |
Joe Onorato | 956091b | 2010-02-19 12:47:40 -0800 | [diff] [blame] | 534 | computeScroll(); |
Joe Onorato | 00acb12 | 2009-08-04 16:04:30 -0400 | [diff] [blame] | 535 | mDragController.setWindowToken(getWindowToken()); |
| 536 | } |
| 537 | |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 538 | @Override |
Michael Jurka | 28750fb | 2010-09-24 17:43:49 -0700 | [diff] [blame] | 539 | protected void onLayout(boolean changed, int left, int top, int right, int bottom) { |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 540 | super.onLayout(changed, left, top, right, bottom); |
Winson Chung | aafa03c | 2010-06-11 17:34:16 -0700 | [diff] [blame] | 541 | |
Michael Jurka | 79212d8 | 2010-07-30 16:36:20 -0700 | [diff] [blame] | 542 | // if shrinkToBottom() is called on initialization, it has to be deferred |
| 543 | // until after the first call to onLayout so that it has the correct width |
| 544 | if (mWaitingToShrinkToBottom) { |
| 545 | shrinkToBottom(false); |
| 546 | mWaitingToShrinkToBottom = false; |
| 547 | } |
| 548 | |
Winson Chung | aafa03c | 2010-06-11 17:34:16 -0700 | [diff] [blame] | 549 | if (LauncherApplication.isInPlaceRotationEnabled()) { |
| 550 | // When the device is rotated, the scroll position of the current screen |
| 551 | // needs to be refreshed |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 552 | setCurrentPage(getCurrentPage()); |
Winson Chung | aafa03c | 2010-06-11 17:34:16 -0700 | [diff] [blame] | 553 | } |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 554 | } |
| 555 | |
| 556 | @Override |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 557 | protected void dispatchDraw(Canvas canvas) { |
Michael Jurka | c0e8fca | 2010-10-06 16:41:29 -0700 | [diff] [blame] | 558 | if (mIsSmall || mIsInUnshrinkAnimation) { |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 559 | // Draw all the workspaces if we're small |
| 560 | final int pageCount = getChildCount(); |
| 561 | final long drawingTime = getDrawingTime(); |
| 562 | for (int i = 0; i < pageCount; i++) { |
| 563 | final View page = (View) getChildAt(i); |
| 564 | |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 565 | drawChild(canvas, page, drawingTime); |
| 566 | } |
| 567 | } else { |
| 568 | super.dispatchDraw(canvas); |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 569 | } |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 570 | } |
| 571 | |
| 572 | @Override |
| 573 | protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) { |
Joe Onorato | 6788621 | 2009-09-14 19:05:05 -0400 | [diff] [blame] | 574 | if (!mLauncher.isAllAppsVisible()) { |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 575 | final Folder openFolder = getOpenFolder(); |
| 576 | if (openFolder != null) { |
| 577 | return openFolder.requestFocus(direction, previouslyFocusedRect); |
| 578 | } else { |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 579 | return super.onRequestFocusInDescendants(direction, previouslyFocusedRect); |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 580 | } |
| 581 | } |
| 582 | return false; |
| 583 | } |
| 584 | |
| 585 | @Override |
Romain Guy | c2e24c0 | 2009-06-01 16:11:41 -0700 | [diff] [blame] | 586 | public void addFocusables(ArrayList<View> views, int direction, int focusableMode) { |
Joe Onorato | 6788621 | 2009-09-14 19:05:05 -0400 | [diff] [blame] | 587 | if (!mLauncher.isAllAppsVisible()) { |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 588 | final Folder openFolder = getOpenFolder(); |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 589 | if (openFolder != null) { |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 590 | openFolder.addFocusables(views, direction); |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 591 | } else { |
| 592 | super.addFocusables(views, direction, focusableMode); |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 593 | } |
| 594 | } |
| 595 | } |
| 596 | |
| 597 | @Override |
Joe Onorato | 7bb1749 | 2009-09-24 17:51:01 -0700 | [diff] [blame] | 598 | public boolean dispatchTouchEvent(MotionEvent ev) { |
| 599 | if (ev.getAction() == MotionEvent.ACTION_DOWN) { |
Michael Jurka | 54dd754 | 2010-07-30 14:47:52 -0700 | [diff] [blame] | 600 | // (In XLarge mode, the workspace is shrunken below all apps, and responds to taps |
| 601 | // ie when you click on a mini-screen, it zooms back to that screen) |
Joe Onorato | 6b4adbc | 2010-09-01 12:13:25 -0700 | [diff] [blame] | 602 | if (!LauncherApplication.isScreenXLarge() && mLauncher.isAllAppsVisible()) { |
Joe Onorato | 7bb1749 | 2009-09-24 17:51:01 -0700 | [diff] [blame] | 603 | return false; |
| 604 | } |
| 605 | } |
| 606 | return super.dispatchTouchEvent(ev); |
| 607 | } |
| 608 | |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 609 | void enableChildrenCache(int fromPage, int toPage) { |
| 610 | if (fromPage > toPage) { |
| 611 | final int temp = fromPage; |
| 612 | fromPage = toPage; |
| 613 | toPage = temp; |
Mike Cleron | 3a2b3f2 | 2009-11-05 17:17:42 -0800 | [diff] [blame] | 614 | } |
Winson Chung | aafa03c | 2010-06-11 17:34:16 -0700 | [diff] [blame] | 615 | |
Michael Jurka | dee0589 | 2010-07-27 10:01:56 -0700 | [diff] [blame] | 616 | final int screenCount = getChildCount(); |
Adam Powell | fea5d02 | 2010-04-29 11:42:45 -0700 | [diff] [blame] | 617 | |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 618 | fromPage = Math.max(fromPage, 0); |
| 619 | toPage = Math.min(toPage, screenCount - 1); |
Adam Powell | fea5d02 | 2010-04-29 11:42:45 -0700 | [diff] [blame] | 620 | |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 621 | for (int i = fromPage; i <= toPage; i++) { |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 622 | final CellLayout layout = (CellLayout) getChildAt(i); |
| 623 | layout.setChildrenDrawnWithCacheEnabled(true); |
| 624 | layout.setChildrenDrawingCacheEnabled(true); |
| 625 | } |
| 626 | } |
| 627 | |
| 628 | void clearChildrenCache() { |
Michael Jurka | dee0589 | 2010-07-27 10:01:56 -0700 | [diff] [blame] | 629 | final int screenCount = getChildCount(); |
| 630 | for (int i = 0; i < screenCount; i++) { |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 631 | final CellLayout layout = (CellLayout) getChildAt(i); |
| 632 | layout.setChildrenDrawnWithCacheEnabled(false); |
| 633 | } |
| 634 | } |
| 635 | |
| 636 | @Override |
| 637 | public boolean onTouchEvent(MotionEvent ev) { |
Joe Onorato | 2bc6b7c | 2009-10-01 14:08:30 -0700 | [diff] [blame] | 638 | if (mLauncher.isAllAppsVisible()) { |
| 639 | // Cancel any scrolling that is in progress. |
| 640 | if (!mScroller.isFinished()) { |
| 641 | mScroller.abortAnimation(); |
| 642 | } |
Michael Jurka | 3e7c763 | 2010-10-02 16:01:03 -0700 | [diff] [blame] | 643 | setCurrentPage(mCurrentPage); |
Joe Onorato | 7c312c1 | 2009-08-13 21:36:53 -0700 | [diff] [blame] | 644 | return false; // We don't want the events. Let them fall through to the all apps view. |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 645 | } |
| 646 | |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 647 | return super.onTouchEvent(ev); |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 648 | } |
Winson Chung | aafa03c | 2010-06-11 17:34:16 -0700 | [diff] [blame] | 649 | |
Michael Jurka | 01f0ed4 | 2010-08-20 00:41:17 -0700 | [diff] [blame] | 650 | public boolean isSmall() { |
| 651 | return mIsSmall; |
| 652 | } |
| 653 | |
Patrick Dubroy | 6b509c1 | 2010-08-23 15:08:16 -0700 | [diff] [blame] | 654 | void shrinkToTop(boolean animated) { |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 655 | shrink(ShrinkPosition.SHRINK_TO_TOP, animated); |
Michael Jurka | 01f0ed4 | 2010-08-20 00:41:17 -0700 | [diff] [blame] | 656 | } |
| 657 | |
| 658 | void shrinkToMiddle() { |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 659 | shrink(ShrinkPosition.SHRINK_TO_MIDDLE, true); |
Michael Jurka | 213d963 | 2010-07-28 11:29:25 -0700 | [diff] [blame] | 660 | } |
| 661 | |
| 662 | void shrinkToBottom() { |
Michael Jurka | 79212d8 | 2010-07-30 16:36:20 -0700 | [diff] [blame] | 663 | shrinkToBottom(true); |
| 664 | } |
| 665 | |
| 666 | void shrinkToBottom(boolean animated) { |
| 667 | if (mFirstLayout) { |
| 668 | // (mFirstLayout == "first layout has not happened yet") |
| 669 | // if we get a call to shrink() as part of our initialization (for example, if |
| 670 | // Launcher is started in All Apps mode) then we need to wait for a layout call |
| 671 | // to get our width so we can layout the mini-screen views correctly |
| 672 | mWaitingToShrinkToBottom = true; |
| 673 | } else { |
Michael Jurka | 3e7c763 | 2010-10-02 16:01:03 -0700 | [diff] [blame] | 674 | shrink(ShrinkPosition.SHRINK_TO_BOTTOM_HIDDEN, animated); |
Michael Jurka | 79212d8 | 2010-07-30 16:36:20 -0700 | [diff] [blame] | 675 | } |
Michael Jurka | 213d963 | 2010-07-28 11:29:25 -0700 | [diff] [blame] | 676 | } |
| 677 | |
Adam Cohen | a985e59 | 2010-09-09 11:23:48 -0700 | [diff] [blame] | 678 | private float getYScaleForScreen(int screen) { |
| 679 | int x = Math.abs(screen - 2); |
| 680 | |
| 681 | // TODO: This should be generalized for use with arbitrary rotation angles. |
| 682 | switch(x) { |
| 683 | case 0: return EXTRA_SCALE_FACTOR_0; |
| 684 | case 1: return EXTRA_SCALE_FACTOR_1; |
| 685 | case 2: return EXTRA_SCALE_FACTOR_2; |
| 686 | } |
| 687 | return 1.0f; |
| 688 | } |
| 689 | |
Michael Jurka | dee0589 | 2010-07-27 10:01:56 -0700 | [diff] [blame] | 690 | // we use this to shrink the workspace for the all apps view and the customize view |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 691 | private void shrink(ShrinkPosition shrinkPosition, boolean animated) { |
Michael Jurka | dee0589 | 2010-07-27 10:01:56 -0700 | [diff] [blame] | 692 | mIsSmall = true; |
Michael Jurka | 3e7c763 | 2010-10-02 16:01:03 -0700 | [diff] [blame] | 693 | mShrunkenState = shrinkPosition; |
| 694 | |
| 695 | // Stop any scrolling, move to the current page right away |
| 696 | setCurrentPage(mCurrentPage); |
| 697 | updateWhichPagesAcceptDrops(mShrunkenState); |
| 698 | |
Michael Jurka | 5f1c509 | 2010-09-03 14:15:02 -0700 | [diff] [blame] | 699 | // we intercept and reject all touch events when we're small, so be sure to reset the state |
| 700 | mTouchState = TOUCH_STATE_REST; |
| 701 | mActivePointerId = INVALID_POINTER; |
| 702 | |
Patrick Dubroy | 7247f63 | 2010-08-04 16:02:59 -0700 | [diff] [blame] | 703 | final Resources res = getResources(); |
Michael Jurka | dee0589 | 2010-07-27 10:01:56 -0700 | [diff] [blame] | 704 | final int screenWidth = getWidth(); |
Michael Jurka | 213d963 | 2010-07-28 11:29:25 -0700 | [diff] [blame] | 705 | final int screenHeight = getHeight(); |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 706 | |
| 707 | // Making the assumption that all pages have the same width as the 0th |
| 708 | final int pageWidth = getChildAt(0).getMeasuredWidth(); |
| 709 | final int pageHeight = getChildAt(0).getMeasuredHeight(); |
| 710 | |
| 711 | final int scaledPageWidth = (int) (SHRINK_FACTOR * pageWidth); |
| 712 | final int scaledPageHeight = (int) (SHRINK_FACTOR * pageHeight); |
Adam Cohen | a985e59 | 2010-09-09 11:23:48 -0700 | [diff] [blame] | 713 | final float extraScaledSpacing = res.getDimension(R.dimen.smallScreenExtraSpacing); |
Michael Jurka | dee0589 | 2010-07-27 10:01:56 -0700 | [diff] [blame] | 714 | |
| 715 | final int screenCount = getChildCount(); |
Adam Cohen | a985e59 | 2010-09-09 11:23:48 -0700 | [diff] [blame] | 716 | float totalWidth = screenCount * scaledPageWidth + (screenCount - 1) * extraScaledSpacing; |
Michael Jurka | 213d963 | 2010-07-28 11:29:25 -0700 | [diff] [blame] | 717 | |
Winson Chung | df4b83d | 2010-10-20 17:49:27 -0700 | [diff] [blame^] | 718 | boolean isPortrait = getMeasuredHeight() > getMeasuredWidth(); |
| 719 | float newY = (isPortrait ? |
| 720 | getResources().getDimension(R.dimen.smallScreenVerticalMarginPortrait) : |
| 721 | getResources().getDimension(R.dimen.smallScreenVerticalMarginLandscape)); |
Michael Jurka | 3e7c763 | 2010-10-02 16:01:03 -0700 | [diff] [blame] | 722 | float finalAlpha = 1.0f; |
| 723 | float extraShrinkFactor = 1.0f; |
| 724 | if (shrinkPosition == ShrinkPosition.SHRINK_TO_BOTTOM_VISIBLE) { |
| 725 | newY = screenHeight - newY - scaledPageHeight; |
| 726 | } else if (shrinkPosition == ShrinkPosition.SHRINK_TO_BOTTOM_HIDDEN) { |
| 727 | |
| 728 | // We shrink and disappear to nothing in the case of all apps |
| 729 | // (which is when we shrink to the bottom) |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 730 | newY = screenHeight - newY - scaledPageHeight; |
Michael Jurka | 3e7c763 | 2010-10-02 16:01:03 -0700 | [diff] [blame] | 731 | finalAlpha = 0.0f; |
| 732 | extraShrinkFactor = 0.1f; |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 733 | } else if (shrinkPosition == ShrinkPosition.SHRINK_TO_MIDDLE) { |
Winson Chung | b0b2e6f | 2010-10-12 17:49:56 -0700 | [diff] [blame] | 734 | newY = screenHeight / 2 - scaledPageHeight / 2; |
| 735 | finalAlpha = 1.0f; |
| 736 | } else if (shrinkPosition == ShrinkPosition.SHRINK_TO_TOP) { |
| 737 | newY = screenHeight / 10; |
Michael Jurka | 213d963 | 2010-07-28 11:29:25 -0700 | [diff] [blame] | 738 | } |
Michael Jurka | dee0589 | 2010-07-27 10:01:56 -0700 | [diff] [blame] | 739 | |
| 740 | // We animate all the screens to the centered position in workspace |
| 741 | // At the same time, the screens become greyed/dimmed |
| 742 | |
| 743 | // newX is initialized to the left-most position of the centered screens |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 744 | float newX = mScroller.getFinalX() + screenWidth / 2 - totalWidth / 2; |
Adam Cohen | a985e59 | 2010-09-09 11:23:48 -0700 | [diff] [blame] | 745 | |
| 746 | // We are going to scale about the center of the view, so we need to adjust the positions |
| 747 | // of the views accordingly |
| 748 | newX -= (pageWidth - scaledPageWidth) / 2.0f; |
| 749 | newY -= (pageHeight - scaledPageHeight) / 2.0f; |
Michael Jurka | dee0589 | 2010-07-27 10:01:56 -0700 | [diff] [blame] | 750 | for (int i = 0; i < screenCount; i++) { |
| 751 | CellLayout cl = (CellLayout) getChildAt(i); |
Adam Cohen | a985e59 | 2010-09-09 11:23:48 -0700 | [diff] [blame] | 752 | |
Adam Cohen | f34bab5 | 2010-09-30 14:11:56 -0700 | [diff] [blame] | 753 | float rotation = (-i + 2) * WORKSPACE_ROTATION; |
Adam Cohen | a985e59 | 2010-09-09 11:23:48 -0700 | [diff] [blame] | 754 | float rotationScaleX = (float) (1.0f / Math.cos(Math.PI * rotation / 180.0f)); |
| 755 | float rotationScaleY = getYScaleForScreen(i); |
| 756 | |
Michael Jurka | 79212d8 | 2010-07-30 16:36:20 -0700 | [diff] [blame] | 757 | if (animated) { |
Patrick Dubroy | 7247f63 | 2010-08-04 16:02:59 -0700 | [diff] [blame] | 758 | final int duration = res.getInteger(R.integer.config_workspaceShrinkTime); |
Chet Haase | 472b281 | 2010-10-14 07:02:04 -0700 | [diff] [blame] | 759 | ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(cl, |
| 760 | PropertyValuesHolder.ofFloat("x", newX), |
| 761 | PropertyValuesHolder.ofFloat("y", newY), |
| 762 | PropertyValuesHolder.ofFloat("scaleX", |
Michael Jurka | 3e7c763 | 2010-10-02 16:01:03 -0700 | [diff] [blame] | 763 | SHRINK_FACTOR * rotationScaleX * extraShrinkFactor), |
Chet Haase | 472b281 | 2010-10-14 07:02:04 -0700 | [diff] [blame] | 764 | PropertyValuesHolder.ofFloat("scaleY", |
Michael Jurka | 3e7c763 | 2010-10-02 16:01:03 -0700 | [diff] [blame] | 765 | SHRINK_FACTOR * rotationScaleY * extraShrinkFactor), |
Chet Haase | 472b281 | 2010-10-14 07:02:04 -0700 | [diff] [blame] | 766 | PropertyValuesHolder.ofFloat("backgroundAlpha", finalAlpha), |
| 767 | PropertyValuesHolder.ofFloat("alpha", finalAlpha), |
| 768 | PropertyValuesHolder.ofFloat("rotationY", rotation)); |
| 769 | anim.setDuration(duration); |
| 770 | anim.start(); |
Michael Jurka | 79212d8 | 2010-07-30 16:36:20 -0700 | [diff] [blame] | 771 | } else { |
| 772 | cl.setX((int)newX); |
| 773 | cl.setY((int)newY); |
Adam Cohen | f34bab5 | 2010-09-30 14:11:56 -0700 | [diff] [blame] | 774 | cl.setScaleX(SHRINK_FACTOR * rotationScaleX); |
| 775 | cl.setScaleY(SHRINK_FACTOR * rotationScaleY); |
Michael Jurka | 5f1c509 | 2010-09-03 14:15:02 -0700 | [diff] [blame] | 776 | cl.setBackgroundAlpha(1.0f); |
Michael Jurka | 3e7c763 | 2010-10-02 16:01:03 -0700 | [diff] [blame] | 777 | cl.setAlpha(finalAlpha); |
Adam Cohen | a985e59 | 2010-09-09 11:23:48 -0700 | [diff] [blame] | 778 | cl.setRotationY(rotation); |
Michael Jurka | 79212d8 | 2010-07-30 16:36:20 -0700 | [diff] [blame] | 779 | } |
Michael Jurka | dee0589 | 2010-07-27 10:01:56 -0700 | [diff] [blame] | 780 | // increment newX for the next screen |
Adam Cohen | a985e59 | 2010-09-09 11:23:48 -0700 | [diff] [blame] | 781 | newX += scaledPageWidth + extraScaledSpacing; |
Michael Jurka | dee0589 | 2010-07-27 10:01:56 -0700 | [diff] [blame] | 782 | } |
| 783 | setChildrenDrawnWithCacheEnabled(true); |
Michael Jurka | dee0589 | 2010-07-27 10:01:56 -0700 | [diff] [blame] | 784 | } |
| 785 | |
Michael Jurka | 3e7c763 | 2010-10-02 16:01:03 -0700 | [diff] [blame] | 786 | |
| 787 | private void updateWhichPagesAcceptDrops(ShrinkPosition state) { |
| 788 | updateWhichPagesAcceptDropsHelper(state, false, 1, 1); |
| 789 | } |
| 790 | |
| 791 | |
| 792 | private void updateWhichPagesAcceptDropsDuringDrag(ShrinkPosition state, int spanX, int spanY) { |
| 793 | updateWhichPagesAcceptDropsHelper(state, true, spanX, spanY); |
| 794 | } |
| 795 | |
| 796 | private void updateWhichPagesAcceptDropsHelper( |
| 797 | ShrinkPosition state, boolean isDragHappening, int spanX, int spanY) { |
| 798 | final int screenCount = getChildCount(); |
| 799 | for (int i = 0; i < screenCount; i++) { |
| 800 | CellLayout cl = (CellLayout) getChildAt(i); |
| 801 | |
| 802 | switch (state) { |
| 803 | case SHRINK_TO_TOP: |
| 804 | if (!isDragHappening) { |
| 805 | boolean showDropHighlight = i == mCurrentPage; |
| 806 | cl.setAcceptsDrops(showDropHighlight); |
| 807 | break; |
| 808 | } |
| 809 | // otherwise, fall through below and mark non-full screens as accepting drops |
| 810 | case SHRINK_TO_BOTTOM_HIDDEN: |
| 811 | case SHRINK_TO_BOTTOM_VISIBLE: |
| 812 | if (!isDragHappening) { |
| 813 | // even if a drag isn't happening, we don't want to show a screen as |
| 814 | // accepting drops if it doesn't have at least one free cell |
| 815 | spanX = 1; |
| 816 | spanY = 1; |
| 817 | } |
| 818 | // the page accepts drops if we can find at least one empty spot |
| 819 | cl.setAcceptsDrops(cl.findCellForSpan(null, spanX, spanY)); |
| 820 | break; |
| 821 | default: |
| 822 | throw new RuntimeException( |
| 823 | "updateWhichPagesAcceptDropsHelper passed an unhandled ShrinkPosition"); |
| 824 | } |
| 825 | } |
| 826 | } |
| 827 | |
| 828 | /* |
| 829 | * |
| 830 | * We call these methods (onDragStartedWithItemSpans/onDragStartedWithItemMinSize) whenever we |
| 831 | * start a drag in Launcher, regardless of whether the drag has ever entered the Workspace |
| 832 | * |
| 833 | * These methods mark the appropriate pages as accepting drops (which alters their visual |
| 834 | * appearance) and, if the pages are hidden, makes them visible. |
| 835 | * |
| 836 | */ |
| 837 | public void onDragStartedWithItemSpans(int spanX, int spanY) { |
| 838 | updateWhichPagesAcceptDropsDuringDrag(mShrunkenState, spanX, spanY); |
| 839 | if (mShrunkenState == ShrinkPosition.SHRINK_TO_BOTTOM_HIDDEN) { |
| 840 | shrink(ShrinkPosition.SHRINK_TO_BOTTOM_VISIBLE, true); |
| 841 | } |
| 842 | } |
| 843 | |
| 844 | public void onDragStartedWithItemMinSize(int minWidth, int minHeight) { |
| 845 | int[] spanXY = CellLayout.rectToCell(getResources(), minWidth, minHeight, null); |
| 846 | onDragStartedWithItemSpans(spanXY[0], spanXY[1]); |
| 847 | } |
| 848 | |
| 849 | // we call this method whenever a drag and drop in Launcher finishes, even if Workspace was |
| 850 | // never dragged over |
| 851 | public void onDragStopped() { |
| 852 | updateWhichPagesAcceptDrops(mShrunkenState); |
| 853 | if (mShrunkenState == ShrinkPosition.SHRINK_TO_BOTTOM_VISIBLE) { |
| 854 | shrink(ShrinkPosition.SHRINK_TO_BOTTOM_HIDDEN, true); |
| 855 | } |
| 856 | } |
| 857 | |
Michael Jurka | dee0589 | 2010-07-27 10:01:56 -0700 | [diff] [blame] | 858 | // We call this when we trigger an unshrink by clicking on the CellLayout cl |
Patrick Dubroy | 2b9ff37 | 2010-09-07 17:49:27 -0700 | [diff] [blame] | 859 | public void unshrink(CellLayout clThatWasClicked) { |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 860 | int newCurrentPage = mCurrentPage; |
Michael Jurka | 4cb3724 | 2010-08-09 21:05:32 -0700 | [diff] [blame] | 861 | final int screenCount = getChildCount(); |
| 862 | for (int i = 0; i < screenCount; i++) { |
| 863 | if (getChildAt(i) == clThatWasClicked) { |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 864 | newCurrentPage = i; |
Michael Jurka | dee0589 | 2010-07-27 10:01:56 -0700 | [diff] [blame] | 865 | } |
Michael Jurka | 4cb3724 | 2010-08-09 21:05:32 -0700 | [diff] [blame] | 866 | } |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 867 | unshrink(newCurrentPage); |
Michael Jurka | 4cb3724 | 2010-08-09 21:05:32 -0700 | [diff] [blame] | 868 | } |
| 869 | |
Adam Cohen | 21f12b5 | 2010-10-07 17:15:37 -0700 | [diff] [blame] | 870 | @Override |
| 871 | protected boolean handlePagingClicks() { |
| 872 | return true; |
| 873 | } |
| 874 | |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 875 | private void unshrink(int newCurrentPage) { |
Michael Jurka | 4cb3724 | 2010-08-09 21:05:32 -0700 | [diff] [blame] | 876 | if (mIsSmall) { |
Michael Jurka | 5f1c509 | 2010-09-03 14:15:02 -0700 | [diff] [blame] | 877 | int newX = getChildOffset(newCurrentPage) - getRelativeChildOffset(newCurrentPage); |
| 878 | int delta = newX - mScrollX; |
Michael Jurka | 4cb3724 | 2010-08-09 21:05:32 -0700 | [diff] [blame] | 879 | |
| 880 | final int screenCount = getChildCount(); |
Michael Jurka | b0f28bd | 2010-07-30 11:58:59 -0700 | [diff] [blame] | 881 | for (int i = 0; i < screenCount; i++) { |
| 882 | CellLayout cl = (CellLayout) getChildAt(i); |
| 883 | cl.setX(cl.getX() + delta); |
| 884 | } |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 885 | setCurrentPage(newCurrentPage); |
Michael Jurka | c0e8fca | 2010-10-06 16:41:29 -0700 | [diff] [blame] | 886 | unshrink(); |
Michael Jurka | b0f28bd | 2010-07-30 11:58:59 -0700 | [diff] [blame] | 887 | } |
Michael Jurka | dee0589 | 2010-07-27 10:01:56 -0700 | [diff] [blame] | 888 | } |
| 889 | |
Michael Jurka | 4cb3724 | 2010-08-09 21:05:32 -0700 | [diff] [blame] | 890 | void unshrink() { |
| 891 | unshrink(true); |
| 892 | } |
| 893 | |
| 894 | void unshrink(boolean animated) { |
Michael Jurka | b0f28bd | 2010-07-30 11:58:59 -0700 | [diff] [blame] | 895 | if (mIsSmall) { |
Michael Jurka | c0e8fca | 2010-10-06 16:41:29 -0700 | [diff] [blame] | 896 | mIsSmall = false; |
Chet Haase | b1254a6 | 2010-09-07 13:35:00 -0700 | [diff] [blame] | 897 | AnimatorSet s = new AnimatorSet(); |
Michael Jurka | b0f28bd | 2010-07-30 11:58:59 -0700 | [diff] [blame] | 898 | final int screenCount = getChildCount(); |
Michael Jurka | 4cb3724 | 2010-08-09 21:05:32 -0700 | [diff] [blame] | 899 | |
| 900 | final int duration = getResources().getInteger(R.integer.config_workspaceUnshrinkTime); |
Michael Jurka | b0f28bd | 2010-07-30 11:58:59 -0700 | [diff] [blame] | 901 | for (int i = 0; i < screenCount; i++) { |
Patrick Dubroy | 7247f63 | 2010-08-04 16:02:59 -0700 | [diff] [blame] | 902 | final CellLayout cl = (CellLayout)getChildAt(i); |
Michael Jurka | 5f1c509 | 2010-09-03 14:15:02 -0700 | [diff] [blame] | 903 | float finalAlphaValue = (i == mCurrentPage) ? 1.0f : 0.0f; |
Adam Cohen | f34bab5 | 2010-09-30 14:11:56 -0700 | [diff] [blame] | 904 | float rotation = 0.0f; |
| 905 | |
| 906 | if (i < mCurrentPage) { |
| 907 | rotation = WORKSPACE_ROTATION; |
| 908 | } else if (i > mCurrentPage) { |
| 909 | rotation = -WORKSPACE_ROTATION; |
| 910 | } |
| 911 | |
Michael Jurka | 4cb3724 | 2010-08-09 21:05:32 -0700 | [diff] [blame] | 912 | if (animated) { |
Chet Haase | 472b281 | 2010-10-14 07:02:04 -0700 | [diff] [blame] | 913 | |
Michael Jurka | 4cb3724 | 2010-08-09 21:05:32 -0700 | [diff] [blame] | 914 | s.playTogether( |
Chet Haase | 472b281 | 2010-10-14 07:02:04 -0700 | [diff] [blame] | 915 | ObjectAnimator.ofFloat(cl, "translationX", 0.0f).setDuration(duration), |
| 916 | ObjectAnimator.ofFloat(cl, "translationY", 0.0f).setDuration(duration), |
| 917 | ObjectAnimator.ofFloat(cl, "scaleX", 1.0f).setDuration(duration), |
| 918 | ObjectAnimator.ofFloat(cl, "scaleY", 1.0f).setDuration(duration), |
| 919 | ObjectAnimator.ofFloat(cl, "backgroundAlpha", 0.0f).setDuration(duration), |
| 920 | ObjectAnimator.ofFloat(cl, "alpha", finalAlphaValue).setDuration(duration), |
| 921 | ObjectAnimator.ofFloat(cl, "rotationY", rotation).setDuration(duration)); |
Michael Jurka | 4cb3724 | 2010-08-09 21:05:32 -0700 | [diff] [blame] | 922 | } else { |
| 923 | cl.setTranslationX(0.0f); |
| 924 | cl.setTranslationY(0.0f); |
| 925 | cl.setScaleX(1.0f); |
| 926 | cl.setScaleY(1.0f); |
Michael Jurka | 5f1c509 | 2010-09-03 14:15:02 -0700 | [diff] [blame] | 927 | cl.setBackgroundAlpha(0.0f); |
Adam Cohen | f34bab5 | 2010-09-30 14:11:56 -0700 | [diff] [blame] | 928 | cl.setAlpha(finalAlphaValue); |
| 929 | cl.setRotationY(rotation); |
Michael Jurka | 4cb3724 | 2010-08-09 21:05:32 -0700 | [diff] [blame] | 930 | } |
Michael Jurka | b0f28bd | 2010-07-30 11:58:59 -0700 | [diff] [blame] | 931 | } |
Michael Jurka | c86756c | 2010-10-10 15:15:47 -0700 | [diff] [blame] | 932 | if (animated) { |
| 933 | // If we call this when we're not animated, onAnimationEnd is never called on |
| 934 | // the listener; make sure we only use the listener when we're actually animating |
| 935 | s.addListener(mUnshrinkAnimationListener); |
| 936 | s.start(); |
| 937 | } |
Michael Jurka | dee0589 | 2010-07-27 10:01:56 -0700 | [diff] [blame] | 938 | } |
Michael Jurka | dee0589 | 2010-07-27 10:01:56 -0700 | [diff] [blame] | 939 | } |
| 940 | |
Joe Onorato | 4be866d | 2010-10-10 11:26:02 -0700 | [diff] [blame] | 941 | /** |
| 942 | * Draw the View v into the given Canvas. |
| 943 | * |
| 944 | * @param v the view to draw |
| 945 | * @param destCanvas the canvas to draw on |
| 946 | * @param padding the horizontal and vertical padding to use when drawing |
| 947 | */ |
| 948 | private void drawDragView(View v, Canvas destCanvas, int padding) { |
| 949 | final Rect clipRect = mTempRect; |
| 950 | v.getDrawingRect(clipRect); |
| 951 | |
| 952 | // For a TextView, adjust the clip rect so that we don't include the text label |
| 953 | if (v instanceof TextView) { |
| 954 | final int iconHeight = ((TextView)v).getCompoundPaddingTop() - v.getPaddingTop(); |
| 955 | clipRect.bottom = clipRect.top + iconHeight; |
| 956 | } |
| 957 | |
| 958 | // Draw the View into the bitmap. |
| 959 | // The translate of scrollX and scrollY is necessary when drawing TextViews, because |
| 960 | // they set scrollX and scrollY to large values to achieve centered text |
| 961 | |
| 962 | destCanvas.save(); |
| 963 | destCanvas.translate(-v.getScrollX() + padding / 2, -v.getScrollY() + padding / 2); |
| 964 | destCanvas.clipRect(clipRect, Op.REPLACE); |
| 965 | v.draw(destCanvas); |
| 966 | destCanvas.restore(); |
| 967 | } |
| 968 | |
| 969 | /** |
| 970 | * Returns a new bitmap to be used as the object outline, e.g. to visualize the drop location. |
| 971 | * Responsibility for the bitmap is transferred to the caller. |
| 972 | */ |
| 973 | private Bitmap createDragOutline(View v, Canvas canvas, int padding) { |
| 974 | final int outlineColor = getResources().getColor(R.color.drag_outline_color); |
| 975 | final Bitmap b = Bitmap.createBitmap( |
| 976 | v.getWidth() + padding, v.getHeight() + padding, Bitmap.Config.ARGB_8888); |
| 977 | |
| 978 | canvas.setBitmap(b); |
| 979 | drawDragView(v, canvas, padding); |
| 980 | mOutlineHelper.applyExpensiveOuterOutline(b, canvas, outlineColor, true); |
| 981 | |
| 982 | return b; |
| 983 | } |
| 984 | |
| 985 | /** |
| 986 | * Returns a new bitmap to show when the given View is being dragged around. |
| 987 | * Responsibility for the bitmap is transferred to the caller. |
| 988 | */ |
| 989 | private Bitmap createDragBitmap(View v, Canvas canvas, int padding) { |
| 990 | final int outlineColor = getResources().getColor(R.color.drag_outline_color); |
| 991 | final Bitmap b = Bitmap.createBitmap( |
| 992 | mDragOutline.getWidth(), mDragOutline.getHeight(), Bitmap.Config.ARGB_8888); |
| 993 | |
| 994 | canvas.setBitmap(b); |
| 995 | canvas.drawBitmap(mDragOutline, 0, 0, null); |
| 996 | drawDragView(v, canvas, padding); |
Patrick Dubroy | 8e58e91 | 2010-10-14 13:21:48 -0700 | [diff] [blame] | 997 | mOutlineHelper.applyOuterBlur(b, canvas, outlineColor); |
Joe Onorato | 4be866d | 2010-10-10 11:26:02 -0700 | [diff] [blame] | 998 | |
| 999 | return b; |
| 1000 | } |
| 1001 | |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 1002 | void startDrag(CellLayout.CellInfo cellInfo) { |
| 1003 | View child = cellInfo.cell; |
Winson Chung | aafa03c | 2010-06-11 17:34:16 -0700 | [diff] [blame] | 1004 | |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 1005 | // Make sure the drag was started by a long press as opposed to a long click. |
Bjorn Bringert | 7984c94 | 2009-12-09 15:38:25 +0000 | [diff] [blame] | 1006 | if (!child.isInTouchMode()) { |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 1007 | return; |
| 1008 | } |
Winson Chung | aafa03c | 2010-06-11 17:34:16 -0700 | [diff] [blame] | 1009 | |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 1010 | mDragInfo = cellInfo; |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 1011 | mDragInfo.screen = mCurrentPage; |
Winson Chung | aafa03c | 2010-06-11 17:34:16 -0700 | [diff] [blame] | 1012 | |
Patrick Dubroy | 08ae2ec | 2010-10-14 23:54:22 -0700 | [diff] [blame] | 1013 | CellLayout current = getCurrentDropLayout(); |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 1014 | |
| 1015 | current.onDragChild(child); |
Joe Onorato | 4be866d | 2010-10-10 11:26:02 -0700 | [diff] [blame] | 1016 | |
| 1017 | child.clearFocus(); |
| 1018 | child.setPressed(false); |
| 1019 | |
| 1020 | final Canvas canvas = new Canvas(); |
| 1021 | |
Patrick Dubroy | 8e58e91 | 2010-10-14 13:21:48 -0700 | [diff] [blame] | 1022 | // We need to add extra padding to the bitmap to make room for the glow effect |
| 1023 | final int bitmapPadding = HolographicOutlineHelper.OUTER_BLUR_RADIUS; |
| 1024 | |
Joe Onorato | 4be866d | 2010-10-10 11:26:02 -0700 | [diff] [blame] | 1025 | // The outline is used to visualize where the item will land if dropped |
Patrick Dubroy | 8e58e91 | 2010-10-14 13:21:48 -0700 | [diff] [blame] | 1026 | mDragOutline = createDragOutline(child, canvas, bitmapPadding); |
Joe Onorato | 4be866d | 2010-10-10 11:26:02 -0700 | [diff] [blame] | 1027 | |
| 1028 | // The drag bitmap follows the touch point around on the screen |
Patrick Dubroy | 8e58e91 | 2010-10-14 13:21:48 -0700 | [diff] [blame] | 1029 | final Bitmap b = createDragBitmap(child, canvas, bitmapPadding); |
Joe Onorato | 4be866d | 2010-10-10 11:26:02 -0700 | [diff] [blame] | 1030 | |
| 1031 | final int bmpWidth = b.getWidth(); |
| 1032 | final int bmpHeight = b.getHeight(); |
| 1033 | child.getLocationOnScreen(mTempXY); |
| 1034 | final int screenX = (int) mTempXY[0] + (child.getWidth() - bmpWidth) / 2; |
| 1035 | final int screenY = (int) mTempXY[1] + (child.getHeight() - bmpHeight) / 2; |
| 1036 | mDragController.startDrag(b, screenX, screenY, 0, 0, bmpWidth, bmpHeight, this, |
| 1037 | child.getTag(), DragController.DRAG_ACTION_MOVE, null); |
| 1038 | b.recycle(); |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 1039 | } |
| 1040 | |
Michael Jurka | 0280c3b | 2010-09-17 15:00:07 -0700 | [diff] [blame] | 1041 | void addApplicationShortcut(ShortcutInfo info, int screen, int cellX, int cellY, |
| 1042 | boolean insertAtFirst, int intersectX, int intersectY) { |
| 1043 | final CellLayout cellLayout = (CellLayout) getChildAt(screen); |
| 1044 | View view = mLauncher.createShortcut(R.layout.application, cellLayout, (ShortcutInfo) info); |
| 1045 | |
| 1046 | final int[] cellXY = new int[2]; |
| 1047 | cellLayout.findCellForSpanThatIntersects(cellXY, 1, 1, intersectX, intersectY); |
| 1048 | addInScreen(view, screen, cellXY[0], cellXY[1], 1, 1, insertAtFirst); |
| 1049 | LauncherModel.addOrMoveItemInDatabase(mLauncher, info, |
| 1050 | LauncherSettings.Favorites.CONTAINER_DESKTOP, screen, |
| 1051 | cellXY[0], cellXY[1]); |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 1052 | } |
| 1053 | |
Patrick Dubroy | ce34a97 | 2010-10-19 10:34:32 -0700 | [diff] [blame] | 1054 | private void setPositionForDropAnimation( |
| 1055 | View dragView, int dragViewX, int dragViewY, View parent, View child) { |
| 1056 | final CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams(); |
| 1057 | |
| 1058 | // Based on the position of the drag view, find the top left of the original view |
| 1059 | int viewX = dragViewX + (dragView.getWidth() - child.getWidth()) / 2; |
| 1060 | int viewY = dragViewY + (dragView.getHeight() - child.getHeight()) / 2; |
| 1061 | viewX -= getResources().getInteger(R.integer.config_dragViewOffsetX); |
| 1062 | viewY -= getResources().getInteger(R.integer.config_dragViewOffsetY); |
| 1063 | |
| 1064 | // Set its old pos (in the new parent's coordinates); the CellLayout will |
| 1065 | // animate it from this position during the next layout pass |
| 1066 | lp.oldX = viewX - (parent.getLeft() - mScrollX); |
| 1067 | lp.oldY = viewY - (parent.getTop() - mScrollY); |
| 1068 | } |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 1069 | |
Joe Onorato | 00acb12 | 2009-08-04 16:04:30 -0400 | [diff] [blame] | 1070 | public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset, |
| 1071 | DragView dragView, Object dragInfo) { |
Patrick Dubroy | ce34a97 | 2010-10-19 10:34:32 -0700 | [diff] [blame] | 1072 | |
Michael Jurka | a63c452 | 2010-08-19 13:52:27 -0700 | [diff] [blame] | 1073 | int originX = x - xOffset; |
| 1074 | int originY = y - yOffset; |
Patrick Dubroy | ce34a97 | 2010-10-19 10:34:32 -0700 | [diff] [blame] | 1075 | |
| 1076 | if (mDragTargetLayout == null) { |
| 1077 | // Cancel the drag if we're not over a screen at time of drop |
| 1078 | if (mDragInfo != null) { |
| 1079 | // Set its position so the parent can animate it back |
| 1080 | final View parent = getChildAt(mDragInfo.screen); |
| 1081 | setPositionForDropAnimation(dragView, originX, originY, parent, mDragInfo.cell); |
| 1082 | } |
| 1083 | return; |
| 1084 | } |
| 1085 | |
Michael Jurka | c0e8fca | 2010-10-06 16:41:29 -0700 | [diff] [blame] | 1086 | if (mIsSmall || mIsInUnshrinkAnimation) { |
Michael Jurka | 0280c3b | 2010-09-17 15:00:07 -0700 | [diff] [blame] | 1087 | // get originX and originY in the local coordinate system of the screen |
| 1088 | mTempOriginXY[0] = originX; |
| 1089 | mTempOriginXY[1] = originY; |
Michael Jurka | d718d6a | 2010-10-14 15:35:17 -0700 | [diff] [blame] | 1090 | mapPointFromSelfToChild(mDragTargetLayout, mTempOriginXY); |
Michael Jurka | 0280c3b | 2010-09-17 15:00:07 -0700 | [diff] [blame] | 1091 | originX = (int)mTempOriginXY[0]; |
| 1092 | originY = (int)mTempOriginXY[1]; |
Michael Jurka | a63c452 | 2010-08-19 13:52:27 -0700 | [diff] [blame] | 1093 | } |
Michael Jurka | c6ee42e | 2010-09-30 12:04:50 -0700 | [diff] [blame] | 1094 | |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 1095 | if (source != this) { |
Michael Jurka | d718d6a | 2010-10-14 15:35:17 -0700 | [diff] [blame] | 1096 | onDropExternal(originX, originY, dragInfo, mDragTargetLayout); |
Patrick Dubroy | ce34a97 | 2010-10-19 10:34:32 -0700 | [diff] [blame] | 1097 | } else if (mDragInfo != null) { |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 1098 | // Move internally |
Patrick Dubroy | ce34a97 | 2010-10-19 10:34:32 -0700 | [diff] [blame] | 1099 | final View cell = mDragInfo.cell; |
| 1100 | mTargetCell = findNearestVacantArea(originX, originY, |
| 1101 | mDragInfo.spanX, mDragInfo.spanY, cell, mDragTargetLayout, |
| 1102 | mTargetCell); |
Michael Jurka | a63c452 | 2010-08-19 13:52:27 -0700 | [diff] [blame] | 1103 | |
Patrick Dubroy | ce34a97 | 2010-10-19 10:34:32 -0700 | [diff] [blame] | 1104 | int screen = indexOfChild(mDragTargetLayout); |
| 1105 | if (screen != mDragInfo.screen) { |
| 1106 | final CellLayout originalCellLayout = (CellLayout) getChildAt(mDragInfo.screen); |
| 1107 | originalCellLayout.removeView(cell); |
| 1108 | addInScreen(cell, screen, mTargetCell[0], mTargetCell[1], |
| 1109 | mDragInfo.spanX, mDragInfo.spanY); |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 1110 | } |
Patrick Dubroy | ce34a97 | 2010-10-19 10:34:32 -0700 | [diff] [blame] | 1111 | mDragTargetLayout.onDropChild(cell); |
| 1112 | |
| 1113 | // update the item's position after drop |
| 1114 | final ItemInfo info = (ItemInfo) cell.getTag(); |
| 1115 | CellLayout.LayoutParams lp = (CellLayout.LayoutParams) cell.getLayoutParams(); |
| 1116 | mDragTargetLayout.onMove(cell, mTargetCell[0], mTargetCell[1]); |
| 1117 | lp.cellX = mTargetCell[0]; |
| 1118 | lp.cellY = mTargetCell[1]; |
| 1119 | cell.setId(LauncherModel.getCellLayoutChildId(-1, mDragInfo.screen, |
| 1120 | mTargetCell[0], mTargetCell[1], mDragInfo.spanX, mDragInfo.spanY)); |
| 1121 | |
| 1122 | LauncherModel.moveItemInDatabase(mLauncher, info, |
| 1123 | LauncherSettings.Favorites.CONTAINER_DESKTOP, screen, |
| 1124 | lp.cellX, lp.cellY); |
| 1125 | |
| 1126 | // Prepare it to be animated into its new position |
| 1127 | // This must be called after the view has been re-parented |
| 1128 | setPositionForDropAnimation(dragView, originX, originY, mDragTargetLayout, cell); |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 1129 | } |
| 1130 | } |
| 1131 | |
Winson Chung | aafa03c | 2010-06-11 17:34:16 -0700 | [diff] [blame] | 1132 | public void onDragEnter(DragSource source, int x, int y, int xOffset, |
| 1133 | int yOffset, DragView dragView, Object dragInfo) { |
Patrick Dubroy | 08ae2ec | 2010-10-14 23:54:22 -0700 | [diff] [blame] | 1134 | mDragTargetLayout = null; // Reset the drag state |
| 1135 | |
Michael Jurka | d718d6a | 2010-10-14 15:35:17 -0700 | [diff] [blame] | 1136 | if (!mIsSmall) { |
Patrick Dubroy | 08ae2ec | 2010-10-14 23:54:22 -0700 | [diff] [blame] | 1137 | mDragTargetLayout = getCurrentDropLayout(); |
| 1138 | mDragTargetLayout.onDragEnter(dragView); |
Michael Jurka | d718d6a | 2010-10-14 15:35:17 -0700 | [diff] [blame] | 1139 | showOutlines(); |
| 1140 | } |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 1141 | } |
| 1142 | |
Michael Jurka | 1801479 | 2010-10-14 09:01:34 -0700 | [diff] [blame] | 1143 | public DropTarget getDropTargetDelegate(DragSource source, int x, int y, |
| 1144 | int xOffset, int yOffset, DragView dragView, Object dragInfo) { |
Patrick Dubroy | 440c360 | 2010-07-13 17:50:32 -0700 | [diff] [blame] | 1145 | |
Michael Jurka | c0e8fca | 2010-10-06 16:41:29 -0700 | [diff] [blame] | 1146 | if (mIsSmall || mIsInUnshrinkAnimation) { |
Michael Jurka | d718d6a | 2010-10-14 15:35:17 -0700 | [diff] [blame] | 1147 | // If we're shrunken, don't let anyone drag on folders/etc that are on the mini-screens |
Michael Jurka | 0280c3b | 2010-09-17 15:00:07 -0700 | [diff] [blame] | 1148 | return null; |
| 1149 | } |
Patrick Dubroy | 440c360 | 2010-07-13 17:50:32 -0700 | [diff] [blame] | 1150 | // We may need to delegate the drag to a child view. If a 1x1 item |
| 1151 | // would land in a cell occupied by a DragTarget (e.g. a Folder), |
| 1152 | // then drag events should be handled by that child. |
| 1153 | |
| 1154 | ItemInfo item = (ItemInfo)dragInfo; |
| 1155 | CellLayout currentLayout = getCurrentDropLayout(); |
| 1156 | |
| 1157 | int dragPointX, dragPointY; |
| 1158 | if (item.spanX == 1 && item.spanY == 1) { |
| 1159 | // For a 1x1, calculate the drop cell exactly as in onDragOver |
| 1160 | dragPointX = x - xOffset; |
| 1161 | dragPointY = y - yOffset; |
| 1162 | } else { |
| 1163 | // Otherwise, use the exact drag coordinates |
| 1164 | dragPointX = x; |
| 1165 | dragPointY = y; |
| 1166 | } |
Michael Jurka | 0280c3b | 2010-09-17 15:00:07 -0700 | [diff] [blame] | 1167 | dragPointX += mScrollX - currentLayout.getLeft(); |
| 1168 | dragPointY += mScrollY - currentLayout.getTop(); |
Patrick Dubroy | 440c360 | 2010-07-13 17:50:32 -0700 | [diff] [blame] | 1169 | |
| 1170 | // If we are dragging over a cell that contains a DropTarget that will |
| 1171 | // accept the drop, delegate to that DropTarget. |
| 1172 | final int[] cellXY = mTempCell; |
| 1173 | currentLayout.estimateDropCell(dragPointX, dragPointY, item.spanX, item.spanY, cellXY); |
| 1174 | View child = currentLayout.getChildAt(cellXY[0], cellXY[1]); |
| 1175 | if (child instanceof DropTarget) { |
| 1176 | DropTarget target = (DropTarget)child; |
| 1177 | if (target.acceptDrop(source, x, y, xOffset, yOffset, dragView, dragInfo)) { |
| 1178 | return target; |
| 1179 | } |
| 1180 | } |
| 1181 | return null; |
| 1182 | } |
| 1183 | |
Michael Jurka | 4516c11 | 2010-10-07 15:13:47 -0700 | [diff] [blame] | 1184 | /* |
| 1185 | * |
| 1186 | * Convert the 2D coordinate xy from the parent View's coordinate space to this CellLayout's |
| 1187 | * coordinate space. The argument xy is modified with the return result. |
| 1188 | * |
| 1189 | */ |
| 1190 | void mapPointFromSelfToChild(View v, float[] xy) { |
| 1191 | mapPointFromSelfToChild(v, xy, null); |
| 1192 | } |
| 1193 | |
| 1194 | /* |
| 1195 | * |
| 1196 | * Convert the 2D coordinate xy from the parent View's coordinate space to this CellLayout's |
| 1197 | * coordinate space. The argument xy is modified with the return result. |
| 1198 | * |
| 1199 | * if cachedInverseMatrix is not null, this method will just use that matrix instead of |
Michael Jurka | d718d6a | 2010-10-14 15:35:17 -0700 | [diff] [blame] | 1200 | * computing it itself; we use this to avoid redundant matrix inversions in |
Michael Jurka | 4516c11 | 2010-10-07 15:13:47 -0700 | [diff] [blame] | 1201 | * findMatchingPageForDragOver |
| 1202 | * |
| 1203 | */ |
| 1204 | void mapPointFromSelfToChild(View v, float[] xy, Matrix cachedInverseMatrix) { |
| 1205 | if (cachedInverseMatrix == null) { |
| 1206 | v.getMatrix().invert(mTempInverseMatrix); |
| 1207 | cachedInverseMatrix = mTempInverseMatrix; |
| 1208 | } |
| 1209 | xy[0] = xy[0] + mScrollX - v.getLeft(); |
| 1210 | xy[1] = xy[1] + mScrollY - v.getTop(); |
| 1211 | cachedInverseMatrix.mapPoints(xy); |
| 1212 | } |
| 1213 | |
| 1214 | /* |
| 1215 | * |
| 1216 | * Convert the 2D coordinate xy from this CellLayout's coordinate space to |
| 1217 | * the parent View's coordinate space. The argument xy is modified with the return result. |
| 1218 | * |
| 1219 | */ |
| 1220 | void mapPointFromChildToSelf(View v, float[] xy) { |
| 1221 | v.getMatrix().mapPoints(xy); |
| 1222 | xy[0] -= (mScrollX - v.getLeft()); |
| 1223 | xy[1] -= (mScrollY - v.getTop()); |
| 1224 | } |
| 1225 | |
| 1226 | static private float squaredDistance(float[] point1, float[] point2) { |
| 1227 | float distanceX = point1[0] - point2[0]; |
| 1228 | float distanceY = point2[1] - point2[1]; |
| 1229 | return distanceX * distanceX + distanceY * distanceY; |
Michael Jurka | 0280c3b | 2010-09-17 15:00:07 -0700 | [diff] [blame] | 1230 | } |
| 1231 | |
Michael Jurka | 4516c11 | 2010-10-07 15:13:47 -0700 | [diff] [blame] | 1232 | /* |
| 1233 | * |
| 1234 | * Returns true if the passed CellLayout cl overlaps with dragView |
| 1235 | * |
| 1236 | */ |
| 1237 | boolean overlaps(CellLayout cl, DragView dragView, |
| 1238 | int dragViewX, int dragViewY, Matrix cachedInverseMatrix) { |
| 1239 | // Transform the coordinates of the item being dragged to the CellLayout's coordinates |
| 1240 | final float[] draggedItemTopLeft = mTempDragCoordinates; |
| 1241 | draggedItemTopLeft[0] = dragViewX + dragView.getScaledDragRegionXOffset(); |
| 1242 | draggedItemTopLeft[1] = dragViewY + dragView.getScaledDragRegionYOffset(); |
| 1243 | final float[] draggedItemBottomRight = mTempDragBottomRightCoordinates; |
| 1244 | draggedItemBottomRight[0] = draggedItemTopLeft[0] + dragView.getScaledDragRegionWidth(); |
| 1245 | draggedItemBottomRight[1] = draggedItemTopLeft[1] + dragView.getScaledDragRegionHeight(); |
Michael Jurka | a63c452 | 2010-08-19 13:52:27 -0700 | [diff] [blame] | 1246 | |
Michael Jurka | 4516c11 | 2010-10-07 15:13:47 -0700 | [diff] [blame] | 1247 | // Transform the dragged item's top left coordinates |
| 1248 | // to the CellLayout's local coordinates |
| 1249 | mapPointFromSelfToChild(cl, draggedItemTopLeft, cachedInverseMatrix); |
| 1250 | float overlapRegionLeft = Math.max(0f, draggedItemTopLeft[0]); |
| 1251 | float overlapRegionTop = Math.max(0f, draggedItemTopLeft[1]); |
| 1252 | |
| 1253 | if (overlapRegionLeft <= cl.getWidth() && overlapRegionTop >= 0) { |
| 1254 | // Transform the dragged item's bottom right coordinates |
| 1255 | // to the CellLayout's local coordinates |
| 1256 | mapPointFromSelfToChild(cl, draggedItemBottomRight, cachedInverseMatrix); |
| 1257 | float overlapRegionRight = Math.min(cl.getWidth(), draggedItemBottomRight[0]); |
| 1258 | float overlapRegionBottom = Math.min(cl.getHeight(), draggedItemBottomRight[1]); |
| 1259 | |
| 1260 | if (overlapRegionRight >= 0 && overlapRegionBottom <= cl.getHeight()) { |
| 1261 | float overlap = (overlapRegionRight - overlapRegionLeft) * |
| 1262 | (overlapRegionBottom - overlapRegionTop); |
| 1263 | if (overlap > 0) { |
| 1264 | return true; |
| 1265 | } |
| 1266 | } |
| 1267 | } |
| 1268 | return false; |
| 1269 | } |
| 1270 | |
| 1271 | /* |
| 1272 | * |
| 1273 | * This method returns the CellLayout that is currently being dragged to. In order to drag |
| 1274 | * to a CellLayout, either the touch point must be directly over the CellLayout, or as a second |
| 1275 | * strategy, we see if the dragView is overlapping any CellLayout and choose the closest one |
| 1276 | * |
| 1277 | * Return null if no CellLayout is currently being dragged over |
| 1278 | * |
| 1279 | */ |
| 1280 | private CellLayout findMatchingPageForDragOver( |
| 1281 | DragView dragView, int originX, int originY, int offsetX, int offsetY) { |
| 1282 | // We loop through all the screens (ie CellLayouts) and see which ones overlap |
| 1283 | // with the item being dragged and then choose the one that's closest to the touch point |
Michael Jurka | a63c452 | 2010-08-19 13:52:27 -0700 | [diff] [blame] | 1284 | final int screenCount = getChildCount(); |
| 1285 | CellLayout bestMatchingScreen = null; |
Michael Jurka | 0280c3b | 2010-09-17 15:00:07 -0700 | [diff] [blame] | 1286 | float smallestDistSoFar = Float.MAX_VALUE; |
Michael Jurka | 4516c11 | 2010-10-07 15:13:47 -0700 | [diff] [blame] | 1287 | |
Michael Jurka | a63c452 | 2010-08-19 13:52:27 -0700 | [diff] [blame] | 1288 | for (int i = 0; i < screenCount; i++) { |
| 1289 | CellLayout cl = (CellLayout)getChildAt(i); |
Michael Jurka | a63c452 | 2010-08-19 13:52:27 -0700 | [diff] [blame] | 1290 | |
Michael Jurka | 4516c11 | 2010-10-07 15:13:47 -0700 | [diff] [blame] | 1291 | final float[] touchXy = mTempTouchCoordinates; |
| 1292 | touchXy[0] = originX + offsetX; |
| 1293 | touchXy[1] = originY + offsetY; |
Michael Jurka | a63c452 | 2010-08-19 13:52:27 -0700 | [diff] [blame] | 1294 | |
Michael Jurka | 4516c11 | 2010-10-07 15:13:47 -0700 | [diff] [blame] | 1295 | // Transform the touch coordinates to the CellLayout's local coordinates |
| 1296 | // If the touch point is within the bounds of the cell layout, we can return immediately |
Michael Jurka | 0280c3b | 2010-09-17 15:00:07 -0700 | [diff] [blame] | 1297 | cl.getMatrix().invert(mTempInverseMatrix); |
Michael Jurka | 4516c11 | 2010-10-07 15:13:47 -0700 | [diff] [blame] | 1298 | mapPointFromSelfToChild(cl, touchXy, mTempInverseMatrix); |
Michael Jurka | a63c452 | 2010-08-19 13:52:27 -0700 | [diff] [blame] | 1299 | |
Michael Jurka | 4516c11 | 2010-10-07 15:13:47 -0700 | [diff] [blame] | 1300 | if (touchXy[0] >= 0 && touchXy[0] <= cl.getWidth() && |
| 1301 | touchXy[1] >= 0 && touchXy[1] <= cl.getHeight()) { |
| 1302 | return cl; |
| 1303 | } |
Michael Jurka | a63c452 | 2010-08-19 13:52:27 -0700 | [diff] [blame] | 1304 | |
Michael Jurka | 4516c11 | 2010-10-07 15:13:47 -0700 | [diff] [blame] | 1305 | if (overlaps(cl, dragView, originX, originY, mTempInverseMatrix)) { |
| 1306 | // Get the center of the cell layout in screen coordinates |
| 1307 | final float[] cellLayoutCenter = mTempCellLayoutCenterCoordinates; |
| 1308 | cellLayoutCenter[0] = cl.getWidth()/2; |
| 1309 | cellLayoutCenter[1] = cl.getHeight()/2; |
| 1310 | mapPointFromChildToSelf(cl, cellLayoutCenter); |
Michael Jurka | 0280c3b | 2010-09-17 15:00:07 -0700 | [diff] [blame] | 1311 | |
Michael Jurka | 4516c11 | 2010-10-07 15:13:47 -0700 | [diff] [blame] | 1312 | touchXy[0] = originX + offsetX; |
| 1313 | touchXy[1] = originY + offsetY; |
Michael Jurka | 0280c3b | 2010-09-17 15:00:07 -0700 | [diff] [blame] | 1314 | |
Michael Jurka | 4516c11 | 2010-10-07 15:13:47 -0700 | [diff] [blame] | 1315 | // Calculate the distance between the center of the CellLayout |
| 1316 | // and the touch point |
| 1317 | float dist = squaredDistance(touchXy, cellLayoutCenter); |
| 1318 | |
| 1319 | if (dist < smallestDistSoFar) { |
Michael Jurka | 0280c3b | 2010-09-17 15:00:07 -0700 | [diff] [blame] | 1320 | smallestDistSoFar = dist; |
Michael Jurka | a63c452 | 2010-08-19 13:52:27 -0700 | [diff] [blame] | 1321 | bestMatchingScreen = cl; |
Michael Jurka | a63c452 | 2010-08-19 13:52:27 -0700 | [diff] [blame] | 1322 | } |
Michael Jurka | 4516c11 | 2010-10-07 15:13:47 -0700 | [diff] [blame] | 1323 | } |
Michael Jurka | a63c452 | 2010-08-19 13:52:27 -0700 | [diff] [blame] | 1324 | } |
Michael Jurka | a63c452 | 2010-08-19 13:52:27 -0700 | [diff] [blame] | 1325 | return bestMatchingScreen; |
| 1326 | } |
| 1327 | |
Patrick Dubroy | 6569f2c | 2010-07-12 14:25:18 -0700 | [diff] [blame] | 1328 | public void onDragOver(DragSource source, int x, int y, int xOffset, int yOffset, |
| 1329 | DragView dragView, Object dragInfo) { |
Patrick Dubroy | 1262e36 | 2010-10-06 15:49:50 -0700 | [diff] [blame] | 1330 | // When touch is inside the scroll area, skip dragOver actions for the current screen |
| 1331 | if (!mInScrollArea) { |
Michael Jurka | d718d6a | 2010-10-14 15:35:17 -0700 | [diff] [blame] | 1332 | CellLayout layout; |
| 1333 | int originX = x - xOffset; |
| 1334 | int originY = y - yOffset; |
| 1335 | if (mIsSmall || mIsInUnshrinkAnimation) { |
| 1336 | layout = findMatchingPageForDragOver( |
| 1337 | dragView, originX, originY, xOffset, yOffset); |
Patrick Dubroy | 1262e36 | 2010-10-06 15:49:50 -0700 | [diff] [blame] | 1338 | |
Michael Jurka | d718d6a | 2010-10-14 15:35:17 -0700 | [diff] [blame] | 1339 | if (layout != mDragTargetLayout) { |
| 1340 | if (mDragTargetLayout != null) { |
| 1341 | mDragTargetLayout.setHover(false); |
| 1342 | } |
| 1343 | mDragTargetLayout = layout; |
| 1344 | if (mDragTargetLayout != null) { |
| 1345 | mDragTargetLayout.setHover(true); |
| 1346 | } |
| 1347 | } |
| 1348 | } else { |
| 1349 | layout = getCurrentDropLayout(); |
| 1350 | |
| 1351 | final ItemInfo item = (ItemInfo)dragInfo; |
| 1352 | if (dragInfo instanceof LauncherAppWidgetInfo) { |
| 1353 | LauncherAppWidgetInfo widgetInfo = (LauncherAppWidgetInfo)dragInfo; |
| 1354 | |
| 1355 | if (widgetInfo.spanX == -1) { |
| 1356 | // Calculate the grid spans needed to fit this widget |
| 1357 | int[] spans = layout.rectToCell( |
| 1358 | widgetInfo.minWidth, widgetInfo.minHeight, null); |
| 1359 | item.spanX = spans[0]; |
| 1360 | item.spanY = spans[1]; |
| 1361 | } |
| 1362 | } |
| 1363 | |
| 1364 | if (source instanceof AllAppsPagedView) { |
| 1365 | // This is a hack to fix the point used to determine which cell an icon from |
| 1366 | // the all apps screen is over |
| 1367 | if (item != null && item.spanX == 1 && layout != null) { |
| 1368 | int dragRegionLeft = (dragView.getWidth() - layout.getCellWidth()) / 2; |
| 1369 | |
| 1370 | originX += dragRegionLeft - dragView.getDragRegionLeft(); |
| 1371 | if (dragView.getDragRegionWidth() != layout.getCellWidth()) { |
| 1372 | dragView.setDragRegion(dragView.getDragRegionLeft(), |
| 1373 | dragView.getDragRegionTop(), |
| 1374 | layout.getCellWidth(), |
| 1375 | dragView.getDragRegionHeight()); |
| 1376 | } |
| 1377 | } |
| 1378 | } |
| 1379 | |
| 1380 | if (layout != mDragTargetLayout) { |
| 1381 | if (mDragTargetLayout != null) { |
| 1382 | mDragTargetLayout.onDragExit(); |
| 1383 | } |
| 1384 | layout.onDragEnter(dragView); |
| 1385 | mDragTargetLayout = layout; |
| 1386 | } |
| 1387 | |
| 1388 | // only visualize the drop locations for moving icons within the home screen on |
| 1389 | // tablet on phone, we also visualize icons dragged in from All Apps |
| 1390 | if ((!LauncherApplication.isScreenXLarge() || source == this) |
| 1391 | && mDragTargetLayout != null) { |
| 1392 | final View child = (mDragInfo == null) ? null : mDragInfo.cell; |
| 1393 | int localOriginX = originX - (mDragTargetLayout.getLeft() - mScrollX); |
| 1394 | int localOriginY = originY - (mDragTargetLayout.getTop() - mScrollY); |
| 1395 | mDragTargetLayout.visualizeDropLocation(child, mDragOutline, |
| 1396 | localOriginX, localOriginY, item.spanX, item.spanY); |
| 1397 | } |
Patrick Dubroy | 1262e36 | 2010-10-06 15:49:50 -0700 | [diff] [blame] | 1398 | } |
Patrick Dubroy | 976ebec | 2010-08-04 20:03:37 -0700 | [diff] [blame] | 1399 | } |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 1400 | } |
| 1401 | |
Winson Chung | aafa03c | 2010-06-11 17:34:16 -0700 | [diff] [blame] | 1402 | public void onDragExit(DragSource source, int x, int y, int xOffset, |
| 1403 | int yOffset, DragView dragView, Object dragInfo) { |
Patrick Dubroy | 6569f2c | 2010-07-12 14:25:18 -0700 | [diff] [blame] | 1404 | if (mDragTargetLayout != null) { |
Michael Jurka | 0280c3b | 2010-09-17 15:00:07 -0700 | [diff] [blame] | 1405 | mDragTargetLayout.onDragExit(); |
Patrick Dubroy | 6569f2c | 2010-07-12 14:25:18 -0700 | [diff] [blame] | 1406 | } |
Patrick Dubroy | 1262e36 | 2010-10-06 15:49:50 -0700 | [diff] [blame] | 1407 | if (!mIsPageMoving) { |
| 1408 | hideOutlines(); |
| 1409 | } |
Patrick Dubroy | 08ae2ec | 2010-10-14 23:54:22 -0700 | [diff] [blame] | 1410 | clearAllHovers(); |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 1411 | } |
| 1412 | |
Winson Chung | aafa03c | 2010-06-11 17:34:16 -0700 | [diff] [blame] | 1413 | private void onDropExternal(int x, int y, Object dragInfo, |
| 1414 | CellLayout cellLayout) { |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 1415 | onDropExternal(x, y, dragInfo, cellLayout, false); |
| 1416 | } |
Winson Chung | aafa03c | 2010-06-11 17:34:16 -0700 | [diff] [blame] | 1417 | |
Patrick Dubroy | 2b9ff37 | 2010-09-07 17:49:27 -0700 | [diff] [blame] | 1418 | /** |
| 1419 | * Add the item specified by dragInfo to the given layout. |
| 1420 | * This is basically the equivalent of onDropExternal, except it's not initiated |
| 1421 | * by drag and drop. |
| 1422 | * @return true if successful |
| 1423 | */ |
| 1424 | public boolean addExternalItemToScreen(Object dragInfo, View layout) { |
| 1425 | CellLayout cl = (CellLayout) layout; |
| 1426 | ItemInfo info = (ItemInfo) dragInfo; |
| 1427 | |
Michael Jurka | 0280c3b | 2010-09-17 15:00:07 -0700 | [diff] [blame] | 1428 | if (cl.findCellForSpan(mTempEstimate, info.spanX, info.spanY)) { |
Patrick Dubroy | 2b9ff37 | 2010-09-07 17:49:27 -0700 | [diff] [blame] | 1429 | onDropExternal(0, 0, dragInfo, cl, false); |
| 1430 | return true; |
| 1431 | } |
Michael Jurka | 0280c3b | 2010-09-17 15:00:07 -0700 | [diff] [blame] | 1432 | mLauncher.showOutOfSpaceMessage(); |
Patrick Dubroy | 2b9ff37 | 2010-09-07 17:49:27 -0700 | [diff] [blame] | 1433 | return false; |
| 1434 | } |
| 1435 | |
Michael Jurka | 0280c3b | 2010-09-17 15:00:07 -0700 | [diff] [blame] | 1436 | // Drag from somewhere else |
Joe Onorato | 4be866d | 2010-10-10 11:26:02 -0700 | [diff] [blame] | 1437 | // NOTE: This can also be called when we are outside of a drag event, when we want |
| 1438 | // to add an item to one of the workspace screens. |
Winson Chung | aafa03c | 2010-06-11 17:34:16 -0700 | [diff] [blame] | 1439 | private void onDropExternal(int x, int y, Object dragInfo, |
| 1440 | CellLayout cellLayout, boolean insertAtFirst) { |
Michael Jurka | 0280c3b | 2010-09-17 15:00:07 -0700 | [diff] [blame] | 1441 | int screen = indexOfChild(cellLayout); |
| 1442 | if (dragInfo instanceof PendingAddItemInfo) { |
| 1443 | PendingAddItemInfo info = (PendingAddItemInfo) dragInfo; |
| 1444 | // When dragging and dropping from customization tray, we deal with creating |
| 1445 | // widgets/shortcuts/folders in a slightly different way |
| 1446 | int[] touchXY = new int[2]; |
| 1447 | touchXY[0] = x; |
| 1448 | touchXY[1] = y; |
| 1449 | switch (info.itemType) { |
| 1450 | case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET: |
| 1451 | mLauncher.addAppWidgetFromDrop(info.componentName, screen, touchXY); |
| 1452 | break; |
| 1453 | case LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER: |
| 1454 | mLauncher.addLiveFolderFromDrop(info.componentName, screen, touchXY); |
| 1455 | break; |
| 1456 | case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT: |
| 1457 | mLauncher.processShortcutFromDrop(info.componentName, screen, touchXY); |
| 1458 | break; |
| 1459 | default: |
| 1460 | throw new IllegalStateException("Unknown item type: " + info.itemType); |
| 1461 | } |
| 1462 | cellLayout.onDragExit(); |
Michael Jurka | 1801479 | 2010-10-14 09:01:34 -0700 | [diff] [blame] | 1463 | cellLayout.animateDrop(); |
Michael Jurka | 0280c3b | 2010-09-17 15:00:07 -0700 | [diff] [blame] | 1464 | return; |
| 1465 | } |
| 1466 | |
| 1467 | // This is for other drag/drop cases, like dragging from All Apps |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 1468 | ItemInfo info = (ItemInfo) dragInfo; |
| 1469 | |
Michael Jurka | af44209 | 2010-06-10 17:01:57 -0700 | [diff] [blame] | 1470 | View view = null; |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 1471 | |
| 1472 | switch (info.itemType) { |
| 1473 | case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION: |
| 1474 | case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT: |
Joe Onorato | e48e7c1 | 2010-02-19 13:10:40 -0800 | [diff] [blame] | 1475 | if (info.container == NO_ID && info instanceof ApplicationInfo) { |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 1476 | // Came from all apps -- make a copy |
Winson Chung | aafa03c | 2010-06-11 17:34:16 -0700 | [diff] [blame] | 1477 | info = new ShortcutInfo((ApplicationInfo) info); |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 1478 | } |
Winson Chung | aafa03c | 2010-06-11 17:34:16 -0700 | [diff] [blame] | 1479 | view = mLauncher.createShortcut(R.layout.application, cellLayout, |
| 1480 | (ShortcutInfo) info); |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 1481 | break; |
| 1482 | case LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER: |
| 1483 | view = FolderIcon.fromXml(R.layout.folder_icon, mLauncher, |
Michael Jurka | 0280c3b | 2010-09-17 15:00:07 -0700 | [diff] [blame] | 1484 | cellLayout, ((UserFolderInfo) info)); |
Michael Jurka | af44209 | 2010-06-10 17:01:57 -0700 | [diff] [blame] | 1485 | break; |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 1486 | default: |
Michael Jurka | 0280c3b | 2010-09-17 15:00:07 -0700 | [diff] [blame] | 1487 | throw new IllegalStateException("Unknown item type: " + info.itemType); |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 1488 | } |
| 1489 | |
Patrick Dubroy | 6569f2c | 2010-07-12 14:25:18 -0700 | [diff] [blame] | 1490 | // If the view is null, it has already been added. |
| 1491 | if (view == null) { |
Michael Jurka | 0280c3b | 2010-09-17 15:00:07 -0700 | [diff] [blame] | 1492 | cellLayout.onDragExit(); |
Patrick Dubroy | 6569f2c | 2010-07-12 14:25:18 -0700 | [diff] [blame] | 1493 | } else { |
Michael Jurka | 7ded67c | 2010-09-28 13:57:39 -0700 | [diff] [blame] | 1494 | mTargetCell = findNearestVacantArea(x, y, 1, 1, null, cellLayout, mTargetCell); |
Winson Chung | aafa03c | 2010-06-11 17:34:16 -0700 | [diff] [blame] | 1495 | addInScreen(view, indexOfChild(cellLayout), mTargetCell[0], |
| 1496 | mTargetCell[1], info.spanX, info.spanY, insertAtFirst); |
| 1497 | cellLayout.onDropChild(view); |
Michael Jurka | 1801479 | 2010-10-14 09:01:34 -0700 | [diff] [blame] | 1498 | cellLayout.animateDrop(); |
Patrick Dubroy | 6569f2c | 2010-07-12 14:25:18 -0700 | [diff] [blame] | 1499 | CellLayout.LayoutParams lp = (CellLayout.LayoutParams) view.getLayoutParams(); |
Michael Jurka | af44209 | 2010-06-10 17:01:57 -0700 | [diff] [blame] | 1500 | |
| 1501 | LauncherModel.addOrMoveItemInDatabase(mLauncher, info, |
Michael Jurka | 0280c3b | 2010-09-17 15:00:07 -0700 | [diff] [blame] | 1502 | LauncherSettings.Favorites.CONTAINER_DESKTOP, screen, |
Winson Chung | aafa03c | 2010-06-11 17:34:16 -0700 | [diff] [blame] | 1503 | lp.cellX, lp.cellY); |
Joe Onorato | 00acb12 | 2009-08-04 16:04:30 -0400 | [diff] [blame] | 1504 | } |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 1505 | } |
Winson Chung | aafa03c | 2010-06-11 17:34:16 -0700 | [diff] [blame] | 1506 | |
Jeff Sharkey | 7086428 | 2009-04-07 21:08:40 -0700 | [diff] [blame] | 1507 | /** |
| 1508 | * Return the current {@link CellLayout}, correctly picking the destination |
| 1509 | * screen while a scroll is in progress. |
| 1510 | */ |
| 1511 | private CellLayout getCurrentDropLayout() { |
Michael Jurka | d718d6a | 2010-10-14 15:35:17 -0700 | [diff] [blame] | 1512 | // if we're currently small, use findMatchingPageForDragOver instead |
| 1513 | if (mIsSmall) return null; |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 1514 | int index = mScroller.isFinished() ? mCurrentPage : mNextPage; |
Jeff Sharkey | 7086428 | 2009-04-07 21:08:40 -0700 | [diff] [blame] | 1515 | return (CellLayout) getChildAt(index); |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 1516 | } |
| 1517 | |
Jeff Sharkey | 7086428 | 2009-04-07 21:08:40 -0700 | [diff] [blame] | 1518 | /** |
Michael Jurka | 0280c3b | 2010-09-17 15:00:07 -0700 | [diff] [blame] | 1519 | * Return the current CellInfo describing our current drag; this method exists |
| 1520 | * so that Launcher can sync this object with the correct info when the activity is created/ |
| 1521 | * destroyed |
| 1522 | * |
| 1523 | */ |
| 1524 | public CellLayout.CellInfo getDragInfo() { |
| 1525 | return mDragInfo; |
| 1526 | } |
| 1527 | |
| 1528 | /** |
Jeff Sharkey | 7086428 | 2009-04-07 21:08:40 -0700 | [diff] [blame] | 1529 | * {@inheritDoc} |
| 1530 | */ |
| 1531 | public boolean acceptDrop(DragSource source, int x, int y, |
Joe Onorato | 00acb12 | 2009-08-04 16:04:30 -0400 | [diff] [blame] | 1532 | int xOffset, int yOffset, DragView dragView, Object dragInfo) { |
Michael Jurka | d718d6a | 2010-10-14 15:35:17 -0700 | [diff] [blame] | 1533 | if (mDragTargetLayout == null) { |
| 1534 | // cancel the drag if we're not over a screen at time of drop |
| 1535 | return false; |
Michael Jurka | 0280c3b | 2010-09-17 15:00:07 -0700 | [diff] [blame] | 1536 | } |
Michael Jurka | d718d6a | 2010-10-14 15:35:17 -0700 | [diff] [blame] | 1537 | |
Michael Jurka | c28de51 | 2010-08-13 11:27:44 -0700 | [diff] [blame] | 1538 | final CellLayout.CellInfo dragCellInfo = mDragInfo; |
| 1539 | final int spanX = dragCellInfo == null ? 1 : dragCellInfo.spanX; |
| 1540 | final int spanY = dragCellInfo == null ? 1 : dragCellInfo.spanY; |
Romain Guy | 4c58c48 | 2009-05-12 17:35:41 -0700 | [diff] [blame] | 1541 | |
Michael Jurka | c28de51 | 2010-08-13 11:27:44 -0700 | [diff] [blame] | 1542 | final View ignoreView = dragCellInfo == null ? null : dragCellInfo.cell; |
Romain Guy | 4c58c48 | 2009-05-12 17:35:41 -0700 | [diff] [blame] | 1543 | |
Michael Jurka | d718d6a | 2010-10-14 15:35:17 -0700 | [diff] [blame] | 1544 | if (mDragTargetLayout.findCellForSpanIgnoring(null, spanX, spanY, ignoreView)) { |
Michael Jurka | 0e26059 | 2010-06-30 17:07:39 -0700 | [diff] [blame] | 1545 | return true; |
| 1546 | } else { |
Michael Jurka | 0280c3b | 2010-09-17 15:00:07 -0700 | [diff] [blame] | 1547 | mLauncher.showOutOfSpaceMessage(); |
Michael Jurka | 0e26059 | 2010-06-30 17:07:39 -0700 | [diff] [blame] | 1548 | return false; |
| 1549 | } |
Jeff Sharkey | 7086428 | 2009-04-07 21:08:40 -0700 | [diff] [blame] | 1550 | } |
Winson Chung | aafa03c | 2010-06-11 17:34:16 -0700 | [diff] [blame] | 1551 | |
Jeff Sharkey | 7086428 | 2009-04-07 21:08:40 -0700 | [diff] [blame] | 1552 | /** |
Jeff Sharkey | 7086428 | 2009-04-07 21:08:40 -0700 | [diff] [blame] | 1553 | * Calculate the nearest cell where the given object would be dropped. |
| 1554 | */ |
Michael Jurka | 6a1435d | 2010-09-27 17:35:12 -0700 | [diff] [blame] | 1555 | private int[] findNearestVacantArea(int pixelX, int pixelY, |
Jeff Sharkey | 7086428 | 2009-04-07 21:08:40 -0700 | [diff] [blame] | 1556 | int spanX, int spanY, View ignoreView, CellLayout layout, int[] recycle) { |
Patrick Dubroy | 6569f2c | 2010-07-12 14:25:18 -0700 | [diff] [blame] | 1557 | |
Michael Jurka | 5f1c509 | 2010-09-03 14:15:02 -0700 | [diff] [blame] | 1558 | int localPixelX = pixelX - (layout.getLeft() - mScrollX); |
| 1559 | int localPixelY = pixelY - (layout.getTop() - mScrollY); |
Patrick Dubroy | 6569f2c | 2010-07-12 14:25:18 -0700 | [diff] [blame] | 1560 | |
Jeff Sharkey | 7086428 | 2009-04-07 21:08:40 -0700 | [diff] [blame] | 1561 | // Find the best target drop location |
Michael Jurka | 0280c3b | 2010-09-17 15:00:07 -0700 | [diff] [blame] | 1562 | return layout.findNearestVacantArea( |
Michael Jurka | fc9f07d | 2010-09-30 13:22:31 -0700 | [diff] [blame] | 1563 | localPixelX, localPixelY, spanX, spanY, ignoreView, recycle); |
Jeff Sharkey | 7086428 | 2009-04-07 21:08:40 -0700 | [diff] [blame] | 1564 | } |
Winson Chung | aafa03c | 2010-06-11 17:34:16 -0700 | [diff] [blame] | 1565 | |
Patrick Dubroy | 8f86ddc | 2010-07-16 13:55:32 -0700 | [diff] [blame] | 1566 | /** |
| 1567 | * Estimate the size that a child with the given dimensions will take in the current screen. |
| 1568 | */ |
| 1569 | void estimateChildSize(int minWidth, int minHeight, int[] result) { |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 1570 | ((CellLayout)getChildAt(mCurrentPage)).estimateChildSize(minWidth, minHeight, result); |
Patrick Dubroy | 8f86ddc | 2010-07-16 13:55:32 -0700 | [diff] [blame] | 1571 | } |
| 1572 | |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 1573 | void setLauncher(Launcher launcher) { |
| 1574 | mLauncher = launcher; |
| 1575 | } |
| 1576 | |
Joe Onorato | 00acb12 | 2009-08-04 16:04:30 -0400 | [diff] [blame] | 1577 | public void setDragController(DragController dragController) { |
| 1578 | mDragController = dragController; |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 1579 | } |
| 1580 | |
| 1581 | public void onDropCompleted(View target, boolean success) { |
Winson Chung | aafa03c | 2010-06-11 17:34:16 -0700 | [diff] [blame] | 1582 | if (success) { |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 1583 | if (target != this && mDragInfo != null) { |
| 1584 | final CellLayout cellLayout = (CellLayout) getChildAt(mDragInfo.screen); |
| 1585 | cellLayout.removeView(mDragInfo.cell); |
Joe Onorato | 00acb12 | 2009-08-04 16:04:30 -0400 | [diff] [blame] | 1586 | if (mDragInfo.cell instanceof DropTarget) { |
| 1587 | mDragController.removeDropTarget((DropTarget)mDragInfo.cell); |
| 1588 | } |
Winson Chung | aafa03c | 2010-06-11 17:34:16 -0700 | [diff] [blame] | 1589 | // final Object tag = mDragInfo.cell.getTag(); |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 1590 | } |
Patrick Dubroy | ce34a97 | 2010-10-19 10:34:32 -0700 | [diff] [blame] | 1591 | } else if (mDragInfo != null) { |
| 1592 | ((CellLayout) getChildAt(mDragInfo.screen)).onDropAborted(mDragInfo.cell); |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 1593 | } |
| 1594 | |
Joe Onorato | 4be866d | 2010-10-10 11:26:02 -0700 | [diff] [blame] | 1595 | mDragOutline = null; |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 1596 | mDragInfo = null; |
| 1597 | } |
| 1598 | |
Michael Jurka | 0280c3b | 2010-09-17 15:00:07 -0700 | [diff] [blame] | 1599 | public boolean isDropEnabled() { |
| 1600 | return true; |
| 1601 | } |
| 1602 | |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 1603 | @Override |
| 1604 | protected void onRestoreInstanceState(Parcelable state) { |
| 1605 | super.onRestoreInstanceState(state); |
| 1606 | Launcher.setScreen(mCurrentPage); |
| 1607 | } |
| 1608 | |
| 1609 | @Override |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 1610 | public void scrollLeft() { |
Michael Jurka | c0e8fca | 2010-10-06 16:41:29 -0700 | [diff] [blame] | 1611 | if (!mIsSmall && !mIsInUnshrinkAnimation) { |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 1612 | super.scrollLeft(); |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 1613 | } |
| 1614 | } |
| 1615 | |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 1616 | @Override |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 1617 | public void scrollRight() { |
Michael Jurka | c0e8fca | 2010-10-06 16:41:29 -0700 | [diff] [blame] | 1618 | if (!mIsSmall && !mIsInUnshrinkAnimation) { |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 1619 | super.scrollRight(); |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 1620 | } |
| 1621 | } |
| 1622 | |
Patrick Dubroy | 1262e36 | 2010-10-06 15:49:50 -0700 | [diff] [blame] | 1623 | @Override |
| 1624 | public void onEnterScrollArea(int direction) { |
Michael Jurka | d718d6a | 2010-10-14 15:35:17 -0700 | [diff] [blame] | 1625 | if (!mIsSmall && !mIsInUnshrinkAnimation) { |
| 1626 | mInScrollArea = true; |
| 1627 | final int screen = getCurrentPage() + ((direction == DragController.SCROLL_LEFT) ? -1 : 1); |
| 1628 | if (0 <= screen && screen < getChildCount()) { |
| 1629 | ((CellLayout) getChildAt(screen)).setHover(true); |
| 1630 | } |
Patrick Dubroy | 1262e36 | 2010-10-06 15:49:50 -0700 | [diff] [blame] | 1631 | |
Michael Jurka | d718d6a | 2010-10-14 15:35:17 -0700 | [diff] [blame] | 1632 | if (mDragTargetLayout != null) { |
| 1633 | mDragTargetLayout.onDragExit(); |
| 1634 | mDragTargetLayout = null; |
| 1635 | } |
Patrick Dubroy | 1262e36 | 2010-10-06 15:49:50 -0700 | [diff] [blame] | 1636 | } |
| 1637 | } |
| 1638 | |
Patrick Dubroy | 08ae2ec | 2010-10-14 23:54:22 -0700 | [diff] [blame] | 1639 | private void clearAllHovers() { |
| 1640 | final int childCount = getChildCount(); |
| 1641 | for (int i = 0; i < childCount; i++) { |
| 1642 | ((CellLayout) getChildAt(i)).setHover(false); |
| 1643 | } |
| 1644 | } |
| 1645 | |
Patrick Dubroy | 1262e36 | 2010-10-06 15:49:50 -0700 | [diff] [blame] | 1646 | @Override |
| 1647 | public void onExitScrollArea() { |
Michael Jurka | d718d6a | 2010-10-14 15:35:17 -0700 | [diff] [blame] | 1648 | if (mInScrollArea) { |
| 1649 | mInScrollArea = false; |
Patrick Dubroy | 08ae2ec | 2010-10-14 23:54:22 -0700 | [diff] [blame] | 1650 | clearAllHovers(); |
Patrick Dubroy | 1262e36 | 2010-10-06 15:49:50 -0700 | [diff] [blame] | 1651 | } |
| 1652 | } |
| 1653 | |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 1654 | public Folder getFolderForTag(Object tag) { |
Michael Jurka | dee0589 | 2010-07-27 10:01:56 -0700 | [diff] [blame] | 1655 | final int screenCount = getChildCount(); |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 1656 | for (int screen = 0; screen < screenCount; screen++) { |
| 1657 | CellLayout currentScreen = ((CellLayout) getChildAt(screen)); |
| 1658 | int count = currentScreen.getChildCount(); |
| 1659 | for (int i = 0; i < count; i++) { |
| 1660 | View child = currentScreen.getChildAt(i); |
| 1661 | CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams(); |
| 1662 | if (lp.cellHSpan == 4 && lp.cellVSpan == 4 && child instanceof Folder) { |
| 1663 | Folder f = (Folder) child; |
Winson Chung | aafa03c | 2010-06-11 17:34:16 -0700 | [diff] [blame] | 1664 | if (f.getInfo() == tag && f.getInfo().opened) { |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 1665 | return f; |
| 1666 | } |
| 1667 | } |
| 1668 | } |
| 1669 | } |
| 1670 | return null; |
| 1671 | } |
| 1672 | |
| 1673 | public View getViewForTag(Object tag) { |
| 1674 | int screenCount = getChildCount(); |
| 1675 | for (int screen = 0; screen < screenCount; screen++) { |
| 1676 | CellLayout currentScreen = ((CellLayout) getChildAt(screen)); |
| 1677 | int count = currentScreen.getChildCount(); |
| 1678 | for (int i = 0; i < count; i++) { |
| 1679 | View child = currentScreen.getChildAt(i); |
| 1680 | if (child.getTag() == tag) { |
| 1681 | return child; |
| 1682 | } |
| 1683 | } |
| 1684 | } |
| 1685 | return null; |
| 1686 | } |
| 1687 | |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 1688 | |
Joe Onorato | 64e6be7 | 2010-03-05 15:05:52 -0500 | [diff] [blame] | 1689 | void removeItems(final ArrayList<ApplicationInfo> apps) { |
Michael Jurka | dee0589 | 2010-07-27 10:01:56 -0700 | [diff] [blame] | 1690 | final int screenCount = getChildCount(); |
Romain Guy | 5c16f3e | 2010-01-12 17:24:58 -0800 | [diff] [blame] | 1691 | final PackageManager manager = getContext().getPackageManager(); |
Romain Guy | 629de3e | 2010-01-13 12:20:59 -0800 | [diff] [blame] | 1692 | final AppWidgetManager widgets = AppWidgetManager.getInstance(getContext()); |
Romain Guy | 574d20e | 2009-06-01 15:34:04 -0700 | [diff] [blame] | 1693 | |
Joe Onorato | 64e6be7 | 2010-03-05 15:05:52 -0500 | [diff] [blame] | 1694 | final HashSet<String> packageNames = new HashSet<String>(); |
| 1695 | final int appCount = apps.size(); |
| 1696 | for (int i = 0; i < appCount; i++) { |
| 1697 | packageNames.add(apps.get(i).componentName.getPackageName()); |
| 1698 | } |
| 1699 | |
Michael Jurka | dee0589 | 2010-07-27 10:01:56 -0700 | [diff] [blame] | 1700 | for (int i = 0; i < screenCount; i++) { |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 1701 | final CellLayout layout = (CellLayout) getChildAt(i); |
Romain Guy | 574d20e | 2009-06-01 15:34:04 -0700 | [diff] [blame] | 1702 | |
Romain Guy | 629de3e | 2010-01-13 12:20:59 -0800 | [diff] [blame] | 1703 | // Avoid ANRs by treating each screen separately |
| 1704 | post(new Runnable() { |
| 1705 | public void run() { |
| 1706 | final ArrayList<View> childrenToRemove = new ArrayList<View>(); |
| 1707 | childrenToRemove.clear(); |
Winson Chung | aafa03c | 2010-06-11 17:34:16 -0700 | [diff] [blame] | 1708 | |
Romain Guy | 629de3e | 2010-01-13 12:20:59 -0800 | [diff] [blame] | 1709 | int childCount = layout.getChildCount(); |
| 1710 | for (int j = 0; j < childCount; j++) { |
| 1711 | final View view = layout.getChildAt(j); |
| 1712 | Object tag = view.getTag(); |
Winson Chung | aafa03c | 2010-06-11 17:34:16 -0700 | [diff] [blame] | 1713 | |
Joe Onorato | 0589f0f | 2010-02-08 13:44:00 -0800 | [diff] [blame] | 1714 | if (tag instanceof ShortcutInfo) { |
| 1715 | final ShortcutInfo info = (ShortcutInfo) tag; |
Romain Guy | 629de3e | 2010-01-13 12:20:59 -0800 | [diff] [blame] | 1716 | final Intent intent = info.intent; |
| 1717 | final ComponentName name = intent.getComponent(); |
Winson Chung | aafa03c | 2010-06-11 17:34:16 -0700 | [diff] [blame] | 1718 | |
Joe Onorato | 64e6be7 | 2010-03-05 15:05:52 -0500 | [diff] [blame] | 1719 | if (Intent.ACTION_MAIN.equals(intent.getAction()) && name != null) { |
| 1720 | for (String packageName: packageNames) { |
| 1721 | if (packageName.equals(name.getPackageName())) { |
Joe Onorato | 64e6be7 | 2010-03-05 15:05:52 -0500 | [diff] [blame] | 1722 | LauncherModel.deleteItemFromDatabase(mLauncher, info); |
| 1723 | childrenToRemove.add(view); |
| 1724 | } |
| 1725 | } |
Romain Guy | 629de3e | 2010-01-13 12:20:59 -0800 | [diff] [blame] | 1726 | } |
| 1727 | } else if (tag instanceof UserFolderInfo) { |
| 1728 | final UserFolderInfo info = (UserFolderInfo) tag; |
Joe Onorato | 0589f0f | 2010-02-08 13:44:00 -0800 | [diff] [blame] | 1729 | final ArrayList<ShortcutInfo> contents = info.contents; |
| 1730 | final ArrayList<ShortcutInfo> toRemove = new ArrayList<ShortcutInfo>(1); |
Romain Guy | 629de3e | 2010-01-13 12:20:59 -0800 | [diff] [blame] | 1731 | final int contentsCount = contents.size(); |
| 1732 | boolean removedFromFolder = false; |
Winson Chung | aafa03c | 2010-06-11 17:34:16 -0700 | [diff] [blame] | 1733 | |
Romain Guy | 629de3e | 2010-01-13 12:20:59 -0800 | [diff] [blame] | 1734 | for (int k = 0; k < contentsCount; k++) { |
Joe Onorato | 0589f0f | 2010-02-08 13:44:00 -0800 | [diff] [blame] | 1735 | final ShortcutInfo appInfo = contents.get(k); |
Romain Guy | 629de3e | 2010-01-13 12:20:59 -0800 | [diff] [blame] | 1736 | final Intent intent = appInfo.intent; |
| 1737 | final ComponentName name = intent.getComponent(); |
Winson Chung | aafa03c | 2010-06-11 17:34:16 -0700 | [diff] [blame] | 1738 | |
Joe Onorato | 64e6be7 | 2010-03-05 15:05:52 -0500 | [diff] [blame] | 1739 | if (Intent.ACTION_MAIN.equals(intent.getAction()) && name != null) { |
| 1740 | for (String packageName: packageNames) { |
| 1741 | if (packageName.equals(name.getPackageName())) { |
| 1742 | toRemove.add(appInfo); |
Brad Fitzpatrick | 73013bf | 2010-09-14 12:15:32 -0700 | [diff] [blame] | 1743 | LauncherModel.deleteItemFromDatabase(mLauncher, appInfo); |
Joe Onorato | 64e6be7 | 2010-03-05 15:05:52 -0500 | [diff] [blame] | 1744 | removedFromFolder = true; |
| 1745 | } |
| 1746 | } |
Romain Guy | 629de3e | 2010-01-13 12:20:59 -0800 | [diff] [blame] | 1747 | } |
| 1748 | } |
Winson Chung | aafa03c | 2010-06-11 17:34:16 -0700 | [diff] [blame] | 1749 | |
Romain Guy | 629de3e | 2010-01-13 12:20:59 -0800 | [diff] [blame] | 1750 | contents.removeAll(toRemove); |
| 1751 | if (removedFromFolder) { |
| 1752 | final Folder folder = getOpenFolder(); |
Winson Chung | aafa03c | 2010-06-11 17:34:16 -0700 | [diff] [blame] | 1753 | if (folder != null) |
| 1754 | folder.notifyDataSetChanged(); |
Romain Guy | 629de3e | 2010-01-13 12:20:59 -0800 | [diff] [blame] | 1755 | } |
| 1756 | } else if (tag instanceof LiveFolderInfo) { |
| 1757 | final LiveFolderInfo info = (LiveFolderInfo) tag; |
| 1758 | final Uri uri = info.uri; |
| 1759 | final ProviderInfo providerInfo = manager.resolveContentProvider( |
| 1760 | uri.getAuthority(), 0); |
Romain Guy | 574d20e | 2009-06-01 15:34:04 -0700 | [diff] [blame] | 1761 | |
Joe Onorato | f11079b | 2010-04-15 11:47:28 -0700 | [diff] [blame] | 1762 | if (providerInfo != null) { |
Joe Onorato | 64e6be7 | 2010-03-05 15:05:52 -0500 | [diff] [blame] | 1763 | for (String packageName: packageNames) { |
| 1764 | if (packageName.equals(providerInfo.packageName)) { |
Joe Onorato | 64e6be7 | 2010-03-05 15:05:52 -0500 | [diff] [blame] | 1765 | LauncherModel.deleteItemFromDatabase(mLauncher, info); |
Winson Chung | aafa03c | 2010-06-11 17:34:16 -0700 | [diff] [blame] | 1766 | childrenToRemove.add(view); |
Joe Onorato | 64e6be7 | 2010-03-05 15:05:52 -0500 | [diff] [blame] | 1767 | } |
| 1768 | } |
Romain Guy | 629de3e | 2010-01-13 12:20:59 -0800 | [diff] [blame] | 1769 | } |
| 1770 | } else if (tag instanceof LauncherAppWidgetInfo) { |
| 1771 | final LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) tag; |
| 1772 | final AppWidgetProviderInfo provider = |
| 1773 | widgets.getAppWidgetInfo(info.appWidgetId); |
Daniel Sandler | e1cc6c3 | 2010-05-07 11:49:29 -0400 | [diff] [blame] | 1774 | if (provider != null) { |
Joe Onorato | 64e6be7 | 2010-03-05 15:05:52 -0500 | [diff] [blame] | 1775 | for (String packageName: packageNames) { |
| 1776 | if (packageName.equals(provider.provider.getPackageName())) { |
Joe Onorato | 64e6be7 | 2010-03-05 15:05:52 -0500 | [diff] [blame] | 1777 | LauncherModel.deleteItemFromDatabase(mLauncher, info); |
Winson Chung | aafa03c | 2010-06-11 17:34:16 -0700 | [diff] [blame] | 1778 | childrenToRemove.add(view); |
Joe Onorato | 64e6be7 | 2010-03-05 15:05:52 -0500 | [diff] [blame] | 1779 | } |
| 1780 | } |
Romain Guy | 629de3e | 2010-01-13 12:20:59 -0800 | [diff] [blame] | 1781 | } |
Romain Guy | 574d20e | 2009-06-01 15:34:04 -0700 | [diff] [blame] | 1782 | } |
| 1783 | } |
Winson Chung | aafa03c | 2010-06-11 17:34:16 -0700 | [diff] [blame] | 1784 | |
Romain Guy | 629de3e | 2010-01-13 12:20:59 -0800 | [diff] [blame] | 1785 | childCount = childrenToRemove.size(); |
| 1786 | for (int j = 0; j < childCount; j++) { |
| 1787 | View child = childrenToRemove.get(j); |
| 1788 | layout.removeViewInLayout(child); |
| 1789 | if (child instanceof DropTarget) { |
| 1790 | mDragController.removeDropTarget((DropTarget)child); |
| 1791 | } |
Romain Guy | 574d20e | 2009-06-01 15:34:04 -0700 | [diff] [blame] | 1792 | } |
Winson Chung | aafa03c | 2010-06-11 17:34:16 -0700 | [diff] [blame] | 1793 | |
Romain Guy | 629de3e | 2010-01-13 12:20:59 -0800 | [diff] [blame] | 1794 | if (childCount > 0) { |
| 1795 | layout.requestLayout(); |
| 1796 | layout.invalidate(); |
Romain Guy | 5c16f3e | 2010-01-12 17:24:58 -0800 | [diff] [blame] | 1797 | } |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 1798 | } |
Romain Guy | 629de3e | 2010-01-13 12:20:59 -0800 | [diff] [blame] | 1799 | }); |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 1800 | } |
| 1801 | } |
The Android Open Source Project | f96811c | 2009-03-18 17:39:48 -0700 | [diff] [blame] | 1802 | |
Joe Onorato | 64e6be7 | 2010-03-05 15:05:52 -0500 | [diff] [blame] | 1803 | void updateShortcuts(ArrayList<ApplicationInfo> apps) { |
Michael Jurka | dee0589 | 2010-07-27 10:01:56 -0700 | [diff] [blame] | 1804 | final int screenCount = getChildCount(); |
| 1805 | for (int i = 0; i < screenCount; i++) { |
The Android Open Source Project | f96811c | 2009-03-18 17:39:48 -0700 | [diff] [blame] | 1806 | final CellLayout layout = (CellLayout) getChildAt(i); |
| 1807 | int childCount = layout.getChildCount(); |
| 1808 | for (int j = 0; j < childCount; j++) { |
| 1809 | final View view = layout.getChildAt(j); |
| 1810 | Object tag = view.getTag(); |
Joe Onorato | 0589f0f | 2010-02-08 13:44:00 -0800 | [diff] [blame] | 1811 | if (tag instanceof ShortcutInfo) { |
| 1812 | ShortcutInfo info = (ShortcutInfo)tag; |
The Android Open Source Project | f96811c | 2009-03-18 17:39:48 -0700 | [diff] [blame] | 1813 | // We need to check for ACTION_MAIN otherwise getComponent() might |
| 1814 | // return null for some shortcuts (for instance, for shortcuts to |
| 1815 | // web pages.) |
| 1816 | final Intent intent = info.intent; |
| 1817 | final ComponentName name = intent.getComponent(); |
| 1818 | if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION && |
Joe Onorato | 64e6be7 | 2010-03-05 15:05:52 -0500 | [diff] [blame] | 1819 | Intent.ACTION_MAIN.equals(intent.getAction()) && name != null) { |
| 1820 | final int appCount = apps.size(); |
Winson Chung | aafa03c | 2010-06-11 17:34:16 -0700 | [diff] [blame] | 1821 | for (int k = 0; k < appCount; k++) { |
Joe Onorato | 64e6be7 | 2010-03-05 15:05:52 -0500 | [diff] [blame] | 1822 | ApplicationInfo app = apps.get(k); |
| 1823 | if (app.componentName.equals(name)) { |
| 1824 | info.setIcon(mIconCache.getIcon(info.intent)); |
| 1825 | ((TextView)view).setCompoundDrawablesWithIntrinsicBounds(null, |
| 1826 | new FastBitmapDrawable(info.getIcon(mIconCache)), |
| 1827 | null, null); |
| 1828 | } |
| 1829 | } |
The Android Open Source Project | f96811c | 2009-03-18 17:39:48 -0700 | [diff] [blame] | 1830 | } |
| 1831 | } |
| 1832 | } |
| 1833 | } |
| 1834 | } |
| 1835 | |
Joe Onorato | 14f122b | 2009-11-19 14:06:36 -0800 | [diff] [blame] | 1836 | void moveToDefaultScreen(boolean animate) { |
Michael Jurka | c0e8fca | 2010-10-06 16:41:29 -0700 | [diff] [blame] | 1837 | if (mIsSmall || mIsInUnshrinkAnimation) { |
| 1838 | mLauncher.showWorkspace(animate, (CellLayout)getChildAt(mDefaultPage)); |
| 1839 | } else if (animate) { |
| 1840 | snapToPage(mDefaultPage); |
Joe Onorato | c45b168 | 2010-01-11 18:48:40 -0500 | [diff] [blame] | 1841 | } else { |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 1842 | setCurrentPage(mDefaultPage); |
Joe Onorato | c45b168 | 2010-01-11 18:48:40 -0500 | [diff] [blame] | 1843 | } |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 1844 | getChildAt(mDefaultPage).requestFocus(); |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 1845 | } |
| 1846 | |
Romain Guy | 8a73c51 | 2009-11-09 19:19:59 -0800 | [diff] [blame] | 1847 | void setIndicators(Drawable previous, Drawable next) { |
| 1848 | mPreviousIndicator = previous; |
| 1849 | mNextIndicator = next; |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 1850 | previous.setLevel(mCurrentPage); |
| 1851 | next.setLevel(mCurrentPage); |
Romain Guy | 8a73c51 | 2009-11-09 19:19:59 -0800 | [diff] [blame] | 1852 | } |
| 1853 | |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 1854 | @Override |
| 1855 | public void syncPages() { |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 1856 | } |
Michael Jurka | 0142d49 | 2010-08-25 17:46:15 -0700 | [diff] [blame] | 1857 | |
| 1858 | @Override |
| 1859 | public void syncPageItems(int page) { |
| 1860 | } |
| 1861 | |
The Android Open Source Project | 31dd503 | 2009-03-03 19:32:27 -0800 | [diff] [blame] | 1862 | } |