CellLayout.java revision 215b416c1f7cf0234b777155b823637a0902739f
131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project/*
231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project *
431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * you may not use this file except in compliance with the License.
631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * You may obtain a copy of the License at
731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project *
831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project *
1031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
1131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
1231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * See the License for the specific language governing permissions and
1431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * limitations under the License.
1531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */
1631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
17a5902524d4403885eb4c50360bf3465c6be796efJoe Onoratopackage com.android.launcher2;
1831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
194be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onoratoimport android.animation.Animator;
20629758ff081a354e43aa409159211210ee4ee85aMichael Jurkaimport android.animation.AnimatorListenerAdapter;
2150e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keelyimport android.animation.AnimatorSet;
2200397b1d9233409d9d6b233b077ae12d09768ce8Chet Haaseimport android.animation.TimeInterpolator;
23de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroyimport android.animation.ValueAnimator;
24de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroyimport android.animation.ValueAnimator.AnimatorUpdateListener;
2531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.content.Context;
2679e56263dbcbe85dc434df372bc6e6730aa13477Joe Onoratoimport android.content.res.Resources;
27aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chungimport android.content.res.TypedArray;
284be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onoratoimport android.graphics.Bitmap;
29aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chungimport android.graphics.Canvas;
300dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynnimport android.graphics.Color;
314be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onoratoimport android.graphics.Paint;
32de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroyimport android.graphics.Point;
33b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohenimport android.graphics.PorterDuff;
34b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohenimport android.graphics.PorterDuffXfermode;
3531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.graphics.Rect;
36482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohenimport android.graphics.drawable.ColorDrawable;
376569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroyimport android.graphics.drawable.Drawable;
38b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohenimport android.graphics.drawable.NinePatchDrawable;
391462de39f01cec0ba785386532719cb0207dd827Adam Cohenimport android.os.Parcelable;
4031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.util.AttributeSet;
414be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onoratoimport android.util.Log;
421462de39f01cec0ba785386532719cb0207dd827Adam Cohenimport android.util.SparseArray;
4331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.MotionEvent;
4431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.View;
4531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.ViewDebug;
4631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.ViewGroup;
47aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chungimport android.view.animation.Animation;
48150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chungimport android.view.animation.DecelerateInterpolator;
49aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chungimport android.view.animation.LayoutAnimationController;
5031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
516639687cd67bab1aeef2a75e5c6bc458b20dc082Adam Cohenimport com.android.launcher.R;
5269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohenimport com.android.launcher2.FolderIcon.FolderRingAnimator;
538e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy
5469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohenimport java.util.ArrayList;
55c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohenimport java.util.Arrays;
56bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohenimport java.util.HashMap;
57d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohenimport java.util.Stack;
58c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen
59bdb5c5342adc550559fd723af461e53248f2fba8Michael Jurkapublic class CellLayout extends ViewGroup {
60aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung    static final String TAG = "CellLayout";
61aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
622acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen    private Launcher mLauncher;
6331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private int mCellWidth;
6431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private int mCellHeight;
65aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
66d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen    private int mCountX;
67d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen    private int mCountY;
6831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
69234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen    private int mOriginalWidthGap;
70234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen    private int mOriginalHeightGap;
7131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private int mWidthGap;
7231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private int mHeightGap;
734b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung    private int mMaxGap;
74ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen    private boolean mScrollingTransformsDirty = false;
7531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
7631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private final Rect mRect = new Rect();
7731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private final CellInfo mCellInfo = new CellInfo();
78aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
79de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy    // These are temporary variables to prevent having to allocate a new object just to
80de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy    // return an (x, y) value from helper functions. Do NOT use them to maintain other state.
810be025d64c1f84138fe430a58875886e66aae767Winson Chung    private final int[] mTmpXY = new int[2];
82de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy    private final int[] mTmpPoint = new int[2];
8369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen    int[] mTempLocation = new int[2];
846569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
8531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    boolean[][] mOccupied;
86482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    boolean[][] mTmpOccupied;
87d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka    private boolean mLastDownOnOccupiedCell = false;
8831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
89dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    private OnTouchListener mInterceptTouchListener;
90dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka
9169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen    private ArrayList<FolderRingAnimator> mFolderOuterRings = new ArrayList<FolderRingAnimator>();
92c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen    private int[] mFolderLeaveBehindCell = {-1, -1};
9369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
94b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    private int mForegroundAlpha = 0;
955f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka    private float mBackgroundAlpha;
961b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen    private float mBackgroundAlphaMultiplier = 1.0f;
97f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen
9833945b21544bc98381df17726a3537c292d8c985Michael Jurka    private Drawable mNormalBackground;
9933945b21544bc98381df17726a3537c292d8c985Michael Jurka    private Drawable mActiveGlowBackground;
100b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    private Drawable mOverScrollForegroundDrawable;
101b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    private Drawable mOverScrollLeft;
102b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    private Drawable mOverScrollRight;
10318014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka    private Rect mBackgroundRect;
104b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    private Rect mForegroundRect;
105b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    private int mForegroundPadding;
10633945b21544bc98381df17726a3537c292d8c985Michael Jurka
10733945b21544bc98381df17726a3537c292d8c985Michael Jurka    // If we're actively dragging something over this screen, mIsDragOverlapping is true
10833945b21544bc98381df17726a3537c292d8c985Michael Jurka    private boolean mIsDragOverlapping = false;
109de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy    private final Point mDragCenter = new Point();
1106569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
111150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung    // These arrays are used to implement the drag visualization on x-large screens.
1124be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato    // They are used as circular arrays, indexed by mDragOutlineCurrent.
113d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    private Rect[] mDragOutlines = new Rect[4];
114472b281d5cb4f5660df981a6c912266b9f5703feChet Haase    private float[] mDragOutlineAlphas = new float[mDragOutlines.length];
1154be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato    private InterruptibleInOutAnimator[] mDragOutlineAnims =
1164be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            new InterruptibleInOutAnimator[mDragOutlines.length];
117150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung
118150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung    // Used as an index into the above 3 arrays; indicates which is the most current value.
1194be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato    private int mDragOutlineCurrent = 0;
1208e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy    private final Paint mDragOutlinePaint = new Paint();
121150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung
12296864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy    private BubbleTextView mPressedOrFocusedIcon;
12396864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy
124482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private HashMap<CellLayout.LayoutParams, Animator> mReorderAnimators = new
125482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            HashMap<CellLayout.LayoutParams, Animator>();
12619f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private HashMap<View, ReorderHintAnimation>
12719f3792523fe2d55ea791a9286398a6120920690Adam Cohen            mShakeAnimators = new HashMap<View, ReorderHintAnimation>();
12819f3792523fe2d55ea791a9286398a6120920690Adam Cohen
12919f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private boolean mItemPlacementDirty = false;
130bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen
1316569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    // When a drag operation is in progress, holds the nearest cell to the touch point
1326569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    private final int[] mDragCell = new int[2];
13331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
1344be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato    private boolean mDragging = false;
1354be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato
136ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy    private TimeInterpolator mEaseOutInterpolator;
137a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka    private ShortcutAndWidgetContainer mShortcutsAndWidgets;
138ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy
1390dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn    private boolean mIsHotseat = false;
140307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen    private float mHotseatScale = 1f;
1410dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn
142482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public static final int MODE_DRAG_OVER = 0;
143482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public static final int MODE_ON_DROP = 1;
144482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public static final int MODE_ON_DROP_EXTERNAL = 2;
145482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public static final int MODE_ACCEPT_DROP = 3;
14619f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private static final boolean DESTRUCTIVE_REORDER = false;
147482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private static final boolean DEBUG_VISUALIZE_OCCUPIED = false;
148482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
149a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen    static final int LANDSCAPE = 0;
150a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen    static final int PORTRAIT = 1;
151a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen
1527bdfc9700b1cad043c04c757f134db1bf3df00daAdam Cohen    private static final float REORDER_HINT_MAGNITUDE = 0.12f;
15319f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private static final int REORDER_ANIMATION_DURATION = 150;
15419f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private float mReorderHintAnimationMagnitude;
15519f3792523fe2d55ea791a9286398a6120920690Adam Cohen
156482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private ArrayList<View> mIntersectingViews = new ArrayList<View>();
157482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private Rect mOccupiedRect = new Rect();
158482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private int[] mDirectionVector = new int[2];
15919f3792523fe2d55ea791a9286398a6120920690Adam Cohen    int[] mPreviousReorderDirection = new int[2];
160b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen    private static final int INVALID_DIRECTION = -100;
161c6cc61d45836e4081920883cc4d448ccb0bb8417Adam Cohen    private DropTarget.DragEnforcer mDragEnforcer;
162482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1638a0bff5e35f63321178bbf777ec24d42544866b3Romain Guy    private final static PorterDuffXfermode sAddBlendMode =
1648a0bff5e35f63321178bbf777ec24d42544866b3Romain Guy            new PorterDuffXfermode(PorterDuff.Mode.ADD);
165ca99383daef92fed673de22126875cb485be494fMichael Jurka    private final static Paint sPaint = new Paint();
1668a0bff5e35f63321178bbf777ec24d42544866b3Romain Guy
16731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public CellLayout(Context context) {
16831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        this(context, null);
16931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
17031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
17131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public CellLayout(Context context, AttributeSet attrs) {
17231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        this(context, attrs, 0);
17331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
17431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
17531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public CellLayout(Context context, AttributeSet attrs, int defStyle) {
17631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        super(context, attrs, defStyle);
1778b805b17158886035b38261eb611d8641701ae43Michael Jurka        mDragEnforcer = new DropTarget.DragEnforcer(context);
1786569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
1796569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        // A ViewGroup usually does not draw, but CellLayout needs to draw a rectangle to show
1806569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        // the user where a dragged item will land when dropped.
1816569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        setWillNotDraw(false);
1822acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen        mLauncher = (Launcher) context;
183a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka
18431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CellLayout, defStyle, 0);
18531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
186f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        mCellWidth = a.getDimensionPixelSize(R.styleable.CellLayout_cellWidth, 10);
187f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        mCellHeight = a.getDimensionPixelSize(R.styleable.CellLayout_cellHeight, 10);
188234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen        mWidthGap = mOriginalWidthGap = a.getDimensionPixelSize(R.styleable.CellLayout_widthGap, 0);
189234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen        mHeightGap = mOriginalHeightGap = a.getDimensionPixelSize(R.styleable.CellLayout_heightGap, 0);
1904b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        mMaxGap = a.getDimensionPixelSize(R.styleable.CellLayout_maxGap, 0);
191d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        mCountX = LauncherModel.getCellCountX();
192d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        mCountY = LauncherModel.getCellCountY();
1930280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        mOccupied = new boolean[mCountX][mCountY];
194482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        mTmpOccupied = new boolean[mCountX][mCountY];
1955b53f29f809a0dad4a1e0717ba610ce737ee0f43Adam Cohen        mPreviousReorderDirection[0] = INVALID_DIRECTION;
1965b53f29f809a0dad4a1e0717ba610ce737ee0f43Adam Cohen        mPreviousReorderDirection[1] = INVALID_DIRECTION;
19731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
19831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        a.recycle();
19931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
20031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        setAlwaysDrawnWithCacheEnabled(false);
20131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
202046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        final Resources res = getResources();
203307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        mHotseatScale = (res.getInteger(R.integer.hotseat_item_scale_percentage) / 100f);
204de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy
205967289b6d5fec77f5c381d11ffb2319f3bb5e737Winson Chung        mNormalBackground = res.getDrawable(R.drawable.homescreen_blue_normal_holo);
206dea74b7d12b0fcd50bfdb4274f9867ba76d75238Winson Chung        mActiveGlowBackground = res.getDrawable(R.drawable.homescreen_blue_strong_holo);
207b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung
208b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        mOverScrollLeft = res.getDrawable(R.drawable.overscroll_glow_left);
209b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        mOverScrollRight = res.getDrawable(R.drawable.overscroll_glow_right);
210b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        mForegroundPadding =
211b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen                res.getDimensionPixelSize(R.dimen.workspace_overscroll_drawable_padding);
212b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung
21319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        mReorderHintAnimationMagnitude = (REORDER_HINT_MAGNITUDE *
21419f3792523fe2d55ea791a9286398a6120920690Adam Cohen                res.getDimensionPixelSize(R.dimen.app_icon_size));
21519f3792523fe2d55ea791a9286398a6120920690Adam Cohen
216b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung        mNormalBackground.setFilterBitmap(true);
217b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung        mActiveGlowBackground.setFilterBitmap(true);
218de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy
219046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        // Initialize the data structures used for the drag visualization.
220150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung
221ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy        mEaseOutInterpolator = new DecelerateInterpolator(2.5f); // Quint ease out
222de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy
223046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy
224b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung        mDragCell[0] = mDragCell[1] = -1;
2254be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        for (int i = 0; i < mDragOutlines.length; i++) {
226d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            mDragOutlines[i] = new Rect(-1, -1, -1, -1);
227046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        }
228046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy
229046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        // When dragging things around the home screens, we show a green outline of
230046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        // where the item will land. The outlines gradually fade out, leaving a trail
231046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        // behind the drag path.
232046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        // Set up all the animations that are used to implement this fading.
233046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        final int duration = res.getInteger(R.integer.config_dragOutlineFadeTime);
234472b281d5cb4f5660df981a6c912266b9f5703feChet Haase        final float fromAlphaValue = 0;
235472b281d5cb4f5660df981a6c912266b9f5703feChet Haase        final float toAlphaValue = (float)res.getInteger(R.integer.config_dragOutlineMaxAlpha);
2364be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato
2378e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy        Arrays.fill(mDragOutlineAlphas, fromAlphaValue);
2384be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato
2394be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        for (int i = 0; i < mDragOutlineAnims.length; i++) {
240046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy            final InterruptibleInOutAnimator anim =
241046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy                new InterruptibleInOutAnimator(duration, fromAlphaValue, toAlphaValue);
242ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy            anim.getAnimator().setInterpolator(mEaseOutInterpolator);
243046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy            final int thisIndex = i;
244472b281d5cb4f5660df981a6c912266b9f5703feChet Haase            anim.getAnimator().addUpdateListener(new AnimatorUpdateListener() {
245de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                public void onAnimationUpdate(ValueAnimator animation) {
2464be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    final Bitmap outline = (Bitmap)anim.getTag();
2474be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato
2484be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    // If an animation is started and then stopped very quickly, we can still
2494be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    // get spurious updates we've cleared the tag. Guard against this.
2504be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    if (outline == null) {
2513a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka                        @SuppressWarnings("all") // suppress dead code warning
2523a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka                        final boolean debug = false;
2533a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka                        if (debug) {
254fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy                            Object val = animation.getAnimatedValue();
255fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy                            Log.d(TAG, "anim " + thisIndex + " update: " + val +
256fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy                                     ", isStopped " + anim.isStopped());
257fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy                        }
2584be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                        // Try to prevent it from continuing to run
2594be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                        animation.cancel();
2604be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    } else {
261472b281d5cb4f5660df981a6c912266b9f5703feChet Haase                        mDragOutlineAlphas[thisIndex] = (Float) animation.getAnimatedValue();
262d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        CellLayout.this.invalidate(mDragOutlines[thisIndex]);
2634be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    }
264de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                }
265de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy            });
2664be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            // The animation holds a reference to the drag outline bitmap as long is it's
2674be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            // running. This way the bitmap can be GCed when the animations are complete.
268472b281d5cb4f5660df981a6c912266b9f5703feChet Haase            anim.getAnimator().addListener(new AnimatorListenerAdapter() {
2693c4c20fbe682cb4b3ef94f09afe0af09171583f3Michael Jurka                @Override
2704be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                public void onAnimationEnd(Animator animation) {
271472b281d5cb4f5660df981a6c912266b9f5703feChet Haase                    if ((Float) ((ValueAnimator) animation).getAnimatedValue() == 0f) {
2724be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                        anim.setTag(null);
2734be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    }
2744be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                }
2754be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            });
2764be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            mDragOutlineAnims[i] = anim;
277de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy        }
278ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy
27918014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka        mBackgroundRect = new Rect();
280b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        mForegroundRect = new Rect();
281bea15195346bab3c52b0156e92f2b71f0811b210Michael Jurka
282a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets = new ShortcutAndWidgetContainer(context);
283a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.setCellDimensions(mCellWidth, mCellHeight, mWidthGap, mHeightGap);
284a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        addView(mShortcutsAndWidgets);
28518014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka    }
28618014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka
287f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka    static int widthInPortrait(Resources r, int numCells) {
288f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka        // We use this method from Workspace to figure out how many rows/columns Launcher should
289f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka        // have. We ignore the left/right padding on CellLayout because it turns out in our design
290f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka        // the padding extends outside the visible screen size, but it looked fine anyway.
291f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka        int cellWidth = r.getDimensionPixelSize(R.dimen.workspace_cell_width);
2924b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        int minGap = Math.min(r.getDimensionPixelSize(R.dimen.workspace_width_gap),
2934b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                r.getDimensionPixelSize(R.dimen.workspace_height_gap));
294f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka
2954b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        return  minGap * (numCells - 1) + cellWidth * numCells;
296f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka    }
297f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka
298f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka    static int heightInLandscape(Resources r, int numCells) {
299f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka        // We use this method from Workspace to figure out how many rows/columns Launcher should
300f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka        // have. We ignore the left/right padding on CellLayout because it turns out in our design
301f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka        // the padding extends outside the visible screen size, but it looked fine anyway.
302f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka        int cellHeight = r.getDimensionPixelSize(R.dimen.workspace_cell_height);
3034b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        int minGap = Math.min(r.getDimensionPixelSize(R.dimen.workspace_width_gap),
3044b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                r.getDimensionPixelSize(R.dimen.workspace_height_gap));
305f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka
3064b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        return minGap * (numCells - 1) + cellHeight * numCells;
307f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka    }
308f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka
3092801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    public void enableHardwareLayers() {
310ca99383daef92fed673de22126875cb485be494fMichael Jurka        mShortcutsAndWidgets.setLayerType(LAYER_TYPE_HARDWARE, sPaint);
311d51f33a6316c34fc69b8040946ed9a62519bb225Michael Jurka    }
312d51f33a6316c34fc69b8040946ed9a62519bb225Michael Jurka
313d51f33a6316c34fc69b8040946ed9a62519bb225Michael Jurka    public void disableHardwareLayers() {
314ca99383daef92fed673de22126875cb485be494fMichael Jurka        mShortcutsAndWidgets.setLayerType(LAYER_TYPE_NONE, sPaint);
315d51f33a6316c34fc69b8040946ed9a62519bb225Michael Jurka    }
316d51f33a6316c34fc69b8040946ed9a62519bb225Michael Jurka
317d51f33a6316c34fc69b8040946ed9a62519bb225Michael Jurka    public void buildHardwareLayer() {
318d51f33a6316c34fc69b8040946ed9a62519bb225Michael Jurka        mShortcutsAndWidgets.buildLayer();
3192801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    }
3202801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
321307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen    public float getChildrenScale() {
322307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        return mIsHotseat ? mHotseatScale : 1.0f;
323307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen    }
324307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen
3252801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    public void setGridSize(int x, int y) {
3262801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        mCountX = x;
3272801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        mCountY = y;
3282801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        mOccupied = new boolean[mCountX][mCountY];
329482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        mTmpOccupied = new boolean[mCountX][mCountY];
3307fbec10b36818f100b631f3d73fe1ad5360975aaAdam Cohen        mTempRectStack.clear();
33176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        requestLayout();
3322801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    }
3332801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
33496864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy    private void invalidateBubbleTextView(BubbleTextView icon) {
33596864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        final int padding = icon.getPressedOrFocusedBackgroundPadding();
3364b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        invalidate(icon.getLeft() + getPaddingLeft() - padding,
3374b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                icon.getTop() + getPaddingTop() - padding,
3384b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                icon.getRight() + getPaddingLeft() + padding,
3394b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                icon.getBottom() + getPaddingTop() + padding);
34096864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy    }
34196864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy
342b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    void setOverScrollAmount(float r, boolean left) {
343b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        if (left && mOverScrollForegroundDrawable != mOverScrollLeft) {
344b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen            mOverScrollForegroundDrawable = mOverScrollLeft;
345b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        } else if (!left && mOverScrollForegroundDrawable != mOverScrollRight) {
346b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen            mOverScrollForegroundDrawable = mOverScrollRight;
347b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        }
348b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen
349b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        mForegroundAlpha = (int) Math.round((r * 255));
350b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        mOverScrollForegroundDrawable.setAlpha(mForegroundAlpha);
351b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        invalidate();
352b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    }
353b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen
35496864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy    void setPressedOrFocusedIcon(BubbleTextView icon) {
35596864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        // We draw the pressed or focused BubbleTextView's background in CellLayout because it
35696864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        // requires an expanded clip rect (due to the glow's blur radius)
35796864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        BubbleTextView oldIcon = mPressedOrFocusedIcon;
35896864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        mPressedOrFocusedIcon = icon;
35996864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        if (oldIcon != null) {
36096864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy            invalidateBubbleTextView(oldIcon);
36196864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        }
36296864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        if (mPressedOrFocusedIcon != null) {
36396864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy            invalidateBubbleTextView(mPressedOrFocusedIcon);
36496864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        }
36596864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy    }
36696864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy
36733945b21544bc98381df17726a3537c292d8c985Michael Jurka    void setIsDragOverlapping(boolean isDragOverlapping) {
36833945b21544bc98381df17726a3537c292d8c985Michael Jurka        if (mIsDragOverlapping != isDragOverlapping) {
36933945b21544bc98381df17726a3537c292d8c985Michael Jurka            mIsDragOverlapping = isDragOverlapping;
37033945b21544bc98381df17726a3537c292d8c985Michael Jurka            invalidate();
37133945b21544bc98381df17726a3537c292d8c985Michael Jurka        }
37233945b21544bc98381df17726a3537c292d8c985Michael Jurka    }
37333945b21544bc98381df17726a3537c292d8c985Michael Jurka
37433945b21544bc98381df17726a3537c292d8c985Michael Jurka    boolean getIsDragOverlapping() {
37533945b21544bc98381df17726a3537c292d8c985Michael Jurka        return mIsDragOverlapping;
37633945b21544bc98381df17726a3537c292d8c985Michael Jurka    }
37733945b21544bc98381df17726a3537c292d8c985Michael Jurka
378ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen    protected void setOverscrollTransformsDirty(boolean dirty) {
379ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen        mScrollingTransformsDirty = dirty;
380ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen    }
381ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen
382ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen    protected void resetOverscrollTransforms() {
383ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen        if (mScrollingTransformsDirty) {
384ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            setOverscrollTransformsDirty(false);
385ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            setTranslationX(0);
386ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            setRotationY(0);
387ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            // It doesn't matter if we pass true or false here, the important thing is that we
388ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            // pass 0, which results in the overscroll drawable not being drawn any more.
389ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            setOverScrollAmount(0, false);
390ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            setPivotX(getMeasuredWidth() / 2);
391ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            setPivotY(getMeasuredHeight() / 2);
392ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen        }
393ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen    }
394ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen
395307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen    public void scaleRect(Rect r, float scale) {
396307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        if (scale != 1.0f) {
397307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen            r.left = (int) (r.left * scale + 0.5f);
398307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen            r.top = (int) (r.top * scale + 0.5f);
399307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen            r.right = (int) (r.right * scale + 0.5f);
400307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen            r.bottom = (int) (r.bottom * scale + 0.5f);
401307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        }
402307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen    }
403307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen
404307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen    Rect temp = new Rect();
405307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen    void scaleRectAboutCenter(Rect in, Rect out, float scale) {
406307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        int cx = in.centerX();
407307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        int cy = in.centerY();
408307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        out.set(in);
409307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        out.offset(-cx, -cy);
410307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        scaleRect(out, scale);
411307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        out.offset(cx, cy);
412307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen    }
413307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen
414a6abce8464b57ce91e8f083951ad263370fc2da8Romain Guy    @Override
4151262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy    protected void onDraw(Canvas canvas) {
4163e7c7634531302271270c8cf418abc959d621cbcMichael Jurka        // When we're large, we are either drawn in a "hover" state (ie when dragging an item to
4173e7c7634531302271270c8cf418abc959d621cbcMichael Jurka        // a neighboring page) or with just a normal background (if backgroundAlpha > 0.0f)
4183e7c7634531302271270c8cf418abc959d621cbcMichael Jurka        // When we're small, we are either drawn normally or in the "accepts drops" state (during
4193e7c7634531302271270c8cf418abc959d621cbcMichael Jurka        // a drag). However, we also drag the mini hover background *over* one of those two
4203e7c7634531302271270c8cf418abc959d621cbcMichael Jurka        // backgrounds
421b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung        if (mBackgroundAlpha > 0.0f) {
422f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen            Drawable bg;
42333945b21544bc98381df17726a3537c292d8c985Michael Jurka
42433945b21544bc98381df17726a3537c292d8c985Michael Jurka            if (mIsDragOverlapping) {
42533945b21544bc98381df17726a3537c292d8c985Michael Jurka                // In the mini case, we draw the active_glow bg *over* the active background
426bdf78559f223ac11e01e3311edd5a48a80383e1eMichael Jurka                bg = mActiveGlowBackground;
427f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen            } else {
428bdf78559f223ac11e01e3311edd5a48a80383e1eMichael Jurka                bg = mNormalBackground;
429f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen            }
43033945b21544bc98381df17726a3537c292d8c985Michael Jurka
43133945b21544bc98381df17726a3537c292d8c985Michael Jurka            bg.setAlpha((int) (mBackgroundAlpha * mBackgroundAlphaMultiplier * 255));
43233945b21544bc98381df17726a3537c292d8c985Michael Jurka            bg.setBounds(mBackgroundRect);
43333945b21544bc98381df17726a3537c292d8c985Michael Jurka            bg.draw(canvas);
434a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka        }
43531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
4368e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy        final Paint paint = mDragOutlinePaint;
4374be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        for (int i = 0; i < mDragOutlines.length; i++) {
438472b281d5cb4f5660df981a6c912266b9f5703feChet Haase            final float alpha = mDragOutlineAlphas[i];
4394be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            if (alpha > 0) {
440d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                final Rect r = mDragOutlines[i];
441307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen                scaleRectAboutCenter(r, temp, getChildrenScale());
4424be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                final Bitmap b = (Bitmap) mDragOutlineAnims[i].getTag();
443472b281d5cb4f5660df981a6c912266b9f5703feChet Haase                paint.setAlpha((int)(alpha + .5f));
444307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen                canvas.drawBitmap(b, null, temp, paint);
445150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung            }
4466569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        }
44796864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy
44896864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        // We draw the pressed or focused BubbleTextView's background in CellLayout because it
44996864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        // requires an expanded clip rect (due to the glow's blur radius)
45096864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        if (mPressedOrFocusedIcon != null) {
45196864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy            final int padding = mPressedOrFocusedIcon.getPressedOrFocusedBackgroundPadding();
45296864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy            final Bitmap b = mPressedOrFocusedIcon.getPressedOrFocusedBackground();
45396864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy            if (b != null) {
45496864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy                canvas.drawBitmap(b,
4554b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                        mPressedOrFocusedIcon.getLeft() + getPaddingLeft() - padding,
4564b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                        mPressedOrFocusedIcon.getTop() + getPaddingTop() - padding,
45796864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy                        null);
45896864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy            }
45996864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        }
46069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
461482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (DEBUG_VISUALIZE_OCCUPIED) {
462482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            int[] pt = new int[2];
463482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            ColorDrawable cd = new ColorDrawable(Color.RED);
464e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen            cd.setBounds(0, 0,  mCellWidth, mCellHeight);
465482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            for (int i = 0; i < mCountX; i++) {
466482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                for (int j = 0; j < mCountY; j++) {
467482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    if (mOccupied[i][j]) {
468482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        cellToPoint(i, j, pt);
469482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        canvas.save();
470482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        canvas.translate(pt[0], pt[1]);
471482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        cd.draw(canvas);
472482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        canvas.restore();
473482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    }
474482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                }
475482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
476482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
477482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
478850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn        int previewOffset = FolderRingAnimator.sPreviewSize;
479850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn
48069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        // The folder outer / inner ring image(s)
48169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        for (int i = 0; i < mFolderOuterRings.size(); i++) {
48269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            FolderRingAnimator fra = mFolderOuterRings.get(i);
48369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
48469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            // Draw outer ring
48569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            Drawable d = FolderRingAnimator.sSharedOuterRingDrawable;
48669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            int width = (int) fra.getOuterRingSize();
48769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            int height = width;
48869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            cellToPoint(fra.mCellX, fra.mCellY, mTempLocation);
48969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
49069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            int centerX = mTempLocation[0] + mCellWidth / 2;
491850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn            int centerY = mTempLocation[1] + previewOffset / 2;
49269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
49369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            canvas.save();
49469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            canvas.translate(centerX - width / 2, centerY - height / 2);
49569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            d.setBounds(0, 0, width, height);
49669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            d.draw(canvas);
49769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            canvas.restore();
49869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
49969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            // Draw inner ring
50069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            d = FolderRingAnimator.sSharedInnerRingDrawable;
50169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            width = (int) fra.getInnerRingSize();
50269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            height = width;
50369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            cellToPoint(fra.mCellX, fra.mCellY, mTempLocation);
50469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
50569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            centerX = mTempLocation[0] + mCellWidth / 2;
506850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn            centerY = mTempLocation[1] + previewOffset / 2;
50769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            canvas.save();
50869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            canvas.translate(centerX - width / 2, centerY - width / 2);
50969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            d.setBounds(0, 0, width, height);
51069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            d.draw(canvas);
51169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            canvas.restore();
51269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        }
513c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen
514c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        if (mFolderLeaveBehindCell[0] >= 0 && mFolderLeaveBehindCell[1] >= 0) {
515c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            Drawable d = FolderIcon.sSharedFolderLeaveBehind;
516c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            int width = d.getIntrinsicWidth();
517c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            int height = d.getIntrinsicHeight();
518c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen
519c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            cellToPoint(mFolderLeaveBehindCell[0], mFolderLeaveBehindCell[1], mTempLocation);
520c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            int centerX = mTempLocation[0] + mCellWidth / 2;
521850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn            int centerY = mTempLocation[1] + previewOffset / 2;
522c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen
523c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            canvas.save();
524c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            canvas.translate(centerX - width / 2, centerY - width / 2);
525c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            d.setBounds(0, 0, width, height);
526c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            d.draw(canvas);
527c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            canvas.restore();
528c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        }
52969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen    }
53069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
531b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    @Override
532b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    protected void dispatchDraw(Canvas canvas) {
533b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        super.dispatchDraw(canvas);
534b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        if (mForegroundAlpha > 0) {
535b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen            mOverScrollForegroundDrawable.setBounds(mForegroundRect);
536b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen            Paint p = ((NinePatchDrawable) mOverScrollForegroundDrawable).getPaint();
5378a0bff5e35f63321178bbf777ec24d42544866b3Romain Guy            p.setXfermode(sAddBlendMode);
538b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen            mOverScrollForegroundDrawable.draw(canvas);
539b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen            p.setXfermode(null);
540b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        }
541b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    }
542b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen
54369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen    public void showFolderAccept(FolderRingAnimator fra) {
54469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        mFolderOuterRings.add(fra);
54569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen    }
54669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
54769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen    public void hideFolderAccept(FolderRingAnimator fra) {
54869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        if (mFolderOuterRings.contains(fra)) {
54969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            mFolderOuterRings.remove(fra);
55069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        }
55169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        invalidate();
5526569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    }
5536569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
554c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen    public void setFolderLeaveBehindCell(int x, int y) {
555c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        mFolderLeaveBehindCell[0] = x;
556c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        mFolderLeaveBehindCell[1] = y;
557c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        invalidate();
558c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen    }
559c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen
560c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen    public void clearFolderLeaveBehind() {
561c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        mFolderLeaveBehindCell[0] = -1;
562c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        mFolderLeaveBehindCell[1] = -1;
563c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        invalidate();
564c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen    }
565c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen
5666569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    @Override
567e6235dd225404239b55c459245543f3302326112Michael Jurka    public boolean shouldDelayChildPressedState() {
568e6235dd225404239b55c459245543f3302326112Michael Jurka        return false;
569e6235dd225404239b55c459245543f3302326112Michael Jurka    }
570e6235dd225404239b55c459245543f3302326112Michael Jurka
5711462de39f01cec0ba785386532719cb0207dd827Adam Cohen    public void restoreInstanceState(SparseArray<Parcelable> states) {
5721462de39f01cec0ba785386532719cb0207dd827Adam Cohen        dispatchRestoreInstanceState(states);
5731462de39f01cec0ba785386532719cb0207dd827Adam Cohen    }
5741462de39f01cec0ba785386532719cb0207dd827Adam Cohen
575e6235dd225404239b55c459245543f3302326112Michael Jurka    @Override
57683f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey    public void cancelLongPress() {
57783f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey        super.cancelLongPress();
57883f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey
57983f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey        // Cancel long press for all children
58083f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey        final int count = getChildCount();
58183f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey        for (int i = 0; i < count; i++) {
58283f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey            final View child = getChildAt(i);
58383f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey            child.cancelLongPress();
58483f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey        }
58583f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey    }
58683f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey
587dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    public void setOnInterceptTouchListener(View.OnTouchListener listener) {
588dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka        mInterceptTouchListener = listener;
589dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    }
590dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka
59131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    int getCountX() {
592d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        return mCountX;
59331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
59431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
59531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    int getCountY() {
596d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        return mCountY;
59731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
59831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
5990dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn    public void setIsHotseat(boolean isHotseat) {
6000dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn        mIsHotseat = isHotseat;
6010dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn    }
6020dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn
6030dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn    public boolean addViewToCellLayout(View child, int index, int childId, LayoutParams params,
604850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn            boolean markCells) {
605aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        final LayoutParams lp = params;
606aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
607de38e42fe89fd7490221427908cd97c51da21b44Andrew Flynn        // Hotseat icons - remove text
6080dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn        if (child instanceof BubbleTextView) {
6090dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn            BubbleTextView bubbleChild = (BubbleTextView) child;
6100dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn
611de38e42fe89fd7490221427908cd97c51da21b44Andrew Flynn            Resources res = getResources();
612de38e42fe89fd7490221427908cd97c51da21b44Andrew Flynn            if (mIsHotseat) {
613de38e42fe89fd7490221427908cd97c51da21b44Andrew Flynn                bubbleChild.setTextColor(res.getColor(android.R.color.transparent));
614de38e42fe89fd7490221427908cd97c51da21b44Andrew Flynn            } else {
615de38e42fe89fd7490221427908cd97c51da21b44Andrew Flynn                bubbleChild.setTextColor(res.getColor(R.color.workspace_icon_text_color));
6160dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn            }
6170dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn        }
6180dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn
619307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        child.setScaleX(getChildrenScale());
620307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        child.setScaleY(getChildrenScale());
621307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen
62231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // Generate an id for each view, this assumes we have at most 256x256 cells
62331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // per workspace screen
624d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        if (lp.cellX >= 0 && lp.cellX <= mCountX - 1 && lp.cellY >= 0 && lp.cellY <= mCountY - 1) {
625aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            // If the horizontal or vertical span is set to -1, it is taken to
626aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            // mean that it spans the extent of the CellLayout
627d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen            if (lp.cellHSpan < 0) lp.cellHSpan = mCountX;
628d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen            if (lp.cellVSpan < 0) lp.cellVSpan = mCountY;
629aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
630aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            child.setId(childId);
63131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
632a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            mShortcutsAndWidgets.addView(child, index, lp);
633dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka
634f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka            if (markCells) markCellsAsOccupiedForView(child);
6350280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
636aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            return true;
637aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        }
638aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        return false;
63931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
6403e7c7634531302271270c8cf418abc959d621cbcMichael Jurka
64131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
6420280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public void removeAllViews() {
6430280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        clearOccupiedCells();
644a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.removeAllViews();
6450280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
6460280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
6470280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    @Override
6480280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public void removeAllViewsInLayout() {
649a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        if (mShortcutsAndWidgets.getChildCount() > 0) {
6507cfc2825c3a1029f962d2fc387ae2eaa85b51798Michael Jurka            clearOccupiedCells();
651a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            mShortcutsAndWidgets.removeAllViewsInLayout();
6527cfc2825c3a1029f962d2fc387ae2eaa85b51798Michael Jurka        }
6530280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
6540280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
655f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka    public void removeViewWithoutMarkingCells(View view) {
656a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.removeView(view);
657f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka    }
658f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka
6590280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    @Override
6600280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public void removeView(View view) {
6610280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        markCellsAsUnoccupiedForView(view);
662a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.removeView(view);
6630280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
6640280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
6650280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    @Override
6660280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public void removeViewAt(int index) {
667a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        markCellsAsUnoccupiedForView(mShortcutsAndWidgets.getChildAt(index));
668a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.removeViewAt(index);
6690280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
6700280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
6710280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    @Override
6720280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public void removeViewInLayout(View view) {
6730280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        markCellsAsUnoccupiedForView(view);
674a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.removeViewInLayout(view);
6750280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
6760280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
6770280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    @Override
6780280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public void removeViews(int start, int count) {
6790280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        for (int i = start; i < start + count; i++) {
680a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            markCellsAsUnoccupiedForView(mShortcutsAndWidgets.getChildAt(i));
6810280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        }
682a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.removeViews(start, count);
6830280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
6840280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
6850280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    @Override
6860280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public void removeViewsInLayout(int start, int count) {
6870280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        for (int i = start; i < start + count; i++) {
688a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            markCellsAsUnoccupiedForView(mShortcutsAndWidgets.getChildAt(i));
6890280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        }
690a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.removeViewsInLayout(start, count);
691abded66084680bb31cc7ea403c88f44f79a3c884Michael Jurka    }
692abded66084680bb31cc7ea403c88f44f79a3c884Michael Jurka
69331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
69431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    protected void onAttachedToWindow() {
69531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        super.onAttachedToWindow();
69631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        mCellInfo.screen = ((ViewGroup) getParent()).indexOfChild(this);
69731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
69831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
699af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka    public void setTagToCellInfoForPoint(int touchX, int touchY) {
70031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        final CellInfo cellInfo = mCellInfo;
701eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung        Rect frame = mRect;
7028b805b17158886035b38261eb611d8641701ae43Michael Jurka        final int x = touchX + getScrollX();
7038b805b17158886035b38261eb611d8641701ae43Michael Jurka        final int y = touchY + getScrollY();
704a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        final int count = mShortcutsAndWidgets.getChildCount();
70531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
706af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka        boolean found = false;
707af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka        for (int i = count - 1; i >= 0; i--) {
708a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            final View child = mShortcutsAndWidgets.getChildAt(i);
709d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
710af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka
7111b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen            if ((child.getVisibility() == VISIBLE || child.getAnimation() != null) &&
7121b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen                    lp.isLockedToGrid) {
713af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                child.getHitRect(frame);
7140be025d64c1f84138fe430a58875886e66aae767Winson Chung
715eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                float scale = child.getScaleX();
716eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                frame = new Rect(child.getLeft(), child.getTop(), child.getRight(),
717eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                        child.getBottom());
7180be025d64c1f84138fe430a58875886e66aae767Winson Chung                // The child hit rect is relative to the CellLayoutChildren parent, so we need to
7190be025d64c1f84138fe430a58875886e66aae767Winson Chung                // offset that by this CellLayout's padding to test an (x,y) point that is relative
7200be025d64c1f84138fe430a58875886e66aae767Winson Chung                // to this view.
7218b805b17158886035b38261eb611d8641701ae43Michael Jurka                frame.offset(getPaddingLeft(), getPaddingTop());
722eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                frame.inset((int) (frame.width() * (1f - scale) / 2),
723eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                        (int) (frame.height() * (1f - scale) / 2));
7240be025d64c1f84138fe430a58875886e66aae767Winson Chung
725af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                if (frame.contains(x, y)) {
726af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                    cellInfo.cell = child;
727af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                    cellInfo.cellX = lp.cellX;
728af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                    cellInfo.cellY = lp.cellY;
729af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                    cellInfo.spanX = lp.cellHSpan;
730af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                    cellInfo.spanY = lp.cellVSpan;
731af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                    found = true;
732af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                    break;
73331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                }
73431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            }
735af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka        }
736aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
737d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka        mLastDownOnOccupiedCell = found;
738d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka
739af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka        if (!found) {
7400be025d64c1f84138fe430a58875886e66aae767Winson Chung            final int cellXY[] = mTmpXY;
741af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka            pointToCellExact(x, y, cellXY);
74231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
743af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka            cellInfo.cell = null;
744af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka            cellInfo.cellX = cellXY[0];
745af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka            cellInfo.cellY = cellXY[1];
746af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka            cellInfo.spanX = 1;
747af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka            cellInfo.spanY = 1;
748af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka        }
749af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka        setTag(cellInfo);
750af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka    }
75131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
752af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka    @Override
753af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka    public boolean onInterceptTouchEvent(MotionEvent ev) {
754c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        // First we clear the tag to ensure that on every touch down we start with a fresh slate,
755c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        // even in the case where we return early. Not clearing here was causing bugs whereby on
756c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        // long-press we'd end up picking up an item from a previous drag operation.
757c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        final int action = ev.getAction();
758c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen
759c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        if (action == MotionEvent.ACTION_DOWN) {
760c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen            clearTagCellInfo();
761c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        }
762c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen
763dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka        if (mInterceptTouchListener != null && mInterceptTouchListener.onTouch(this, ev)) {
764dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka            return true;
765dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka        }
76631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
767af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka        if (action == MotionEvent.ACTION_DOWN) {
768af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka            setTagToCellInfoForPoint((int) ev.getX(), (int) ev.getY());
76931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
770eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung
77131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        return false;
77231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
77331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
774c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen    private void clearTagCellInfo() {
775c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        final CellInfo cellInfo = mCellInfo;
776c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        cellInfo.cell = null;
777c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        cellInfo.cellX = -1;
778c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        cellInfo.cellY = -1;
779c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        cellInfo.spanX = 0;
780c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        cellInfo.spanY = 0;
781c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        setTag(cellInfo);
782c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen    }
783c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen
78431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public CellInfo getTag() {
7850280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        return (CellInfo) super.getTag();
78631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
78731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
7886569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    /**
789aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     * Given a point, return the cell that strictly encloses that point
79031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param x X coordinate of the point
79131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param y Y coordinate of the point
79231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param result Array of 2 ints to hold the x and y coordinate of the cell
79331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
79431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    void pointToCellExact(int x, int y, int[] result) {
7954b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int hStartPadding = getPaddingLeft();
7964b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int vStartPadding = getPaddingTop();
79731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
79831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        result[0] = (x - hStartPadding) / (mCellWidth + mWidthGap);
79931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        result[1] = (y - vStartPadding) / (mCellHeight + mHeightGap);
80031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
801d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        final int xAxis = mCountX;
802d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        final int yAxis = mCountY;
80331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
80431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        if (result[0] < 0) result[0] = 0;
80531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        if (result[0] >= xAxis) result[0] = xAxis - 1;
80631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        if (result[1] < 0) result[1] = 0;
80731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        if (result[1] >= yAxis) result[1] = yAxis - 1;
80831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
809aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
81031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
81131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * Given a point, return the cell that most closely encloses that point
81231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param x X coordinate of the point
81331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param y Y coordinate of the point
81431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param result Array of 2 ints to hold the x and y coordinate of the cell
81531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
81631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    void pointToCellRounded(int x, int y, int[] result) {
81731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        pointToCellExact(x + (mCellWidth / 2), y + (mCellHeight / 2), result);
81831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
81931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
82031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
82131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * Given a cell coordinate, return the point that represents the upper left corner of that cell
822aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     *
823aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     * @param cellX X coordinate of the cell
82431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param cellY Y coordinate of the cell
825aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     *
82631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param result Array of 2 ints to hold the x and y coordinate of the point
82731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
82831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    void cellToPoint(int cellX, int cellY, int[] result) {
8294b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int hStartPadding = getPaddingLeft();
8304b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int vStartPadding = getPaddingTop();
83131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
83231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        result[0] = hStartPadding + cellX * (mCellWidth + mWidthGap);
83331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        result[1] = vStartPadding + cellY * (mCellHeight + mHeightGap);
83431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
83531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
836e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen    /**
837482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * Given a cell coordinate, return the point that represents the center of the cell
838e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen     *
839e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen     * @param cellX X coordinate of the cell
840e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen     * @param cellY Y coordinate of the cell
841e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen     *
842e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen     * @param result Array of 2 ints to hold the x and y coordinate of the point
843e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen     */
844e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen    void cellToCenterPoint(int cellX, int cellY, int[] result) {
84547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        regionToCenterPoint(cellX, cellY, 1, 1, result);
84647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    }
84747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
84847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    /**
84947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * Given a cell coordinate and span return the point that represents the center of the regio
85047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     *
85147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param cellX X coordinate of the cell
85247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param cellY Y coordinate of the cell
85347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     *
85447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param result Array of 2 ints to hold the x and y coordinate of the point
85547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     */
85647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    void regionToCenterPoint(int cellX, int cellY, int spanX, int spanY, int[] result) {
8574b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int hStartPadding = getPaddingLeft();
8584b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int vStartPadding = getPaddingTop();
85947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        result[0] = hStartPadding + cellX * (mCellWidth + mWidthGap) +
86047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                (spanX * mCellWidth + (spanX - 1) * mWidthGap) / 2;
86147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        result[1] = vStartPadding + cellY * (mCellHeight + mHeightGap) +
86247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                (spanY * mCellHeight + (spanY - 1) * mHeightGap) / 2;
863e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen    }
864e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen
86519f3792523fe2d55ea791a9286398a6120920690Adam Cohen     /**
86619f3792523fe2d55ea791a9286398a6120920690Adam Cohen     * Given a cell coordinate and span fills out a corresponding pixel rect
86719f3792523fe2d55ea791a9286398a6120920690Adam Cohen     *
86819f3792523fe2d55ea791a9286398a6120920690Adam Cohen     * @param cellX X coordinate of the cell
86919f3792523fe2d55ea791a9286398a6120920690Adam Cohen     * @param cellY Y coordinate of the cell
87019f3792523fe2d55ea791a9286398a6120920690Adam Cohen     * @param result Rect in which to write the result
87119f3792523fe2d55ea791a9286398a6120920690Adam Cohen     */
87219f3792523fe2d55ea791a9286398a6120920690Adam Cohen     void regionToRect(int cellX, int cellY, int spanX, int spanY, Rect result) {
87319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        final int hStartPadding = getPaddingLeft();
87419f3792523fe2d55ea791a9286398a6120920690Adam Cohen        final int vStartPadding = getPaddingTop();
87519f3792523fe2d55ea791a9286398a6120920690Adam Cohen        final int left = hStartPadding + cellX * (mCellWidth + mWidthGap);
87619f3792523fe2d55ea791a9286398a6120920690Adam Cohen        final int top = vStartPadding + cellY * (mCellHeight + mHeightGap);
87719f3792523fe2d55ea791a9286398a6120920690Adam Cohen        result.set(left, top, left + (spanX * mCellWidth + (spanX - 1) * mWidthGap),
87819f3792523fe2d55ea791a9286398a6120920690Adam Cohen                top + (spanY * mCellHeight + (spanY - 1) * mHeightGap));
87919f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
88019f3792523fe2d55ea791a9286398a6120920690Adam Cohen
881482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public float getDistanceFromCell(float x, float y, int[] cell) {
882482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        cellToCenterPoint(cell[0], cell[1], mTmpPoint);
883482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        float distance = (float) Math.sqrt( Math.pow(x - mTmpPoint[0], 2) +
884482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                Math.pow(y - mTmpPoint[1], 2));
885482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return distance;
886482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
887482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
88884f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy    int getCellWidth() {
88984f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy        return mCellWidth;
89084f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy    }
89184f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy
89284f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy    int getCellHeight() {
89384f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy        return mCellHeight;
89484f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy    }
89584f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy
896d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    int getWidthGap() {
897d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        return mWidthGap;
898d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    }
899d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
900d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    int getHeightGap() {
901d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        return mHeightGap;
902d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    }
903d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
9047f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen    Rect getContentRect(Rect r) {
9057f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        if (r == null) {
9067f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            r = new Rect();
9077f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
9087f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        int left = getPaddingLeft();
9097f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        int top = getPaddingTop();
9108b805b17158886035b38261eb611d8641701ae43Michael Jurka        int right = left + getWidth() - getPaddingLeft() - getPaddingRight();
9118b805b17158886035b38261eb611d8641701ae43Michael Jurka        int bottom = top + getHeight() - getPaddingTop() - getPaddingBottom();
9127f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        r.set(left, top, right, bottom);
9137f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        return r;
9147f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen    }
9157f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
916a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen    static void getMetrics(Rect metrics, Resources res, int measureWidth, int measureHeight,
917a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen            int countX, int countY, int orientation) {
918a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen        int numWidthGaps = countX - 1;
919a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen        int numHeightGaps = countY - 1;
920f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen
921f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        int widthGap;
922f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        int heightGap;
923f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        int cellWidth;
924f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        int cellHeight;
925f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        int paddingLeft;
926f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        int paddingRight;
927f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        int paddingTop;
928f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        int paddingBottom;
929f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen
930a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen        int maxGap = res.getDimensionPixelSize(R.dimen.workspace_max_gap);
931f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        if (orientation == LANDSCAPE) {
932f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            cellWidth = res.getDimensionPixelSize(R.dimen.workspace_cell_width_land);
933f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            cellHeight = res.getDimensionPixelSize(R.dimen.workspace_cell_height_land);
934f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            widthGap = res.getDimensionPixelSize(R.dimen.workspace_width_gap_land);
935f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            heightGap = res.getDimensionPixelSize(R.dimen.workspace_height_gap_land);
936f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            paddingLeft = res.getDimensionPixelSize(R.dimen.cell_layout_left_padding_land);
937f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            paddingRight = res.getDimensionPixelSize(R.dimen.cell_layout_right_padding_land);
938f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            paddingTop = res.getDimensionPixelSize(R.dimen.cell_layout_top_padding_land);
939f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            paddingBottom = res.getDimensionPixelSize(R.dimen.cell_layout_bottom_padding_land);
940f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        } else {
941f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            // PORTRAIT
942f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            cellWidth = res.getDimensionPixelSize(R.dimen.workspace_cell_width_port);
943f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            cellHeight = res.getDimensionPixelSize(R.dimen.workspace_cell_height_port);
944f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            widthGap = res.getDimensionPixelSize(R.dimen.workspace_width_gap_port);
945f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            heightGap = res.getDimensionPixelSize(R.dimen.workspace_height_gap_port);
946f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            paddingLeft = res.getDimensionPixelSize(R.dimen.cell_layout_left_padding_port);
947f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            paddingRight = res.getDimensionPixelSize(R.dimen.cell_layout_right_padding_port);
948f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            paddingTop = res.getDimensionPixelSize(R.dimen.cell_layout_top_padding_port);
949f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            paddingBottom = res.getDimensionPixelSize(R.dimen.cell_layout_bottom_padding_port);
950f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        }
951f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen
952f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        if (widthGap < 0 || heightGap < 0) {
953f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            int hSpace = measureWidth - paddingLeft - paddingRight;
954f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            int vSpace = measureHeight - paddingTop - paddingBottom;
955a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen            int hFreeSpace = hSpace - (countX * cellWidth);
956a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen            int vFreeSpace = vSpace - (countY * cellHeight);
957a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen            widthGap = Math.min(maxGap, numWidthGaps > 0 ? (hFreeSpace / numWidthGaps) : 0);
958a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen            heightGap = Math.min(maxGap, numHeightGaps > 0 ? (vFreeSpace / numHeightGaps) : 0);
959f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        }
960f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        metrics.set(cellWidth, cellHeight, widthGap, heightGap);
961f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen    }
962f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen
96331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
96431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
96531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
966aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
967aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
96831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
96931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int heightSpecSize =  MeasureSpec.getSize(heightMeasureSpec);
970aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
97131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        if (widthSpecMode == MeasureSpec.UNSPECIFIED || heightSpecMode == MeasureSpec.UNSPECIFIED) {
97231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            throw new RuntimeException("CellLayout cannot have UNSPECIFIED dimensions");
97331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
97431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
975d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        int numWidthGaps = mCountX - 1;
976d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        int numHeightGaps = mCountY - 1;
977d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen
978234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen        if (mOriginalWidthGap < 0 || mOriginalHeightGap < 0) {
979dd13e3d0f9925b7bb80c37e21d039aab4fa7e7a1Michael Jurka            int hSpace = widthSpecSize - getPaddingLeft() - getPaddingRight();
980dd13e3d0f9925b7bb80c37e21d039aab4fa7e7a1Michael Jurka            int vSpace = heightSpecSize - getPaddingTop() - getPaddingBottom();
981f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            int hFreeSpace = hSpace - (mCountX * mCellWidth);
982f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            int vFreeSpace = vSpace - (mCountY * mCellHeight);
9834b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung            mWidthGap = Math.min(mMaxGap, numWidthGaps > 0 ? (hFreeSpace / numWidthGaps) : 0);
9844b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung            mHeightGap = Math.min(mMaxGap,numHeightGaps > 0 ? (vFreeSpace / numHeightGaps) : 0);
985a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            mShortcutsAndWidgets.setCellDimensions(mCellWidth, mCellHeight, mWidthGap, mHeightGap);
986234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen        } else {
987234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen            mWidthGap = mOriginalWidthGap;
988234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen            mHeightGap = mOriginalHeightGap;
989ece7f5b3b55cab646941123e03589241a61678e2Winson Chung        }
9905f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka
9918c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka        // Initial values correspond to widthSpecMode == MeasureSpec.EXACTLY
9928c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka        int newWidth = widthSpecSize;
9938c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka        int newHeight = heightSpecSize;
9948c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka        if (widthSpecMode == MeasureSpec.AT_MOST) {
9958b805b17158886035b38261eb611d8641701ae43Michael Jurka            newWidth = getPaddingLeft() + getPaddingRight() + (mCountX * mCellWidth) +
9968c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka                ((mCountX - 1) * mWidthGap);
9978b805b17158886035b38261eb611d8641701ae43Michael Jurka            newHeight = getPaddingTop() + getPaddingBottom() + (mCountY * mCellHeight) +
9988c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka                ((mCountY - 1) * mHeightGap);
9998c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka            setMeasuredDimension(newWidth, newHeight);
10008c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka        }
100131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
10028c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka        int count = getChildCount();
100331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        for (int i = 0; i < count; i++) {
100431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            View child = getChildAt(i);
10058b805b17158886035b38261eb611d8641701ae43Michael Jurka            int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(newWidth - getPaddingLeft() -
10068b805b17158886035b38261eb611d8641701ae43Michael Jurka                    getPaddingRight(), MeasureSpec.EXACTLY);
10078b805b17158886035b38261eb611d8641701ae43Michael Jurka            int childheightMeasureSpec = MeasureSpec.makeMeasureSpec(newHeight - getPaddingTop() -
10088b805b17158886035b38261eb611d8641701ae43Michael Jurka                    getPaddingBottom(), MeasureSpec.EXACTLY);
100931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            child.measure(childWidthMeasureSpec, childheightMeasureSpec);
101031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
10118c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka        setMeasuredDimension(newWidth, newHeight);
101231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
101331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
101431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
101528750fba6a2d141eb9a1e566718c17236030b815Michael Jurka    protected void onLayout(boolean changed, int l, int t, int r, int b) {
101631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int count = getChildCount();
101731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        for (int i = 0; i < count; i++) {
10188c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka            View child = getChildAt(i);
10198b805b17158886035b38261eb611d8641701ae43Michael Jurka            child.layout(getPaddingLeft(), getPaddingTop(),
10208b805b17158886035b38261eb611d8641701ae43Michael Jurka                    r - l - getPaddingRight(), b - t - getPaddingBottom());
102131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
102231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
102331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
102431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
1025dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
1026dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka        super.onSizeChanged(w, h, oldw, oldh);
102718014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka        mBackgroundRect.set(0, 0, w, h);
1028b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        mForegroundRect.set(mForegroundPadding, mForegroundPadding,
1029215b416c1f7cf0234b777155b823637a0902739fAdam Cohen                w - mForegroundPadding, h - mForegroundPadding);
1030dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    }
1031dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka
1032dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    @Override
103331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    protected void setChildrenDrawingCacheEnabled(boolean enabled) {
1034a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.setChildrenDrawingCacheEnabled(enabled);
103531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
103631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
103731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
103831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    protected void setChildrenDrawnWithCacheEnabled(boolean enabled) {
1039a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.setChildrenDrawnWithCacheEnabled(enabled);
104031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
104131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
10425f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka    public float getBackgroundAlpha() {
10435f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka        return mBackgroundAlpha;
1044dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    }
1045dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka
10461b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen    public void setBackgroundAlphaMultiplier(float multiplier) {
1047a3d30adbfd4f013260f1f5ba3a56bc9bb4a11717Michael Jurka        if (mBackgroundAlphaMultiplier != multiplier) {
1048a3d30adbfd4f013260f1f5ba3a56bc9bb4a11717Michael Jurka            mBackgroundAlphaMultiplier = multiplier;
1049a3d30adbfd4f013260f1f5ba3a56bc9bb4a11717Michael Jurka            invalidate();
1050a3d30adbfd4f013260f1f5ba3a56bc9bb4a11717Michael Jurka        }
10511b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen    }
10521b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen
1053ddb821981e0919bbd3b4c9a2b6aa1811d6c86bb6Adam Cohen    public float getBackgroundAlphaMultiplier() {
1054ddb821981e0919bbd3b4c9a2b6aa1811d6c86bb6Adam Cohen        return mBackgroundAlphaMultiplier;
1055ddb821981e0919bbd3b4c9a2b6aa1811d6c86bb6Adam Cohen    }
1056ddb821981e0919bbd3b4c9a2b6aa1811d6c86bb6Adam Cohen
10575f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka    public void setBackgroundAlpha(float alpha) {
1058afaa05014e0bf3ed1192f9ddec2af4283bc50248Michael Jurka        if (mBackgroundAlpha != alpha) {
1059afaa05014e0bf3ed1192f9ddec2af4283bc50248Michael Jurka            mBackgroundAlpha = alpha;
1060afaa05014e0bf3ed1192f9ddec2af4283bc50248Michael Jurka            invalidate();
1061afaa05014e0bf3ed1192f9ddec2af4283bc50248Michael Jurka        }
1062dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    }
1063dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka
1064a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka    public void setShortcutAndWidgetAlpha(float alpha) {
10650142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka        final int childCount = getChildCount();
10660142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka        for (int i = 0; i < childCount; i++) {
1067dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka            getChildAt(i).setAlpha(alpha);
1068dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka        }
1069dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    }
1070dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka
1071a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka    public ShortcutAndWidgetContainer getShortcutsAndWidgets() {
1072a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        if (getChildCount() > 0) {
1073a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            return (ShortcutAndWidgetContainer) getChildAt(0);
1074a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        }
1075a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        return null;
1076a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka    }
1077a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka
1078440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy    public View getChildAt(int x, int y) {
1079a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        return mShortcutsAndWidgets.getChildAt(x, y);
1080440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy    }
1081440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy
108276fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    public boolean animateChildToPosition(final View child, int cellX, int cellY, int duration,
1083482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            int delay, boolean permanent, boolean adjustOccupied) {
1084a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        ShortcutAndWidgetContainer clc = getShortcutsAndWidgets();
1085482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        boolean[][] occupied = mOccupied;
1086482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (!permanent) {
1087482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            occupied = mTmpOccupied;
1088482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1089482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
109019f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if (clc.indexOfChild(child) != -1) {
1091bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
1092bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            final ItemInfo info = (ItemInfo) child.getTag();
1093bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen
1094bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            // We cancel any existing animations
1095bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            if (mReorderAnimators.containsKey(lp)) {
1096bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                mReorderAnimators.get(lp).cancel();
1097bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                mReorderAnimators.remove(lp);
1098bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            }
1099bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen
1100482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            final int oldX = lp.x;
1101482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            final int oldY = lp.y;
1102482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (adjustOccupied) {
1103482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                occupied[lp.cellX][lp.cellY] = false;
1104482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                occupied[cellX][cellY] = true;
1105482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1106bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            lp.isLockedToGrid = true;
1107482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (permanent) {
1108482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                lp.cellX = info.cellX = cellX;
1109482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                lp.cellY = info.cellY = cellY;
1110482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            } else {
1111482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                lp.tmpCellX = cellX;
1112482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                lp.tmpCellY = cellY;
1113482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1114bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            clc.setupLp(lp);
1115bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            lp.isLockedToGrid = false;
1116482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            final int newX = lp.x;
1117482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            final int newY = lp.y;
1118bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen
111976fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen            lp.x = oldX;
112076fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen            lp.y = oldY;
112176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
1122482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            // Exit early if we're not actually moving the view
1123482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (oldX == newX && oldY == newY) {
1124482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                lp.isLockedToGrid = true;
1125482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                return true;
1126482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1127482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
11282ecf995e0d2d55eb71d03f7230ca87270872d1a3Michael Jurka            ValueAnimator va = LauncherAnimUtils.ofFloat(0f, 1f);
1129482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            va.setDuration(duration);
1130482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            mReorderAnimators.put(lp, va);
1131482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1132482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            va.addUpdateListener(new AnimatorUpdateListener() {
1133482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                @Override
1134bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                public void onAnimationUpdate(ValueAnimator animation) {
1135482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    float r = ((Float) animation.getAnimatedValue()).floatValue();
113619f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    lp.x = (int) ((1 - r) * oldX + r * newX);
113719f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    lp.y = (int) ((1 - r) * oldY + r * newY);
11386b8a02d63a5d9cab8209381993e37db6a6afb753Adam Cohen                    child.requestLayout();
1139bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                }
1140bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            });
1141482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            va.addListener(new AnimatorListenerAdapter() {
1142bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                boolean cancelled = false;
1143bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                public void onAnimationEnd(Animator animation) {
1144bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    // If the animation was cancelled, it means that another animation
1145bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    // has interrupted this one, and we don't want to lock the item into
1146bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    // place just yet.
1147bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    if (!cancelled) {
1148bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                        lp.isLockedToGrid = true;
1149482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        child.requestLayout();
1150bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    }
1151bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    if (mReorderAnimators.containsKey(lp)) {
1152bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                        mReorderAnimators.remove(lp);
1153bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    }
1154bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                }
1155bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                public void onAnimationCancel(Animator animation) {
1156bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    cancelled = true;
1157bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                }
1158bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            });
1159482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            va.setStartDelay(delay);
1160482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            va.start();
1161bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            return true;
1162bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        }
1163bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        return false;
1164bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    }
1165bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen
11666569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    /**
11676569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     * Estimate where the top left cell of the dragged item will land if it is dropped.
11686569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     *
11696569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     * @param originX The X value of the top left corner of the item
11706569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     * @param originY The Y value of the top left corner of the item
11716569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     * @param spanX The number of horizontal cells that the item spans
11726569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     * @param spanY The number of vertical cells that the item spans
11736569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     * @param result The estimated drop cell X and Y.
11746569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     */
11756569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    void estimateDropCell(int originX, int originY, int spanX, int spanY, int[] result) {
1176d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        final int countX = mCountX;
1177d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        final int countY = mCountY;
11786569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
1179a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka        // pointToCellRounded takes the top left of a cell but will pad that with
1180a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka        // cellWidth/2 and cellHeight/2 when finding the matching cell
1181a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka        pointToCellRounded(originX, originY, result);
11826569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
11836569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        // If the item isn't fully on this screen, snap to the edges
11846569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        int rightOverhang = result[0] + spanX - countX;
11856569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        if (rightOverhang > 0) {
11866569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy            result[0] -= rightOverhang; // Snap to right
11876569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        }
11886569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        result[0] = Math.max(0, result[0]); // Snap to left
11896569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        int bottomOverhang = result[1] + spanY - countY;
11906569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        if (bottomOverhang > 0) {
11916569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy            result[1] -= bottomOverhang; // Snap to bottom
11926569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        }
11936569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        result[1] = Math.max(0, result[1]); // Snap to top
11946569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    }
11956569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
1196482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    void visualizeDropLocation(View v, Bitmap dragOutline, int originX, int originY, int cellX,
1197482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            int cellY, int spanX, int spanY, boolean resize, Point dragOffset, Rect dragRegion) {
119808ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy        final int oldDragCellX = mDragCell[0];
119908ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy        final int oldDragCellY = mDragCell[1];
1200482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1201b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung        if (v != null && dragOffset == null) {
1202a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung            mDragCenter.set(originX + (v.getWidth() / 2), originY + (v.getHeight() / 2));
1203a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung        } else {
1204a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung            mDragCenter.set(originX, originY);
1205a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung        }
12066569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
12072801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        if (dragOutline == null && v == null) {
12082801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            return;
12092801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        }
12102801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
1211482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (cellX != oldDragCellX || cellY != oldDragCellY) {
1212482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            mDragCell[0] = cellX;
1213482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            mDragCell[1] = cellY;
12146569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy            // Find the top left corner of the rect the object will occupy
1215de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy            final int[] topLeft = mTmpPoint;
1216482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            cellToPoint(cellX, cellY, topLeft);
1217de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy
12184be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            int left = topLeft[0];
12194be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            int top = topLeft[1];
12206569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
1221b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung            if (v != null && dragOffset == null) {
122299e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                // When drawing the drag outline, it did not account for margin offsets
122399e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                // added by the view's parent.
122499e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                MarginLayoutParams lp = (MarginLayoutParams) v.getLayoutParams();
122599e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                left += lp.leftMargin;
122699e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                top += lp.topMargin;
122799e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen
122899e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                // Offsets due to the size difference between the View and the dragOutline.
122999e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                // There is a size difference to account for the outer blur, which may lie
123099e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                // outside the bounds of the view.
1231a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung                top += (v.getHeight() - dragOutline.getHeight()) / 2;
1232ae915cecd36af4973061a1cb0b58c5be1be699a0Adam Cohen                // We center about the x axis
1233ae915cecd36af4973061a1cb0b58c5be1be699a0Adam Cohen                left += ((mCellWidth * spanX) + ((spanX - 1) * mWidthGap)
1234ae915cecd36af4973061a1cb0b58c5be1be699a0Adam Cohen                        - dragOutline.getWidth()) / 2;
12356639687cd67bab1aeef2a75e5c6bc458b20dc082Adam Cohen            } else {
1236b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                if (dragOffset != null && dragRegion != null) {
1237b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                    // Center the drag region *horizontally* in the cell and apply a drag
1238b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                    // outline offset
1239b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                    left += dragOffset.x + ((mCellWidth * spanX) + ((spanX - 1) * mWidthGap)
1240b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                             - dragRegion.width()) / 2;
1241b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                    top += dragOffset.y;
1242b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                } else {
1243b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                    // Center the drag outline in the cell
1244b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                    left += ((mCellWidth * spanX) + ((spanX - 1) * mWidthGap)
1245b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                            - dragOutline.getWidth()) / 2;
1246b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                    top += ((mCellHeight * spanY) + ((spanY - 1) * mHeightGap)
1247b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                            - dragOutline.getHeight()) / 2;
1248b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                }
1249a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung            }
12504be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            final int oldIndex = mDragOutlineCurrent;
125108ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy            mDragOutlineAnims[oldIndex].animateOut();
125208ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy            mDragOutlineCurrent = (oldIndex + 1) % mDragOutlines.length;
1253d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            Rect r = mDragOutlines[mDragOutlineCurrent];
1254d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            r.set(left, top, left + dragOutline.getWidth(), top + dragOutline.getHeight());
1255d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            if (resize) {
1256482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                cellToRect(cellX, cellY, spanX, spanY, r);
1257d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            }
1258150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung
125908ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy            mDragOutlineAnims[mDragOutlineCurrent].setTag(dragOutline);
126008ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy            mDragOutlineAnims[mDragOutlineCurrent].animateIn();
12616569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        }
12626569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    }
12636569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
1264e0310965022e7a1adb7ad489505d404186608689Adam Cohen    public void clearDragOutlines() {
1265e0310965022e7a1adb7ad489505d404186608689Adam Cohen        final int oldIndex = mDragOutlineCurrent;
1266e0310965022e7a1adb7ad489505d404186608689Adam Cohen        mDragOutlineAnims[oldIndex].animateOut();
1267d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        mDragCell[0] = mDragCell[1] = -1;
1268e0310965022e7a1adb7ad489505d404186608689Adam Cohen    }
1269e0310965022e7a1adb7ad489505d404186608689Adam Cohen
127031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
127170864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey     * Find a vacant area that will fit the given bounds nearest the requested
127270864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey     * cell location. Uses Euclidean distance to score multiple vacant areas.
1273aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     *
127451afc022fa76c79f0d1ece470ddc126c08fea8a4Romain Guy     * @param pixelX The X location at which you want to search for a vacant area.
127551afc022fa76c79f0d1ece470ddc126c08fea8a4Romain Guy     * @param pixelY The Y location at which you want to search for a vacant area.
127670864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey     * @param spanX Horizontal span of the object.
127770864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey     * @param spanY Vertical span of the object.
1278de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy     * @param result Array in which to place the result, or null (in which case a new array will
1279de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy     *        be allocated)
128070864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey     * @return The X, Y cell of a vacant area that can contain this object,
128170864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey     *         nearest the requested location.
128231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
1283d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    int[] findNearestVacantArea(int pixelX, int pixelY, int spanX, int spanY,
1284d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            int[] result) {
1285de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy        return findNearestVacantArea(pixelX, pixelY, spanX, spanY, null, result);
12866a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka    }
1287aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
12886a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka    /**
12896a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     * Find a vacant area that will fit the given bounds nearest the requested
12906a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     * cell location. Uses Euclidean distance to score multiple vacant areas.
12916a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     *
12926a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     * @param pixelX The X location at which you want to search for a vacant area.
12936a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     * @param pixelY The Y location at which you want to search for a vacant area.
1294d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param minSpanX The minimum horizontal span required
1295d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param minSpanY The minimum vertical span required
1296d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param spanX Horizontal span of the object.
1297d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param spanY Vertical span of the object.
1298d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param result Array in which to place the result, or null (in which case a new array will
1299d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *        be allocated)
1300d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @return The X, Y cell of a vacant area that can contain this object,
1301d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *         nearest the requested location.
1302d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     */
1303d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    int[] findNearestVacantArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX,
1304d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            int spanY, int[] result, int[] resultSpan) {
1305d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        return findNearestVacantArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, null,
1306d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                result, resultSpan);
1307d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    }
1308d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen
1309d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    /**
1310d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * Find a vacant area that will fit the given bounds nearest the requested
1311d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * cell location. Uses Euclidean distance to score multiple vacant areas.
1312d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *
1313d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param pixelX The X location at which you want to search for a vacant area.
1314d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param pixelY The Y location at which you want to search for a vacant area.
13156a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     * @param spanX Horizontal span of the object.
13166a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     * @param spanY Vertical span of the object.
1317df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param ignoreOccupied If true, the result can be an occupied cell
1318df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param result Array in which to place the result, or null (in which case a new array will
1319df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     *        be allocated)
13206a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     * @return The X, Y cell of a vacant area that can contain this object,
13216a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     *         nearest the requested location.
13226a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     */
1323df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    int[] findNearestArea(int pixelX, int pixelY, int spanX, int spanY, View ignoreView,
1324df0353815c629fc678824b07a234b89a1ff94208Adam Cohen            boolean ignoreOccupied, int[] result) {
1325d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        return findNearestArea(pixelX, pixelY, spanX, spanY,
1326482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                spanX, spanY, ignoreView, ignoreOccupied, result, null, mOccupied);
1327d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    }
1328d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen
1329d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    private final Stack<Rect> mTempRectStack = new Stack<Rect>();
1330d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    private void lazyInitTempRectStack() {
1331d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        if (mTempRectStack.isEmpty()) {
1332d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            for (int i = 0; i < mCountX * mCountY; i++) {
1333d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                mTempRectStack.push(new Rect());
1334d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            }
1335d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        }
1336d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    }
1337482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1338d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    private void recycleTempRects(Stack<Rect> used) {
1339d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        while (!used.isEmpty()) {
1340d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            mTempRectStack.push(used.pop());
1341d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        }
1342d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    }
1343d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen
1344d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    /**
1345d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * Find a vacant area that will fit the given bounds nearest the requested
1346d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * cell location. Uses Euclidean distance to score multiple vacant areas.
1347d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *
1348d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param pixelX The X location at which you want to search for a vacant area.
1349d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param pixelY The Y location at which you want to search for a vacant area.
1350d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param minSpanX The minimum horizontal span required
1351d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param minSpanY The minimum vertical span required
1352d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param spanX Horizontal span of the object.
1353d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param spanY Vertical span of the object.
1354d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param ignoreOccupied If true, the result can be an occupied cell
1355d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param result Array in which to place the result, or null (in which case a new array will
1356d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *        be allocated)
1357d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @return The X, Y cell of a vacant area that can contain this object,
1358d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *         nearest the requested location.
1359d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     */
1360d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    int[] findNearestArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, int spanY,
1361482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            View ignoreView, boolean ignoreOccupied, int[] result, int[] resultSpan,
1362482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            boolean[][] occupied) {
1363d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        lazyInitTempRectStack();
1364c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka        // mark space take by ignoreView as available (method checks if ignoreView is null)
1365482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsAsUnoccupiedForView(ignoreView, occupied);
1366c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka
1367e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        // For items with a spanX / spanY > 1, the passed in point (pixelX, pixelY) corresponds
1368e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        // to the center of the item, but we are searching based on the top-left cell, so
1369e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        // we translate the point over to correspond to the top-left.
1370e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        pixelX -= (mCellWidth + mWidthGap) * (spanX - 1) / 2f;
1371e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        pixelY -= (mCellHeight + mHeightGap) * (spanY - 1) / 2f;
1372e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen
137370864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey        // Keep track of best-scoring drop area
1374de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy        final int[] bestXY = result != null ? result : new int[2];
137570864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey        double bestDistance = Double.MAX_VALUE;
1376d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        final Rect bestRect = new Rect(-1, -1, -1, -1);
1377d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        final Stack<Rect> validRegions = new Stack<Rect>();
1378aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
1379de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy        final int countX = mCountX;
1380de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy        final int countY = mCountY;
1381de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy
1382d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        if (minSpanX <= 0 || minSpanY <= 0 || spanX <= 0 || spanY <= 0 ||
1383d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                spanX < minSpanX || spanY < minSpanY) {
1384d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            return bestXY;
1385d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        }
1386d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen
1387d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        for (int y = 0; y < countY - (minSpanY - 1); y++) {
1388c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka            inner:
1389d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            for (int x = 0; x < countX - (minSpanX - 1); x++) {
1390d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                int ySize = -1;
1391d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                int xSize = -1;
1392df0353815c629fc678824b07a234b89a1ff94208Adam Cohen                if (ignoreOccupied) {
1393d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    // First, let's see if this thing fits anywhere
1394d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    for (int i = 0; i < minSpanX; i++) {
1395d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        for (int j = 0; j < minSpanY; j++) {
1396df0353815c629fc678824b07a234b89a1ff94208Adam Cohen                            if (occupied[x + i][y + j]) {
1397df0353815c629fc678824b07a234b89a1ff94208Adam Cohen                                continue inner;
1398df0353815c629fc678824b07a234b89a1ff94208Adam Cohen                            }
1399c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                        }
1400c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                    }
1401d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    xSize = minSpanX;
1402d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    ySize = minSpanY;
1403d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen
1404d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    // We know that the item will fit at _some_ acceptable size, now let's see
1405d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    // how big we can make it. We'll alternate between incrementing x and y spans
1406d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    // until we hit a limit.
1407d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    boolean incX = true;
1408d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    boolean hitMaxX = xSize >= spanX;
1409d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    boolean hitMaxY = ySize >= spanY;
1410d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    while (!(hitMaxX && hitMaxY)) {
1411d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        if (incX && !hitMaxX) {
1412d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            for (int j = 0; j < ySize; j++) {
1413d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                if (x + xSize > countX -1 || occupied[x + xSize][y + j]) {
1414d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                    // We can't move out horizontally
1415d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                    hitMaxX = true;
1416d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                }
1417d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            }
1418d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            if (!hitMaxX) {
1419d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                xSize++;
1420d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            }
1421d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        } else if (!hitMaxY) {
1422d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            for (int i = 0; i < xSize; i++) {
1423d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                if (y + ySize > countY - 1 || occupied[x + i][y + ySize]) {
1424d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                    // We can't move out vertically
1425d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                    hitMaxY = true;
1426d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                }
1427d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            }
1428d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            if (!hitMaxY) {
1429d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                ySize++;
1430d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            }
1431d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        }
1432d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        hitMaxX |= xSize >= spanX;
1433d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        hitMaxY |= ySize >= spanY;
1434d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        incX = !incX;
1435d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    }
1436d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    incX = true;
1437d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    hitMaxX = xSize >= spanX;
1438d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    hitMaxY = ySize >= spanY;
1439c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                }
14400be025d64c1f84138fe430a58875886e66aae767Winson Chung                final int[] cellXY = mTmpXY;
1441e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen                cellToCenterPoint(x, y, cellXY);
1442c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka
1443d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                // We verify that the current rect is not a sub-rect of any of our previous
1444d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                // candidates. In this case, the current rect is disqualified in favour of the
1445d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                // containing rect.
1446d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                Rect currentRect = mTempRectStack.pop();
1447d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                currentRect.set(x, y, x + xSize, y + ySize);
1448d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                boolean contained = false;
1449d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                for (Rect r : validRegions) {
1450d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    if (r.contains(currentRect)) {
1451d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        contained = true;
1452d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        break;
1453d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    }
1454d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                }
1455d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                validRegions.push(currentRect);
1456c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                double distance = Math.sqrt(Math.pow(cellXY[0] - pixelX, 2)
1457c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                        + Math.pow(cellXY[1] - pixelY, 2));
1458482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1459d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                if ((distance <= bestDistance && !contained) ||
1460d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        currentRect.contains(bestRect)) {
1461c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                    bestDistance = distance;
1462c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                    bestXY[0] = x;
1463c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                    bestXY[1] = y;
1464d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    if (resultSpan != null) {
1465d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        resultSpan[0] = xSize;
1466d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        resultSpan[1] = ySize;
1467d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    }
1468d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    bestRect.set(currentRect);
1469c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                }
147031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            }
147131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
1472c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka        // re-mark space taken by ignoreView as occupied
1473482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsAsOccupiedForView(ignoreView, occupied);
147431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
1475c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        // Return -1, -1 if no suitable location found
1476c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        if (bestDistance == Double.MAX_VALUE) {
1477c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            bestXY[0] = -1;
1478c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            bestXY[1] = -1;
147970864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey        }
1480d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        recycleTempRects(validRegions);
1481c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        return bestXY;
148231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
1483aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
1484482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     /**
1485482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * Find a vacant area that will fit the given bounds nearest the requested
1486482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * cell location, and will also weigh in a suggested direction vector of the
1487482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * desired location. This method computers distance based on unit grid distances,
1488482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * not pixel distances.
1489482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     *
149047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param cellX The X cell nearest to which you want to search for a vacant area.
149147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param cellY The Y cell nearest which you want to search for a vacant area.
1492482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * @param spanX Horizontal span of the object.
1493482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * @param spanY Vertical span of the object.
149447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param direction The favored direction in which the views should move from x, y
149547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param exactDirectionOnly If this parameter is true, then only solutions where the direction
149647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     *        matches exactly. Otherwise we find the best matching direction.
149747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param occoupied The array which represents which cells in the CellLayout are occupied
149847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param blockOccupied The array which represents which cells in the specified block (cellX,
149947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     *        cellY, spanX, spanY) are occupied. This is used when try to move a group of views.
1500482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * @param result Array in which to place the result, or null (in which case a new array will
1501482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     *        be allocated)
1502482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * @return The X, Y cell of a vacant area that can contain this object,
1503482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     *         nearest the requested location.
1504482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     */
1505482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private int[] findNearestArea(int cellX, int cellY, int spanX, int spanY, int[] direction,
150647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            boolean[][] occupied, boolean blockOccupied[][], int[] result) {
1507482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // Keep track of best-scoring drop area
1508482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        final int[] bestXY = result != null ? result : new int[2];
1509482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        float bestDistance = Float.MAX_VALUE;
1510482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        int bestDirectionScore = Integer.MIN_VALUE;
1511482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1512482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        final int countX = mCountX;
1513482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        final int countY = mCountY;
1514482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1515482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int y = 0; y < countY - (spanY - 1); y++) {
1516482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            inner:
1517482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            for (int x = 0; x < countX - (spanX - 1); x++) {
1518482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                // First, let's see if this thing fits anywhere
1519482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                for (int i = 0; i < spanX; i++) {
1520482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    for (int j = 0; j < spanY; j++) {
152147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        if (occupied[x + i][y + j] && (blockOccupied == null || blockOccupied[i][j])) {
1522482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                            continue inner;
1523482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        }
1524482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    }
1525482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                }
1526482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1527482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                float distance = (float)
1528482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        Math.sqrt((x - cellX) * (x - cellX) + (y - cellY) * (y - cellY));
1529482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                int[] curDirection = mTmpPoint;
153047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                computeDirectionVector(x - cellX, y - cellY, curDirection);
153147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                // The direction score is just the dot product of the two candidate direction
153247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                // and that passed in.
1533482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                int curDirectionScore = direction[0] * curDirection[0] +
1534482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        direction[1] * curDirection[1];
153547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                boolean exactDirectionOnly = false;
153647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                boolean directionMatches = direction[0] == curDirection[0] &&
153747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        direction[0] == curDirection[0];
153847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                if ((directionMatches || !exactDirectionOnly) &&
153947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        Float.compare(distance,  bestDistance) < 0 || (Float.compare(distance,
1540482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        bestDistance) == 0 && curDirectionScore > bestDirectionScore)) {
1541482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    bestDistance = distance;
1542482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    bestDirectionScore = curDirectionScore;
1543482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    bestXY[0] = x;
1544482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    bestXY[1] = y;
1545482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                }
1546482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1547482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1548482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1549482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // Return -1, -1 if no suitable location found
1550482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (bestDistance == Float.MAX_VALUE) {
1551482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            bestXY[0] = -1;
1552482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            bestXY[1] = -1;
1553482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1554482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return bestXY;
1555482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1556482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
155747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    private int[] findNearestAreaInDirection(int cellX, int cellY, int spanX, int spanY,
155847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            int[] direction,boolean[][] occupied,
155947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            boolean blockOccupied[][], int[] result) {
156047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        // Keep track of best-scoring drop area
156147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        final int[] bestXY = result != null ? result : new int[2];
156247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        bestXY[0] = -1;
156347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        bestXY[1] = -1;
156447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        float bestDistance = Float.MAX_VALUE;
156547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
156647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        // We use this to march in a single direction
15675b53f29f809a0dad4a1e0717ba610ce737ee0f43Adam Cohen        if ((direction[0] != 0 && direction[1] != 0) ||
15685b53f29f809a0dad4a1e0717ba610ce737ee0f43Adam Cohen                (direction[0] == 0 && direction[1] == 0)) {
156947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            return bestXY;
157047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
157147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
157247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        // This will only incrememnet one of x or y based on the assertion above
157347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        int x = cellX + direction[0];
157447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        int y = cellY + direction[1];
157547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        while (x >= 0 && x + spanX <= mCountX && y >= 0 && y + spanY <= mCountY) {
157647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            boolean fail = false;
157747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            for (int i = 0; i < spanX; i++) {
157847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                for (int j = 0; j < spanY; j++) {
157947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    if (occupied[x + i][y + j] && (blockOccupied == null || blockOccupied[i][j])) {
158047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        fail = true;
158147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    }
158247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                }
158347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            }
158447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            if (!fail) {
158547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                float distance = (float)
158647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        Math.sqrt((x - cellX) * (x - cellX) + (y - cellY) * (y - cellY));
158747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                if (Float.compare(distance,  bestDistance) < 0) {
158847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    bestDistance = distance;
158947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    bestXY[0] = x;
159047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    bestXY[1] = y;
159147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                }
159247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            }
159347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            x += direction[0];
159447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            y += direction[1];
159547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
159647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        return bestXY;
159747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    }
159847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
1599482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private boolean addViewToTempLocation(View v, Rect rectOccupiedByPotentialDrop,
16008baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            int[] direction, ItemConfiguration currentState) {
16018baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        CellAndSpan c = currentState.map.get(v);
1602482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        boolean success = false;
16038baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, false);
1604482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsForRect(rectOccupiedByPotentialDrop, mTmpOccupied, true);
1605482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
16068baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        findNearestArea(c.x, c.y, c.spanX, c.spanY, direction, mTmpOccupied, null, mTempLocation);
1607482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1608482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (mTempLocation[0] >= 0 && mTempLocation[1] >= 0) {
16098baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            c.x = mTempLocation[0];
16108baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            c.y = mTempLocation[1];
1611482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            success = true;
1612482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1613482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
16148baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, true);
1615482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return success;
1616482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1617482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1618a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen    // This method looks in the specified direction to see if there are additional views adjacent
1619e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen    // to the current set of views. If there are, then these views are added to the current
1620a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen    // set of views. This is performed iteratively, giving a cascading push behaviour.
162147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    private boolean addViewInDirection(ArrayList<View> views, Rect boundingRect, int[] direction,
162219f3792523fe2d55ea791a9286398a6120920690Adam Cohen            boolean[][] occupied, View dragView, ItemConfiguration currentState) {
162347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        boolean found = false;
162447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
1625a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        int childCount = mShortcutsAndWidgets.getChildCount();
162647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        Rect r0 = new Rect(boundingRect);
162747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        Rect r1 = new Rect();
162847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
1629a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen        // First, we consider the rect of the views that we are trying to translate
163047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        int deltaX = 0;
163147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        int deltaY = 0;
163247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        if (direction[1] < 0) {
1633a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen            r0.set(r0.left, r0.top - 1, r0.right, r0.bottom - 1);
163447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            deltaY = -1;
163547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        } else if (direction[1] > 0) {
1636a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen            r0.set(r0.left, r0.top + 1, r0.right, r0.bottom + 1);
163747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            deltaY = 1;
163847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        } else if (direction[0] < 0) {
1639a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen            r0.set(r0.left - 1, r0.top, r0.right - 1, r0.bottom);
164047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            deltaX = -1;
164147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        } else if (direction[0] > 0) {
1642a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen            r0.set(r0.left + 1, r0.top, r0.right + 1, r0.bottom);
164347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            deltaX = 1;
164447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
164547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
1646a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen        // Now we see which views, if any, are being overlapped by shifting the current group
1647a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen        // of views in the desired direction.
164847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        for (int i = 0; i < childCount; i++) {
1649a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen            // We don't need to worry about views already in our group, or the current drag view.
1650a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            View child = mShortcutsAndWidgets.getChildAt(i);
165119f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (views.contains(child) || child == dragView) continue;
16528baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = currentState.map.get(child);
165347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
16548baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
16558baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            r1.set(c.x, c.y, c.x + c.spanX, c.y + c.spanY);
165647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            if (Rect.intersects(r0, r1)) {
165747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                if (!lp.canReorder) {
165847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    return false;
165947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                }
1660a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen                // First we verify that the view in question is at the border of the extents
1661a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen                // of the block of items we are pushing
1662a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen                if ((direction[0] < 0 && c.x == r0.left) ||
1663a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen                        (direction[0] > 0 && c.x == r0.right - 1) ||
1664a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen                        (direction[1] < 0 && c.y == r0.top) ||
1665a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen                        (direction[1] > 0 && c.y == r0.bottom - 1)) {
1666a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen                    boolean pushed = false;
1667e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen                    // Since the bounding rect is a coarse description of the region (there can
1668a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen                    // be holes at the edge of the block), we need to check to verify that a solid
1669a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen                    // piece is intersecting. This ensures that interlocking is possible.
1670a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen                    for (int x = c.x; x < c.x + c.spanX; x++) {
1671a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen                        for (int y = c.y; y < c.y + c.spanY; y++) {
1672a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen                            if (occupied[x - deltaX][y - deltaY]) {
1673a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen                                pushed = true;
1674a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen                                break;
1675a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen                            }
1676a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen                            if (pushed) break;
167747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        }
167847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    }
1679a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen                    if (pushed) {
1680a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen                        views.add(child);
1681a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen                        boundingRect.union(c.x, c.y, c.x + c.spanX, c.y + c.spanY);
1682a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen                        found = true;
1683a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen                    }
168447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                }
168547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            }
168647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
168747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        return found;
168847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    }
168947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
1690e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen    private void completeSetOfViewsToMove(ArrayList<View> views, Rect boundingRect, int[] direction,
1691e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen            boolean[][] occupied, View dragView, ItemConfiguration currentState) {
1692e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen        Rect r0 = new Rect(boundingRect);
1693e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen        int minRuns = 0;
1694e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen
1695e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen        // The first thing we do is to reduce the bounding rect to first or last row or column,
1696e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen        // depending on the direction. Then, we add any necessary views that are already contained
1697e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen        // by the bounding rect, but aren't in the list of intersecting views, and will be pushed
1698e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen        // by something already in the intersecting views.
1699e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen        if (direction[1] < 0) {
1700e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen            r0.set(r0.left, r0.bottom - 1, r0.right, r0.bottom);
1701e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen        } else if (direction[1] > 0) {
1702e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen            r0.set(r0.left, r0.top, r0.right, r0.top + 1);
1703e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen        } else if (direction[0] < 0) {
1704e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen            r0.set(r0.right - 1, r0.top, r0.right, r0.bottom);
1705e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen        } else if (direction[0] > 0) {
1706e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen            r0.set(r0.left, r0.top, r0.left + 1, r0.bottom);
1707e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen        }
1708e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen
1709e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen        minRuns = Math.max(Math.abs(boundingRect.width() - r0.width()),
1710e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen                Math.abs(boundingRect.height() - r0.height())) + 1;
1711e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen
1712e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen        // Here the first number of runs (minRuns) accounts for the the comment above, and
1713e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen        // further runs execute based on whether the intersecting views / bounding rect need
1714e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen        // to be expanded to include other views that will be pushed.
1715e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen        while (addViewInDirection(views, r0, direction, mTmpOccupied,
1716e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen                dragView, currentState) || minRuns > 0) {
1717e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen            minRuns--;
1718e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen        }
1719e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen        boundingRect.union(r0);
1720e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen    }
1721e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen
17228baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen    private boolean addViewsToTempLocation(ArrayList<View> views, Rect rectOccupiedByPotentialDrop,
172319f3792523fe2d55ea791a9286398a6120920690Adam Cohen            int[] direction, boolean push, View dragView, ItemConfiguration currentState) {
172447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        if (views.size() == 0) return true;
172547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
172647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        boolean success = false;
172747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        Rect boundingRect = null;
17288baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // We construct a rect which represents the entire group of views passed in
172947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        for (View v: views) {
17308baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = currentState.map.get(v);
173147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            if (boundingRect == null) {
17328baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                boundingRect = new Rect(c.x, c.y, c.x + c.spanX, c.y + c.spanY);
173347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            } else {
17348baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                boundingRect.union(c.x, c.y, c.x + c.spanX, c.y + c.spanY);
173547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            }
173647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
173747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
17388baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        @SuppressWarnings("unchecked")
173947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        ArrayList<View> dup = (ArrayList<View>) views.clone();
1740e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen        if (push) {
1741e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen            completeSetOfViewsToMove(dup, boundingRect, direction, mTmpOccupied, dragView,
1742e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen                    currentState);
174347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
17448baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen
17458baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // Mark the occupied state as false for the group of views we want to move.
174647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        for (View v: dup) {
17478baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = currentState.map.get(v);
17488baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, false);
174947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
175047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
175147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        boolean[][] blockOccupied = new boolean[boundingRect.width()][boundingRect.height()];
175247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        int top = boundingRect.top;
175347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        int left = boundingRect.left;
17548baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // We mark more precisely which parts of the bounding rect are truly occupied, allowing
1755a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen        // for interlocking.
175647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        for (View v: dup) {
17578baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = currentState.map.get(v);
17588baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            markCellsForView(c.x - left, c.y - top, c.spanX, c.spanY, blockOccupied, true);
175947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
176047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
176147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        markCellsForRect(rectOccupiedByPotentialDrop, mTmpOccupied, true);
176247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
17638baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        if (push) {
17648baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            findNearestAreaInDirection(boundingRect.left, boundingRect.top, boundingRect.width(),
17658baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                    boundingRect.height(), direction, mTmpOccupied, blockOccupied, mTempLocation);
17668baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        } else {
17678baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            findNearestArea(boundingRect.left, boundingRect.top, boundingRect.width(),
17688baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                    boundingRect.height(), direction, mTmpOccupied, blockOccupied, mTempLocation);
17698baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        }
177047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
17718baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // If we successfuly found a location by pushing the block of views, we commit it
177247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        if (mTempLocation[0] >= 0 && mTempLocation[1] >= 0) {
17738baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            int deltaX = mTempLocation[0] - boundingRect.left;
17748baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            int deltaY = mTempLocation[1] - boundingRect.top;
177547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            for (View v: dup) {
17768baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                CellAndSpan c = currentState.map.get(v);
17778baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                c.x += deltaX;
17788baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                c.y += deltaY;
177947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            }
178047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            success = true;
178147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
1782482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
17838baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // In either case, we set the occupied array as marked for the location of the views
17848baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        for (View v: dup) {
17858baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = currentState.map.get(v);
17868baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, true);
1787482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1788482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return success;
1789482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1790482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1791482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private void markCellsForRect(Rect r, boolean[][] occupied, boolean value) {
1792482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsForView(r.left, r.top, r.width(), r.height(), occupied, value);
1793482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1794482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
17954abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen    // This method tries to find a reordering solution which satisfies the push mechanic by trying
17964abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen    // to push items in each of the cardinal directions, in an order based on the direction vector
17974abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen    // passed.
17984abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen    private boolean attemptPushInDirection(ArrayList<View> intersectingViews, Rect occupied,
17994abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            int[] direction, View ignoreView, ItemConfiguration solution) {
18004abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen        if ((Math.abs(direction[0]) + Math.abs(direction[1])) > 1) {
18014abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            // If the direction vector has two non-zero components, we try pushing
18024abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            // separately in each of the components.
18034abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            int temp = direction[1];
18044abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            direction[1] = 0;
18054abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            if (addViewsToTempLocation(intersectingViews, occupied, direction, true,
18064abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen                    ignoreView, solution)) {
18074abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen                return true;
18084abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            }
18094abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            direction[1] = temp;
18104abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            temp = direction[0];
18114abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            direction[0] = 0;
18124abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            if (addViewsToTempLocation(intersectingViews, occupied, direction, true,
18134abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen                    ignoreView, solution)) {
18144abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen                return true;
18154abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            }
18164abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            // Revert the direction
18174abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            direction[0] = temp;
18184abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen
18194abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            // Now we try pushing in each component of the opposite direction
18204abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            direction[0] *= -1;
18214abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            direction[1] *= -1;
18224abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            temp = direction[1];
18234abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            direction[1] = 0;
18244abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            if (addViewsToTempLocation(intersectingViews, occupied, direction, true,
18254abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen                    ignoreView, solution)) {
18264abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen                return true;
18274abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            }
18284abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen
18294abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            direction[1] = temp;
18304abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            temp = direction[0];
18314abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            direction[0] = 0;
18324abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            if (addViewsToTempLocation(intersectingViews, occupied, direction, true,
18334abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen                    ignoreView, solution)) {
18344abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen                return true;
18354abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            }
18364abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            // revert the direction
18374abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            direction[0] = temp;
18384abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            direction[0] *= -1;
18394abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            direction[1] *= -1;
18404abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen
18414abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen        } else {
18424abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            // If the direction vector has a single non-zero component, we push first in the
18434abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            // direction of the vector
18444abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            if (addViewsToTempLocation(intersectingViews, occupied, direction, true,
18454abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen                    ignoreView, solution)) {
18464abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen                return true;
18474abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            }
18484abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen
18494abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            // Then we try the opposite direction
18504abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            direction[0] *= -1;
18514abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            direction[1] *= -1;
18524abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            if (addViewsToTempLocation(intersectingViews, occupied, direction, true,
18534abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen                    ignoreView, solution)) {
18544abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen                return true;
18554abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            }
18564abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            // Switch the direction back
18574abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            direction[0] *= -1;
18584abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            direction[1] *= -1;
18594abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen
18604abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            // If we have failed to find a push solution with the above, then we try
18614abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            // to find a solution by pushing along the perpendicular axis.
18624abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen
18634abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            // Swap the components
18644abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            int temp = direction[1];
18654abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            direction[1] = direction[0];
18664abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            direction[0] = temp;
18674abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            if (addViewsToTempLocation(intersectingViews, occupied, direction, true,
18684abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen                    ignoreView, solution)) {
18694abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen                return true;
18704abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            }
18714abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen
18724abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            // Then we try the opposite direction
18734abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            direction[0] *= -1;
18744abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            direction[1] *= -1;
18754abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            if (addViewsToTempLocation(intersectingViews, occupied, direction, true,
18764abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen                    ignoreView, solution)) {
18774abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen                return true;
18784abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            }
18794abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            // Switch the direction back
18804abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            direction[0] *= -1;
18814abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            direction[1] *= -1;
18824abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen
18834abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            // Swap the components back
18844abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            temp = direction[1];
18854abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            direction[1] = direction[0];
18864abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            direction[0] = temp;
18874abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen        }
18884abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen        return false;
18894abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen    }
18904abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen
1891482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private boolean rearrangementExists(int cellX, int cellY, int spanX, int spanY, int[] direction,
18928baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            View ignoreView, ItemConfiguration solution) {
1893e3e03bcd313ba8060f2832b6a16dea6fd6d532eaWinson Chung        // Return early if get invalid cell positions
1894e3e03bcd313ba8060f2832b6a16dea6fd6d532eaWinson Chung        if (cellX < 0 || cellY < 0) return false;
1895482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
18968baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        mIntersectingViews.clear();
1897482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        mOccupiedRect.set(cellX, cellY, cellX + spanX, cellY + spanY);
1898482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
18998baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // Mark the desired location of the view currently being dragged.
1900482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (ignoreView != null) {
19018baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = solution.map.get(ignoreView);
190219f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (c != null) {
190319f3792523fe2d55ea791a9286398a6120920690Adam Cohen                c.x = cellX;
190419f3792523fe2d55ea791a9286398a6120920690Adam Cohen                c.y = cellY;
190519f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
1906482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1907482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        Rect r0 = new Rect(cellX, cellY, cellX + spanX, cellY + spanY);
1908482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        Rect r1 = new Rect();
19098baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        for (View child: solution.map.keySet()) {
1910482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (child == ignoreView) continue;
19118baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = solution.map.get(child);
1912482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
19138baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            r1.set(c.x, c.y, c.x + c.spanX, c.y + c.spanY);
1914482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (Rect.intersects(r0, r1)) {
1915482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                if (!lp.canReorder) {
1916482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    return false;
1917482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                }
1918482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                mIntersectingViews.add(child);
1919482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1920482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
192147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
19224abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen        // First we try to find a solution which respects the push mechanic. That is,
19234abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen        // we try to find a solution such that no displaced item travels through another item
19244abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen        // without also displacing that item.
19254abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen        if (attemptPushInDirection(mIntersectingViews, mOccupiedRect, direction, ignoreView,
192619f3792523fe2d55ea791a9286398a6120920690Adam Cohen                solution)) {
192747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            return true;
192847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
192947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
19304abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen        // Next we try moving the views as a block, but without requiring the push mechanic.
193119f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if (addViewsToTempLocation(mIntersectingViews, mOccupiedRect, direction, false, ignoreView,
193219f3792523fe2d55ea791a9286398a6120920690Adam Cohen                solution)) {
1933482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            return true;
1934482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
193547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
1936482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // Ok, they couldn't move as a block, let's move them individually
1937482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (View v : mIntersectingViews) {
19388baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            if (!addViewToTempLocation(v, mOccupiedRect, direction, solution)) {
1939482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                return false;
1940482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1941482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1942482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return true;
1943482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1944482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1945482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    /*
1946482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * Returns a pair (x, y), where x,y are in {-1, 0, 1} corresponding to vector between
1947482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * the provided point and the provided cell
1948482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     */
194947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    private void computeDirectionVector(float deltaX, float deltaY, int[] result) {
1950482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        double angle = Math.atan(((float) deltaY) / deltaX);
1951482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1952482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        result[0] = 0;
1953482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        result[1] = 0;
1954482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (Math.abs(Math.cos(angle)) > 0.5f) {
1955482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            result[0] = (int) Math.signum(deltaX);
1956482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1957482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (Math.abs(Math.sin(angle)) > 0.5f) {
1958482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            result[1] = (int) Math.signum(deltaY);
1959482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1960482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1961482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
19628baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen    private void copyOccupiedArray(boolean[][] occupied) {
19638baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        for (int i = 0; i < mCountX; i++) {
19648baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            for (int j = 0; j < mCountY; j++) {
19658baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                occupied[i][j] = mOccupied[i][j];
19668baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            }
19678baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        }
19688baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen    }
19698baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen
1970482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    ItemConfiguration simpleSwap(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX,
1971482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            int spanY, int[] direction, View dragView, boolean decX, ItemConfiguration solution) {
19728baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // Copy the current state into the solution. This solution will be manipulated as necessary.
19738baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        copyCurrentStateToSolution(solution, false);
19748baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // Copy the current occupied array into the temporary occupied array. This array will be
19758baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // manipulated as necessary to find a solution.
19768baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        copyOccupiedArray(mTmpOccupied);
1977482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1978482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // We find the nearest cell into which we would place the dragged item, assuming there's
1979482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // nothing in its way.
1980482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        int result[] = new int[2];
1981482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        result = findNearestArea(pixelX, pixelY, spanX, spanY, result);
1982482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1983482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        boolean success = false;
1984482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // First we try the exact nearest position of the item being dragged,
1985482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // we will then want to try to move this around to other neighbouring positions
19868baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        success = rearrangementExists(result[0], result[1], spanX, spanY, direction, dragView,
19878baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                solution);
1988482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1989482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (!success) {
1990482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            // We try shrinking the widget down to size in an alternating pattern, shrink 1 in
1991482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            // x, then 1 in y etc.
1992482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (spanX > minSpanX && (minSpanY == spanY || decX)) {
1993482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                return simpleSwap(pixelX, pixelY, minSpanX, minSpanY, spanX - 1, spanY, direction,
1994482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        dragView, false, solution);
1995482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            } else if (spanY > minSpanY) {
1996482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                return simpleSwap(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY - 1, direction,
1997482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        dragView, true, solution);
1998482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1999482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.isSolution = false;
2000482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        } else {
2001482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.isSolution = true;
2002482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewX = result[0];
2003482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewY = result[1];
2004482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewSpanX = spanX;
2005482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewSpanY = spanY;
2006482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2007482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return solution;
2008482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2009482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2010482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private void copyCurrentStateToSolution(ItemConfiguration solution, boolean temp) {
2011a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        int childCount = mShortcutsAndWidgets.getChildCount();
2012482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < childCount; i++) {
2013a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            View child = mShortcutsAndWidgets.getChildAt(i);
2014482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
20158baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c;
2016482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (temp) {
20178baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                c = new CellAndSpan(lp.tmpCellX, lp.tmpCellY, lp.cellHSpan, lp.cellVSpan);
2018482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            } else {
20198baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                c = new CellAndSpan(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan);
2020482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
20218baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            solution.map.put(child, c);
2022482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2023482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2024482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2025482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private void copySolutionToTempState(ItemConfiguration solution, View dragView) {
2026482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < mCountX; i++) {
2027482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            for (int j = 0; j < mCountY; j++) {
2028482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                mTmpOccupied[i][j] = false;
2029482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
2030482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2031482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2032a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        int childCount = mShortcutsAndWidgets.getChildCount();
2033482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < childCount; i++) {
2034a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            View child = mShortcutsAndWidgets.getChildAt(i);
2035482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (child == dragView) continue;
2036482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
20378baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = solution.map.get(child);
20388baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            if (c != null) {
20398baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                lp.tmpCellX = c.x;
20408baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                lp.tmpCellY = c.y;
20418baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                lp.cellHSpan = c.spanX;
20428baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                lp.cellVSpan = c.spanY;
20438baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, true);
2044482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
2045482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2046482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsForView(solution.dragViewX, solution.dragViewY, solution.dragViewSpanX,
2047482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                solution.dragViewSpanY, mTmpOccupied, true);
2048482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2049482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2050482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private void animateItemsToSolution(ItemConfiguration solution, View dragView, boolean
2051482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            commitDragView) {
2052482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2053482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        boolean[][] occupied = DESTRUCTIVE_REORDER ? mOccupied : mTmpOccupied;
2054482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < mCountX; i++) {
2055482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            for (int j = 0; j < mCountY; j++) {
2056482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                occupied[i][j] = false;
2057482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
2058482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2059482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2060a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        int childCount = mShortcutsAndWidgets.getChildCount();
2061482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < childCount; i++) {
2062a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            View child = mShortcutsAndWidgets.getChildAt(i);
2063482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (child == dragView) continue;
20648baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = solution.map.get(child);
20658baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            if (c != null) {
206619f3792523fe2d55ea791a9286398a6120920690Adam Cohen                animateChildToPosition(child, c.x, c.y, REORDER_ANIMATION_DURATION, 0,
206719f3792523fe2d55ea791a9286398a6120920690Adam Cohen                        DESTRUCTIVE_REORDER, false);
20688baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                markCellsForView(c.x, c.y, c.spanX, c.spanY, occupied, true);
2069482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
2070482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2071482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (commitDragView) {
2072482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            markCellsForView(solution.dragViewX, solution.dragViewY, solution.dragViewSpanX,
2073482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    solution.dragViewSpanY, occupied, true);
2074482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2075482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2076482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
207719f3792523fe2d55ea791a9286398a6120920690Adam Cohen    // This method starts or changes the reorder hint animations
207819f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private void beginOrAdjustHintAnimations(ItemConfiguration solution, View dragView, int delay) {
207919f3792523fe2d55ea791a9286398a6120920690Adam Cohen        int childCount = mShortcutsAndWidgets.getChildCount();
208019f3792523fe2d55ea791a9286398a6120920690Adam Cohen        for (int i = 0; i < childCount; i++) {
208119f3792523fe2d55ea791a9286398a6120920690Adam Cohen            View child = mShortcutsAndWidgets.getChildAt(i);
208219f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (child == dragView) continue;
208319f3792523fe2d55ea791a9286398a6120920690Adam Cohen            CellAndSpan c = solution.map.get(child);
208419f3792523fe2d55ea791a9286398a6120920690Adam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
208519f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (c != null) {
208619f3792523fe2d55ea791a9286398a6120920690Adam Cohen                ReorderHintAnimation rha = new ReorderHintAnimation(child, lp.cellX, lp.cellY,
208719f3792523fe2d55ea791a9286398a6120920690Adam Cohen                        c.x, c.y, c.spanX, c.spanY);
2088d024f9845a0974ab525baad085f316031cd5a742Adam Cohen                rha.animate();
208919f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
209019f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
209119f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
209219f3792523fe2d55ea791a9286398a6120920690Adam Cohen
209319f3792523fe2d55ea791a9286398a6120920690Adam Cohen    // Class which represents the reorder hint animations. These animations show that an item is
209419f3792523fe2d55ea791a9286398a6120920690Adam Cohen    // in a temporary state, and hint at where the item will return to.
209519f3792523fe2d55ea791a9286398a6120920690Adam Cohen    class ReorderHintAnimation {
209619f3792523fe2d55ea791a9286398a6120920690Adam Cohen        View child;
2097d024f9845a0974ab525baad085f316031cd5a742Adam Cohen        float finalDeltaX;
2098d024f9845a0974ab525baad085f316031cd5a742Adam Cohen        float finalDeltaY;
2099d024f9845a0974ab525baad085f316031cd5a742Adam Cohen        float initDeltaX;
2100d024f9845a0974ab525baad085f316031cd5a742Adam Cohen        float initDeltaY;
2101d024f9845a0974ab525baad085f316031cd5a742Adam Cohen        float finalScale;
2102d024f9845a0974ab525baad085f316031cd5a742Adam Cohen        float initScale;
210350e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely        private static final int DURATION = 300;
2104e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen        Animator a;
210519f3792523fe2d55ea791a9286398a6120920690Adam Cohen
210619f3792523fe2d55ea791a9286398a6120920690Adam Cohen        public ReorderHintAnimation(View child, int cellX0, int cellY0, int cellX1, int cellY1,
210719f3792523fe2d55ea791a9286398a6120920690Adam Cohen                int spanX, int spanY) {
210819f3792523fe2d55ea791a9286398a6120920690Adam Cohen            regionToCenterPoint(cellX0, cellY0, spanX, spanY, mTmpPoint);
210919f3792523fe2d55ea791a9286398a6120920690Adam Cohen            final int x0 = mTmpPoint[0];
211019f3792523fe2d55ea791a9286398a6120920690Adam Cohen            final int y0 = mTmpPoint[1];
211119f3792523fe2d55ea791a9286398a6120920690Adam Cohen            regionToCenterPoint(cellX1, cellY1, spanX, spanY, mTmpPoint);
211219f3792523fe2d55ea791a9286398a6120920690Adam Cohen            final int x1 = mTmpPoint[0];
211319f3792523fe2d55ea791a9286398a6120920690Adam Cohen            final int y1 = mTmpPoint[1];
211419f3792523fe2d55ea791a9286398a6120920690Adam Cohen            final int dX = x1 - x0;
211519f3792523fe2d55ea791a9286398a6120920690Adam Cohen            final int dY = y1 - y0;
2116d024f9845a0974ab525baad085f316031cd5a742Adam Cohen            finalDeltaX = 0;
2117d024f9845a0974ab525baad085f316031cd5a742Adam Cohen            finalDeltaY = 0;
211819f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (dX == dY && dX == 0) {
211919f3792523fe2d55ea791a9286398a6120920690Adam Cohen            } else {
212019f3792523fe2d55ea791a9286398a6120920690Adam Cohen                if (dY == 0) {
2121d024f9845a0974ab525baad085f316031cd5a742Adam Cohen                    finalDeltaX = - Math.signum(dX) * mReorderHintAnimationMagnitude;
212219f3792523fe2d55ea791a9286398a6120920690Adam Cohen                } else if (dX == 0) {
2123d024f9845a0974ab525baad085f316031cd5a742Adam Cohen                    finalDeltaY = - Math.signum(dY) * mReorderHintAnimationMagnitude;
212419f3792523fe2d55ea791a9286398a6120920690Adam Cohen                } else {
212519f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    double angle = Math.atan( (float) (dY) / dX);
2126d024f9845a0974ab525baad085f316031cd5a742Adam Cohen                    finalDeltaX = (int) (- Math.signum(dX) *
2127fe41ac641bdef7ea96dcbac59b4f3abdbdff6cfeAdam Cohen                            Math.abs(Math.cos(angle) * mReorderHintAnimationMagnitude));
2128d024f9845a0974ab525baad085f316031cd5a742Adam Cohen                    finalDeltaY = (int) (- Math.signum(dY) *
2129fe41ac641bdef7ea96dcbac59b4f3abdbdff6cfeAdam Cohen                            Math.abs(Math.sin(angle) * mReorderHintAnimationMagnitude));
213019f3792523fe2d55ea791a9286398a6120920690Adam Cohen                }
213119f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
2132d024f9845a0974ab525baad085f316031cd5a742Adam Cohen            initDeltaX = child.getTranslationX();
2133d024f9845a0974ab525baad085f316031cd5a742Adam Cohen            initDeltaY = child.getTranslationY();
2134307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen            finalScale = getChildrenScale() - 4.0f / child.getWidth();
2135d024f9845a0974ab525baad085f316031cd5a742Adam Cohen            initScale = child.getScaleX();
213619f3792523fe2d55ea791a9286398a6120920690Adam Cohen            this.child = child;
213719f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
213819f3792523fe2d55ea791a9286398a6120920690Adam Cohen
2139d024f9845a0974ab525baad085f316031cd5a742Adam Cohen        void animate() {
214019f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (mShakeAnimators.containsKey(child)) {
214119f3792523fe2d55ea791a9286398a6120920690Adam Cohen                ReorderHintAnimation oldAnimation = mShakeAnimators.get(child);
2142d024f9845a0974ab525baad085f316031cd5a742Adam Cohen                oldAnimation.cancel();
214319f3792523fe2d55ea791a9286398a6120920690Adam Cohen                mShakeAnimators.remove(child);
2144e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen                if (finalDeltaX == 0 && finalDeltaY == 0) {
2145e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen                    completeAnimationImmediately();
2146e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen                    return;
2147e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen                }
214819f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
2149d024f9845a0974ab525baad085f316031cd5a742Adam Cohen            if (finalDeltaX == 0 && finalDeltaY == 0) {
215019f3792523fe2d55ea791a9286398a6120920690Adam Cohen                return;
215119f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
21522ecf995e0d2d55eb71d03f7230ca87270872d1a3Michael Jurka            ValueAnimator va = LauncherAnimUtils.ofFloat(0f, 1f);
2153e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen            a = va;
215419f3792523fe2d55ea791a9286398a6120920690Adam Cohen            va.setRepeatMode(ValueAnimator.REVERSE);
215519f3792523fe2d55ea791a9286398a6120920690Adam Cohen            va.setRepeatCount(ValueAnimator.INFINITE);
21567bdfc9700b1cad043c04c757f134db1bf3df00daAdam Cohen            va.setDuration(DURATION);
2157d024f9845a0974ab525baad085f316031cd5a742Adam Cohen            va.setStartDelay((int) (Math.random() * 60));
215819f3792523fe2d55ea791a9286398a6120920690Adam Cohen            va.addUpdateListener(new AnimatorUpdateListener() {
215919f3792523fe2d55ea791a9286398a6120920690Adam Cohen                @Override
216019f3792523fe2d55ea791a9286398a6120920690Adam Cohen                public void onAnimationUpdate(ValueAnimator animation) {
216119f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    float r = ((Float) animation.getAnimatedValue()).floatValue();
2162d024f9845a0974ab525baad085f316031cd5a742Adam Cohen                    float x = r * finalDeltaX + (1 - r) * initDeltaX;
2163d024f9845a0974ab525baad085f316031cd5a742Adam Cohen                    float y = r * finalDeltaY + (1 - r) * initDeltaY;
216419f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    child.setTranslationX(x);
216519f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    child.setTranslationY(y);
2166d024f9845a0974ab525baad085f316031cd5a742Adam Cohen                    float s = r * finalScale + (1 - r) * initScale;
216750e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely                    child.setScaleX(s);
216850e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely                    child.setScaleY(s);
216919f3792523fe2d55ea791a9286398a6120920690Adam Cohen                }
217019f3792523fe2d55ea791a9286398a6120920690Adam Cohen            });
217119f3792523fe2d55ea791a9286398a6120920690Adam Cohen            va.addListener(new AnimatorListenerAdapter() {
217219f3792523fe2d55ea791a9286398a6120920690Adam Cohen                public void onAnimationRepeat(Animator animation) {
217319f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    // We make sure to end only after a full period
2174d024f9845a0974ab525baad085f316031cd5a742Adam Cohen                    initDeltaX = 0;
2175d024f9845a0974ab525baad085f316031cd5a742Adam Cohen                    initDeltaY = 0;
2176307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen                    initScale = getChildrenScale();
217719f3792523fe2d55ea791a9286398a6120920690Adam Cohen                }
217819f3792523fe2d55ea791a9286398a6120920690Adam Cohen            });
217919f3792523fe2d55ea791a9286398a6120920690Adam Cohen            mShakeAnimators.put(child, this);
218019f3792523fe2d55ea791a9286398a6120920690Adam Cohen            va.start();
218119f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
218219f3792523fe2d55ea791a9286398a6120920690Adam Cohen
2183d024f9845a0974ab525baad085f316031cd5a742Adam Cohen        private void cancel() {
2184e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen            if (a != null) {
2185e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen                a.cancel();
2186e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen            }
218719f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
2188e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen
218950e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely        private void completeAnimationImmediately() {
2190e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen            if (a != null) {
2191e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen                a.cancel();
2192e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen            }
219350e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely
21942ecf995e0d2d55eb71d03f7230ca87270872d1a3Michael Jurka            AnimatorSet s = LauncherAnimUtils.createAnimatorSet();
2195e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen            a = s;
219650e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely            s.playTogether(
2197307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen                LauncherAnimUtils.ofFloat(child, "scaleX", getChildrenScale()),
2198307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen                LauncherAnimUtils.ofFloat(child, "scaleY", getChildrenScale()),
21992ecf995e0d2d55eb71d03f7230ca87270872d1a3Michael Jurka                LauncherAnimUtils.ofFloat(child, "translationX", 0f),
22002ecf995e0d2d55eb71d03f7230ca87270872d1a3Michael Jurka                LauncherAnimUtils.ofFloat(child, "translationY", 0f)
220150e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely            );
220250e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely            s.setDuration(REORDER_ANIMATION_DURATION);
220350e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely            s.setInterpolator(new android.view.animation.DecelerateInterpolator(1.5f));
220450e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely            s.start();
220550e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely        }
220619f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
220719f3792523fe2d55ea791a9286398a6120920690Adam Cohen
220819f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private void completeAndClearReorderHintAnimations() {
220919f3792523fe2d55ea791a9286398a6120920690Adam Cohen        for (ReorderHintAnimation a: mShakeAnimators.values()) {
221050e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely            a.completeAnimationImmediately();
221119f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
221219f3792523fe2d55ea791a9286398a6120920690Adam Cohen        mShakeAnimators.clear();
221319f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
221419f3792523fe2d55ea791a9286398a6120920690Adam Cohen
2215482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private void commitTempPlacement() {
2216482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < mCountX; i++) {
2217482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            for (int j = 0; j < mCountY; j++) {
2218482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                mOccupied[i][j] = mTmpOccupied[i][j];
2219482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
2220482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2221a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        int childCount = mShortcutsAndWidgets.getChildCount();
2222482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < childCount; i++) {
2223ea889a294be004f4b1c21e9b874f9e63abfb8bd6Adam Cohen            View child = mShortcutsAndWidgets.getChildAt(i);
2224ea889a294be004f4b1c21e9b874f9e63abfb8bd6Adam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
2225ea889a294be004f4b1c21e9b874f9e63abfb8bd6Adam Cohen            ItemInfo info = (ItemInfo) child.getTag();
22262acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen            // We do a null check here because the item info can be null in the case of the
22272acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen            // AllApps button in the hotseat.
22282acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen            if (info != null) {
2229487f7dd3059621527eb439d7d51d34e00293f9b1Adam Cohen                if (info.cellX != lp.tmpCellX || info.cellY != lp.tmpCellY ||
2230487f7dd3059621527eb439d7d51d34e00293f9b1Adam Cohen                        info.spanX != lp.cellHSpan || info.spanY != lp.cellVSpan) {
2231487f7dd3059621527eb439d7d51d34e00293f9b1Adam Cohen                    info.requiresDbUpdate = true;
2232487f7dd3059621527eb439d7d51d34e00293f9b1Adam Cohen                }
22332acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen                info.cellX = lp.cellX = lp.tmpCellX;
22342acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen                info.cellY = lp.cellY = lp.tmpCellY;
2235bebf042666cffe52039b875a549a582abd78a431Adam Cohen                info.spanX = lp.cellHSpan;
2236bebf042666cffe52039b875a549a582abd78a431Adam Cohen                info.spanY = lp.cellVSpan;
22372acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen            }
2238482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
22392acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen        mLauncher.getWorkspace().updateItemLocationsInDatabase(this);
2240482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2241482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2242482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public void setUseTempCoords(boolean useTempCoords) {
2243a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        int childCount = mShortcutsAndWidgets.getChildCount();
2244482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < childCount; i++) {
2245a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            LayoutParams lp = (LayoutParams) mShortcutsAndWidgets.getChildAt(i).getLayoutParams();
2246482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            lp.useTmpCoords = useTempCoords;
2247482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2248482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2249482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2250482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    ItemConfiguration findConfigurationNoShuffle(int pixelX, int pixelY, int minSpanX, int minSpanY,
2251482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            int spanX, int spanY, View dragView, ItemConfiguration solution) {
2252482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        int[] result = new int[2];
2253482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        int[] resultSpan = new int[2];
2254482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        findNearestVacantArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, null, result,
2255482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                resultSpan);
2256482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (result[0] >= 0 && result[1] >= 0) {
2257482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            copyCurrentStateToSolution(solution, false);
2258482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewX = result[0];
2259482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewY = result[1];
2260482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewSpanX = resultSpan[0];
2261482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewSpanY = resultSpan[1];
2262482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.isSolution = true;
2263482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        } else {
2264482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.isSolution = false;
2265482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2266482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return solution;
2267482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2268482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2269482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public void prepareChildForDrag(View child) {
2270482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsAsUnoccupiedForView(child);
2271482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2272482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
227319f3792523fe2d55ea791a9286398a6120920690Adam Cohen    /* This seems like it should be obvious and straight-forward, but when the direction vector
227419f3792523fe2d55ea791a9286398a6120920690Adam Cohen    needs to match with the notion of the dragView pushing other views, we have to employ
227519f3792523fe2d55ea791a9286398a6120920690Adam Cohen    a slightly more subtle notion of the direction vector. The question is what two points is
227619f3792523fe2d55ea791a9286398a6120920690Adam Cohen    the vector between? The center of the dragView and its desired destination? Not quite, as
227719f3792523fe2d55ea791a9286398a6120920690Adam Cohen    this doesn't necessarily coincide with the interaction of the dragView and items occupying
227819f3792523fe2d55ea791a9286398a6120920690Adam Cohen    those cells. Instead we use some heuristics to often lock the vector to up, down, left
227919f3792523fe2d55ea791a9286398a6120920690Adam Cohen    or right, which helps make pushing feel right.
228019f3792523fe2d55ea791a9286398a6120920690Adam Cohen    */
228119f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private void getDirectionVectorForDrop(int dragViewCenterX, int dragViewCenterY, int spanX,
228219f3792523fe2d55ea791a9286398a6120920690Adam Cohen            int spanY, View dragView, int[] resultDirection) {
228319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        int[] targetDestination = new int[2];
228419f3792523fe2d55ea791a9286398a6120920690Adam Cohen
228519f3792523fe2d55ea791a9286398a6120920690Adam Cohen        findNearestArea(dragViewCenterX, dragViewCenterY, spanX, spanY, targetDestination);
228619f3792523fe2d55ea791a9286398a6120920690Adam Cohen        Rect dragRect = new Rect();
228719f3792523fe2d55ea791a9286398a6120920690Adam Cohen        regionToRect(targetDestination[0], targetDestination[1], spanX, spanY, dragRect);
228819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        dragRect.offset(dragViewCenterX - dragRect.centerX(), dragViewCenterY - dragRect.centerY());
228919f3792523fe2d55ea791a9286398a6120920690Adam Cohen
229019f3792523fe2d55ea791a9286398a6120920690Adam Cohen        Rect dropRegionRect = new Rect();
229119f3792523fe2d55ea791a9286398a6120920690Adam Cohen        getViewsIntersectingRegion(targetDestination[0], targetDestination[1], spanX, spanY,
229219f3792523fe2d55ea791a9286398a6120920690Adam Cohen                dragView, dropRegionRect, mIntersectingViews);
229319f3792523fe2d55ea791a9286398a6120920690Adam Cohen
229419f3792523fe2d55ea791a9286398a6120920690Adam Cohen        int dropRegionSpanX = dropRegionRect.width();
229519f3792523fe2d55ea791a9286398a6120920690Adam Cohen        int dropRegionSpanY = dropRegionRect.height();
229619f3792523fe2d55ea791a9286398a6120920690Adam Cohen
229719f3792523fe2d55ea791a9286398a6120920690Adam Cohen        regionToRect(dropRegionRect.left, dropRegionRect.top, dropRegionRect.width(),
229819f3792523fe2d55ea791a9286398a6120920690Adam Cohen                dropRegionRect.height(), dropRegionRect);
229919f3792523fe2d55ea791a9286398a6120920690Adam Cohen
230019f3792523fe2d55ea791a9286398a6120920690Adam Cohen        int deltaX = (dropRegionRect.centerX() - dragViewCenterX) / spanX;
230119f3792523fe2d55ea791a9286398a6120920690Adam Cohen        int deltaY = (dropRegionRect.centerY() - dragViewCenterY) / spanY;
230219f3792523fe2d55ea791a9286398a6120920690Adam Cohen
230319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if (dropRegionSpanX == mCountX || spanX == mCountX) {
230419f3792523fe2d55ea791a9286398a6120920690Adam Cohen            deltaX = 0;
230519f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
230619f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if (dropRegionSpanY == mCountY || spanY == mCountY) {
230719f3792523fe2d55ea791a9286398a6120920690Adam Cohen            deltaY = 0;
230819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
230919f3792523fe2d55ea791a9286398a6120920690Adam Cohen
231019f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if (deltaX == 0 && deltaY == 0) {
231119f3792523fe2d55ea791a9286398a6120920690Adam Cohen            // No idea what to do, give a random direction.
231219f3792523fe2d55ea791a9286398a6120920690Adam Cohen            resultDirection[0] = 1;
231319f3792523fe2d55ea791a9286398a6120920690Adam Cohen            resultDirection[1] = 0;
231419f3792523fe2d55ea791a9286398a6120920690Adam Cohen        } else {
231519f3792523fe2d55ea791a9286398a6120920690Adam Cohen            computeDirectionVector(deltaX, deltaY, resultDirection);
231619f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
231719f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
231819f3792523fe2d55ea791a9286398a6120920690Adam Cohen
231919f3792523fe2d55ea791a9286398a6120920690Adam Cohen    // For a given cell and span, fetch the set of views intersecting the region.
232019f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private void getViewsIntersectingRegion(int cellX, int cellY, int spanX, int spanY,
232119f3792523fe2d55ea791a9286398a6120920690Adam Cohen            View dragView, Rect boundingRect, ArrayList<View> intersectingViews) {
232219f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if (boundingRect != null) {
232319f3792523fe2d55ea791a9286398a6120920690Adam Cohen            boundingRect.set(cellX, cellY, cellX + spanX, cellY + spanY);
232419f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
232519f3792523fe2d55ea791a9286398a6120920690Adam Cohen        intersectingViews.clear();
232619f3792523fe2d55ea791a9286398a6120920690Adam Cohen        Rect r0 = new Rect(cellX, cellY, cellX + spanX, cellY + spanY);
232719f3792523fe2d55ea791a9286398a6120920690Adam Cohen        Rect r1 = new Rect();
232819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        final int count = mShortcutsAndWidgets.getChildCount();
232919f3792523fe2d55ea791a9286398a6120920690Adam Cohen        for (int i = 0; i < count; i++) {
233019f3792523fe2d55ea791a9286398a6120920690Adam Cohen            View child = mShortcutsAndWidgets.getChildAt(i);
233119f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (child == dragView) continue;
233219f3792523fe2d55ea791a9286398a6120920690Adam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
233319f3792523fe2d55ea791a9286398a6120920690Adam Cohen            r1.set(lp.cellX, lp.cellY, lp.cellX + lp.cellHSpan, lp.cellY + lp.cellVSpan);
233419f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (Rect.intersects(r0, r1)) {
233519f3792523fe2d55ea791a9286398a6120920690Adam Cohen                mIntersectingViews.add(child);
233619f3792523fe2d55ea791a9286398a6120920690Adam Cohen                if (boundingRect != null) {
233719f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    boundingRect.union(r1);
233819f3792523fe2d55ea791a9286398a6120920690Adam Cohen                }
233919f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
234019f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
234119f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
234219f3792523fe2d55ea791a9286398a6120920690Adam Cohen
234319f3792523fe2d55ea791a9286398a6120920690Adam Cohen    boolean isNearestDropLocationOccupied(int pixelX, int pixelY, int spanX, int spanY,
234419f3792523fe2d55ea791a9286398a6120920690Adam Cohen            View dragView, int[] result) {
234519f3792523fe2d55ea791a9286398a6120920690Adam Cohen        result = findNearestArea(pixelX, pixelY, spanX, spanY, result);
234619f3792523fe2d55ea791a9286398a6120920690Adam Cohen        getViewsIntersectingRegion(result[0], result[1], spanX, spanY, dragView, null,
234719f3792523fe2d55ea791a9286398a6120920690Adam Cohen                mIntersectingViews);
234819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        return !mIntersectingViews.isEmpty();
234919f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
235019f3792523fe2d55ea791a9286398a6120920690Adam Cohen
235119f3792523fe2d55ea791a9286398a6120920690Adam Cohen    void revertTempState() {
235219f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if (!isItemPlacementDirty() || DESTRUCTIVE_REORDER) return;
235319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        final int count = mShortcutsAndWidgets.getChildCount();
235419f3792523fe2d55ea791a9286398a6120920690Adam Cohen        for (int i = 0; i < count; i++) {
235519f3792523fe2d55ea791a9286398a6120920690Adam Cohen            View child = mShortcutsAndWidgets.getChildAt(i);
235619f3792523fe2d55ea791a9286398a6120920690Adam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
235719f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (lp.tmpCellX != lp.cellX || lp.tmpCellY != lp.cellY) {
235819f3792523fe2d55ea791a9286398a6120920690Adam Cohen                lp.tmpCellX = lp.cellX;
235919f3792523fe2d55ea791a9286398a6120920690Adam Cohen                lp.tmpCellY = lp.cellY;
236019f3792523fe2d55ea791a9286398a6120920690Adam Cohen                animateChildToPosition(child, lp.cellX, lp.cellY, REORDER_ANIMATION_DURATION,
236119f3792523fe2d55ea791a9286398a6120920690Adam Cohen                        0, false, false);
236219f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
236319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
236419f3792523fe2d55ea791a9286398a6120920690Adam Cohen        completeAndClearReorderHintAnimations();
236519f3792523fe2d55ea791a9286398a6120920690Adam Cohen        setItemPlacementDirty(false);
236619f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
236719f3792523fe2d55ea791a9286398a6120920690Adam Cohen
2368bebf042666cffe52039b875a549a582abd78a431Adam Cohen    boolean createAreaForResize(int cellX, int cellY, int spanX, int spanY,
2369bebf042666cffe52039b875a549a582abd78a431Adam Cohen            View dragView, int[] direction, boolean commit) {
2370bebf042666cffe52039b875a549a582abd78a431Adam Cohen        int[] pixelXY = new int[2];
2371bebf042666cffe52039b875a549a582abd78a431Adam Cohen        regionToCenterPoint(cellX, cellY, spanX, spanY, pixelXY);
2372bebf042666cffe52039b875a549a582abd78a431Adam Cohen
2373bebf042666cffe52039b875a549a582abd78a431Adam Cohen        // First we determine if things have moved enough to cause a different layout
2374bebf042666cffe52039b875a549a582abd78a431Adam Cohen        ItemConfiguration swapSolution = simpleSwap(pixelXY[0], pixelXY[1], spanX, spanY,
2375bebf042666cffe52039b875a549a582abd78a431Adam Cohen                 spanX,  spanY, direction, dragView,  true,  new ItemConfiguration());
2376bebf042666cffe52039b875a549a582abd78a431Adam Cohen
2377bebf042666cffe52039b875a549a582abd78a431Adam Cohen        setUseTempCoords(true);
2378bebf042666cffe52039b875a549a582abd78a431Adam Cohen        if (swapSolution != null && swapSolution.isSolution) {
2379bebf042666cffe52039b875a549a582abd78a431Adam Cohen            // If we're just testing for a possible location (MODE_ACCEPT_DROP), we don't bother
2380bebf042666cffe52039b875a549a582abd78a431Adam Cohen            // committing anything or animating anything as we just want to determine if a solution
2381bebf042666cffe52039b875a549a582abd78a431Adam Cohen            // exists
2382bebf042666cffe52039b875a549a582abd78a431Adam Cohen            copySolutionToTempState(swapSolution, dragView);
2383bebf042666cffe52039b875a549a582abd78a431Adam Cohen            setItemPlacementDirty(true);
2384bebf042666cffe52039b875a549a582abd78a431Adam Cohen            animateItemsToSolution(swapSolution, dragView, commit);
2385bebf042666cffe52039b875a549a582abd78a431Adam Cohen
2386bebf042666cffe52039b875a549a582abd78a431Adam Cohen            if (commit) {
2387bebf042666cffe52039b875a549a582abd78a431Adam Cohen                commitTempPlacement();
2388bebf042666cffe52039b875a549a582abd78a431Adam Cohen                completeAndClearReorderHintAnimations();
2389bebf042666cffe52039b875a549a582abd78a431Adam Cohen                setItemPlacementDirty(false);
2390bebf042666cffe52039b875a549a582abd78a431Adam Cohen            } else {
2391bebf042666cffe52039b875a549a582abd78a431Adam Cohen                beginOrAdjustHintAnimations(swapSolution, dragView,
2392bebf042666cffe52039b875a549a582abd78a431Adam Cohen                        REORDER_ANIMATION_DURATION);
2393bebf042666cffe52039b875a549a582abd78a431Adam Cohen            }
2394bebf042666cffe52039b875a549a582abd78a431Adam Cohen            mShortcutsAndWidgets.requestLayout();
2395bebf042666cffe52039b875a549a582abd78a431Adam Cohen        }
2396bebf042666cffe52039b875a549a582abd78a431Adam Cohen        return swapSolution.isSolution;
2397bebf042666cffe52039b875a549a582abd78a431Adam Cohen    }
2398bebf042666cffe52039b875a549a582abd78a431Adam Cohen
2399482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    int[] createArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, int spanY,
2400482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            View dragView, int[] result, int resultSpan[], int mode) {
2401482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // First we determine if things have moved enough to cause a different layout
240247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        result = findNearestArea(pixelX, pixelY, spanX, spanY, result);
2403482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2404482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (resultSpan == null) {
2405482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            resultSpan = new int[2];
2406482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2407482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
240819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        // When we are checking drop validity or actually dropping, we don't recompute the
240919f3792523fe2d55ea791a9286398a6120920690Adam Cohen        // direction vector, since we want the solution to match the preview, and it's possible
241019f3792523fe2d55ea791a9286398a6120920690Adam Cohen        // that the exact position of the item has changed to result in a new reordering outcome.
2411b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen        if ((mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL || mode == MODE_ACCEPT_DROP)
2412b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen               && mPreviousReorderDirection[0] != INVALID_DIRECTION) {
241319f3792523fe2d55ea791a9286398a6120920690Adam Cohen            mDirectionVector[0] = mPreviousReorderDirection[0];
241419f3792523fe2d55ea791a9286398a6120920690Adam Cohen            mDirectionVector[1] = mPreviousReorderDirection[1];
241519f3792523fe2d55ea791a9286398a6120920690Adam Cohen            // We reset this vector after drop
2416b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen            if (mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL) {
2417b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen                mPreviousReorderDirection[0] = INVALID_DIRECTION;
2418b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen                mPreviousReorderDirection[1] = INVALID_DIRECTION;
241919f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
242019f3792523fe2d55ea791a9286398a6120920690Adam Cohen        } else {
242119f3792523fe2d55ea791a9286398a6120920690Adam Cohen            getDirectionVectorForDrop(pixelX, pixelY, spanX, spanY, dragView, mDirectionVector);
242219f3792523fe2d55ea791a9286398a6120920690Adam Cohen            mPreviousReorderDirection[0] = mDirectionVector[0];
242319f3792523fe2d55ea791a9286398a6120920690Adam Cohen            mPreviousReorderDirection[1] = mDirectionVector[1];
242419f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
242519f3792523fe2d55ea791a9286398a6120920690Adam Cohen
2426482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        ItemConfiguration swapSolution = simpleSwap(pixelX, pixelY, minSpanX, minSpanY,
2427482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                 spanX,  spanY, mDirectionVector, dragView,  true,  new ItemConfiguration());
2428482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2429482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // We attempt the approach which doesn't shuffle views at all
2430482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        ItemConfiguration noShuffleSolution = findConfigurationNoShuffle(pixelX, pixelY, minSpanX,
2431482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                minSpanY, spanX, spanY, dragView, new ItemConfiguration());
2432482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2433482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        ItemConfiguration finalSolution = null;
2434482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (swapSolution.isSolution && swapSolution.area() >= noShuffleSolution.area()) {
2435482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            finalSolution = swapSolution;
2436482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        } else if (noShuffleSolution.isSolution) {
2437482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            finalSolution = noShuffleSolution;
2438482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2439482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2440482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        boolean foundSolution = true;
2441482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (!DESTRUCTIVE_REORDER) {
2442482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            setUseTempCoords(true);
2443482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2444482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2445482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (finalSolution != null) {
2446482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            result[0] = finalSolution.dragViewX;
2447482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            result[1] = finalSolution.dragViewY;
2448482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            resultSpan[0] = finalSolution.dragViewSpanX;
2449482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            resultSpan[1] = finalSolution.dragViewSpanY;
2450482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2451482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            // If we're just testing for a possible location (MODE_ACCEPT_DROP), we don't bother
2452482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            // committing anything or animating anything as we just want to determine if a solution
2453482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            // exists
2454482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (mode == MODE_DRAG_OVER || mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL) {
2455482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                if (!DESTRUCTIVE_REORDER) {
2456482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    copySolutionToTempState(finalSolution, dragView);
2457482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                }
2458482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                setItemPlacementDirty(true);
2459482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                animateItemsToSolution(finalSolution, dragView, mode == MODE_ON_DROP);
2460482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
246119f3792523fe2d55ea791a9286398a6120920690Adam Cohen                if (!DESTRUCTIVE_REORDER &&
246219f3792523fe2d55ea791a9286398a6120920690Adam Cohen                        (mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL)) {
2463482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    commitTempPlacement();
246419f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    completeAndClearReorderHintAnimations();
246519f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    setItemPlacementDirty(false);
246619f3792523fe2d55ea791a9286398a6120920690Adam Cohen                } else {
246719f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    beginOrAdjustHintAnimations(finalSolution, dragView,
246819f3792523fe2d55ea791a9286398a6120920690Adam Cohen                            REORDER_ANIMATION_DURATION);
2469482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                }
2470482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
2471482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        } else {
2472482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            foundSolution = false;
2473482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            result[0] = result[1] = resultSpan[0] = resultSpan[1] = -1;
2474482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2475482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2476482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if ((mode == MODE_ON_DROP || !foundSolution) && !DESTRUCTIVE_REORDER) {
2477482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            setUseTempCoords(false);
2478482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2479482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2480a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.requestLayout();
2481482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return result;
2482482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2483482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
248419f3792523fe2d55ea791a9286398a6120920690Adam Cohen    void setItemPlacementDirty(boolean dirty) {
248519f3792523fe2d55ea791a9286398a6120920690Adam Cohen        mItemPlacementDirty = dirty;
2486482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
248719f3792523fe2d55ea791a9286398a6120920690Adam Cohen    boolean isItemPlacementDirty() {
248819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        return mItemPlacementDirty;
2489482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2490482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2491482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private class ItemConfiguration {
24928baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        HashMap<View, CellAndSpan> map = new HashMap<View, CellAndSpan>();
2493482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        boolean isSolution = false;
2494482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        int dragViewX, dragViewY, dragViewSpanX, dragViewSpanY;
2495482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2496482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        int area() {
2497482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            return dragViewSpanX * dragViewSpanY;
2498482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
24998baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen    }
25008baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen
25018baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen    private class CellAndSpan {
25028baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        int x, y;
25038baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        int spanX, spanY;
25048baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen
25058baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        public CellAndSpan(int x, int y, int spanX, int spanY) {
25068baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            this.x = x;
25078baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            this.y = y;
25088baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            this.spanX = spanX;
25098baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            this.spanY = spanY;
2510482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2511482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2512482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2513df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    /**
2514df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * Find a vacant area that will fit the given bounds nearest the requested
2515df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * cell location. Uses Euclidean distance to score multiple vacant areas.
2516df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     *
2517df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param pixelX The X location at which you want to search for a vacant area.
2518df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param pixelY The Y location at which you want to search for a vacant area.
2519df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param spanX Horizontal span of the object.
2520df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param spanY Vertical span of the object.
2521df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param ignoreView Considers space occupied by this view as unoccupied
2522df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param result Previously returned value to possibly recycle.
2523df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @return The X, Y cell of a vacant area that can contain this object,
2524df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     *         nearest the requested location.
2525df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     */
2526df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    int[] findNearestVacantArea(
2527df0353815c629fc678824b07a234b89a1ff94208Adam Cohen            int pixelX, int pixelY, int spanX, int spanY, View ignoreView, int[] result) {
2528df0353815c629fc678824b07a234b89a1ff94208Adam Cohen        return findNearestArea(pixelX, pixelY, spanX, spanY, ignoreView, true, result);
2529df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    }
2530df0353815c629fc678824b07a234b89a1ff94208Adam Cohen
2531df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    /**
2532d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * Find a vacant area that will fit the given bounds nearest the requested
2533d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * cell location. Uses Euclidean distance to score multiple vacant areas.
2534d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *
2535d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param pixelX The X location at which you want to search for a vacant area.
2536d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param pixelY The Y location at which you want to search for a vacant area.
2537d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param minSpanX The minimum horizontal span required
2538d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param minSpanY The minimum vertical span required
2539d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param spanX Horizontal span of the object.
2540d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param spanY Vertical span of the object.
2541d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param ignoreView Considers space occupied by this view as unoccupied
2542d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param result Previously returned value to possibly recycle.
2543d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @return The X, Y cell of a vacant area that can contain this object,
2544d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *         nearest the requested location.
2545d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     */
2546d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    int[] findNearestVacantArea(int pixelX, int pixelY, int minSpanX, int minSpanY,
2547d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            int spanX, int spanY, View ignoreView, int[] result, int[] resultSpan) {
2548482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return findNearestArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, ignoreView, true,
2549482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                result, resultSpan, mOccupied);
2550d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    }
2551d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen
2552d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    /**
2553df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * Find a starting cell position that will fit the given bounds nearest the requested
2554df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * cell location. Uses Euclidean distance to score multiple vacant areas.
2555df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     *
2556df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param pixelX The X location at which you want to search for a vacant area.
2557df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param pixelY The Y location at which you want to search for a vacant area.
2558df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param spanX Horizontal span of the object.
2559df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param spanY Vertical span of the object.
2560df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param ignoreView Considers space occupied by this view as unoccupied
2561df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param result Previously returned value to possibly recycle.
2562df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @return The X, Y cell of a vacant area that can contain this object,
2563df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     *         nearest the requested location.
2564df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     */
2565df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    int[] findNearestArea(
2566df0353815c629fc678824b07a234b89a1ff94208Adam Cohen            int pixelX, int pixelY, int spanX, int spanY, int[] result) {
2567df0353815c629fc678824b07a234b89a1ff94208Adam Cohen        return findNearestArea(pixelX, pixelY, spanX, spanY, null, false, result);
2568df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    }
2569df0353815c629fc678824b07a234b89a1ff94208Adam Cohen
25700280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    boolean existsEmptyCell() {
25710280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        return findCellForSpan(null, 1, 1);
25720280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
25730280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
25740280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    /**
25750280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * Finds the upper-left coordinate of the first rectangle in the grid that can
25760280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * hold a cell of the specified dimensions. If intersectX and intersectY are not -1,
25770280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * then this method will only return coordinates for rectangles that contain the cell
25780280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * (intersectX, intersectY)
25790280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     *
25800280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param cellXY The array that will contain the position of a vacant cell if such a cell
25810280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     *               can be found.
25820280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param spanX The horizontal span of the cell we want to find.
25830280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param spanY The vertical span of the cell we want to find.
25840280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     *
25850280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @return True if a vacant cell of the specified dimension was found, false otherwise.
25860280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     */
25870280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    boolean findCellForSpan(int[] cellXY, int spanX, int spanY) {
2588482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return findCellForSpanThatIntersectsIgnoring(cellXY, spanX, spanY, -1, -1, null, mOccupied);
25890280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
25900280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
25910280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    /**
25920280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * Like above, but ignores any cells occupied by the item "ignoreView"
25930280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     *
25940280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param cellXY The array that will contain the position of a vacant cell if such a cell
25950280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     *               can be found.
25960280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param spanX The horizontal span of the cell we want to find.
25970280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param spanY The vertical span of the cell we want to find.
25980280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param ignoreView The home screen item we should treat as not occupying any space
25990280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @return
26000280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     */
26010280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    boolean findCellForSpanIgnoring(int[] cellXY, int spanX, int spanY, View ignoreView) {
2602482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return findCellForSpanThatIntersectsIgnoring(cellXY, spanX, spanY, -1, -1,
2603482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                ignoreView, mOccupied);
26040280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
26050280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
26060280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    /**
26070280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * Like above, but if intersectX and intersectY are not -1, then this method will try to
26080280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * return coordinates for rectangles that contain the cell [intersectX, intersectY]
26090280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     *
26100280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param spanX The horizontal span of the cell we want to find.
26110280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param spanY The vertical span of the cell we want to find.
26120280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param ignoreView The home screen item we should treat as not occupying any space
26130280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param intersectX The X coordinate of the cell that we should try to overlap
26140280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param intersectX The Y coordinate of the cell that we should try to overlap
26150280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     *
26160280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @return True if a vacant cell of the specified dimension was found, false otherwise.
26170280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     */
26180280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    boolean findCellForSpanThatIntersects(int[] cellXY, int spanX, int spanY,
26190280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            int intersectX, int intersectY) {
26200280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        return findCellForSpanThatIntersectsIgnoring(
2621482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                cellXY, spanX, spanY, intersectX, intersectY, null, mOccupied);
26220280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
26230280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
26240280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    /**
26250280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * The superset of the above two methods
26260280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     */
26270280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    boolean findCellForSpanThatIntersectsIgnoring(int[] cellXY, int spanX, int spanY,
2628482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            int intersectX, int intersectY, View ignoreView, boolean occupied[][]) {
2629c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka        // mark space take by ignoreView as available (method checks if ignoreView is null)
2630482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsAsUnoccupiedForView(ignoreView, occupied);
26310280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
263228750fba6a2d141eb9a1e566718c17236030b815Michael Jurka        boolean foundCell = false;
26330280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        while (true) {
26340280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            int startX = 0;
26350280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            if (intersectX >= 0) {
26360280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                startX = Math.max(startX, intersectX - (spanX - 1));
26370280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            }
26380280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            int endX = mCountX - (spanX - 1);
26390280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            if (intersectX >= 0) {
26400280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                endX = Math.min(endX, intersectX + (spanX - 1) + (spanX == 1 ? 1 : 0));
26410280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            }
26420280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            int startY = 0;
26430280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            if (intersectY >= 0) {
26440280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                startY = Math.max(startY, intersectY - (spanY - 1));
26450280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            }
26460280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            int endY = mCountY - (spanY - 1);
26470280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            if (intersectY >= 0) {
26480280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                endY = Math.min(endY, intersectY + (spanY - 1) + (spanY == 1 ? 1 : 0));
26490280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            }
26500280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
2651bbc60d8e79416e37cbede55c159bf6aaa6c171d5Winson Chung            for (int y = startY; y < endY && !foundCell; y++) {
26520280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                inner:
2653bbc60d8e79416e37cbede55c159bf6aaa6c171d5Winson Chung                for (int x = startX; x < endX; x++) {
26540280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                    for (int i = 0; i < spanX; i++) {
26550280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                        for (int j = 0; j < spanY; j++) {
2656482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                            if (occupied[x + i][y + j]) {
2657bbc60d8e79416e37cbede55c159bf6aaa6c171d5Winson Chung                                // small optimization: we can skip to after the column we just found
26580280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                                // an occupied cell
2659bbc60d8e79416e37cbede55c159bf6aaa6c171d5Winson Chung                                x += i;
26600280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                                continue inner;
26610280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                            }
26620280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                        }
26630280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                    }
26640280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                    if (cellXY != null) {
26650280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                        cellXY[0] = x;
26660280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                        cellXY[1] = y;
26670280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                    }
266828750fba6a2d141eb9a1e566718c17236030b815Michael Jurka                    foundCell = true;
266928750fba6a2d141eb9a1e566718c17236030b815Michael Jurka                    break;
26700280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                }
26710280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            }
26720280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            if (intersectX == -1 && intersectY == -1) {
26730280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                break;
26740280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            } else {
26750280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                // if we failed to find anything, try again but without any requirements of
26760280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                // intersecting
26770280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                intersectX = -1;
26780280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                intersectY = -1;
26790280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                continue;
26800280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            }
26810280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        }
26820280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
2683c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka        // re-mark space taken by ignoreView as occupied
2684482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsAsOccupiedForView(ignoreView, occupied);
268528750fba6a2d141eb9a1e566718c17236030b815Michael Jurka        return foundCell;
26860280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
26870280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
268831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
2689c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung     * A drag event has begun over this layout.
2690c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung     * It may have begun over this layout (in which case onDragChild is called first),
2691c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung     * or it may have begun on another layout.
2692c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung     */
2693c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung    void onDragEnter() {
2694c6cc61d45836e4081920883cc4d448ccb0bb8417Adam Cohen        mDragEnforcer.onDragEnter();
2695c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung        mDragging = true;
2696c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung    }
2697c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung
2698c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung    /**
26990280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * Called when drag has left this CellLayout or has been completed (successfully or not)
27006569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     */
27010280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    void onDragExit() {
2702c6cc61d45836e4081920883cc4d448ccb0bb8417Adam Cohen        mDragEnforcer.onDragExit();
27034be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        // This can actually be called when we aren't in a drag, e.g. when adding a new
27044be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        // item to this layout via the customize drawer.
27054be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        // Guard against that case.
27064be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        if (mDragging) {
27074be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            mDragging = false;
27084be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        }
270908ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy
271008ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy        // Invalidate the drag data
2711d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        mDragCell[0] = mDragCell[1] = -1;
271208ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy        mDragOutlineAnims[mDragOutlineCurrent].animateOut();
271308ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy        mDragOutlineCurrent = (mDragOutlineCurrent + 1) % mDragOutlineAnims.length;
271419f3792523fe2d55ea791a9286398a6120920690Adam Cohen        revertTempState();
271533945b21544bc98381df17726a3537c292d8c985Michael Jurka        setIsDragOverlapping(false);
27166569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    }
27176569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
27186569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    /**
2719aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     * Mark a child as having been dropped.
2720de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy     * At the beginning of the drag operation, the child may have been on another
2721ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy     * screen, but it is re-parented before this method is called.
272231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     *
272331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param child The child that is being dropped
272431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
2725716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    void onDropChild(View child) {
2726d94533d04a5f8f5485f106d10af60169857ea899Romain Guy        if (child != null) {
2727d94533d04a5f8f5485f106d10af60169857ea899Romain Guy            LayoutParams lp = (LayoutParams) child.getLayoutParams();
272884f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy            lp.dropped = true;
2729d94533d04a5f8f5485f106d10af60169857ea899Romain Guy            child.requestLayout();
2730d94533d04a5f8f5485f106d10af60169857ea899Romain Guy        }
273131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
273231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
273331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
273431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * Computes a bounding rectangle for a range of cells
2735aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     *
273631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param cellX X coordinate of upper left corner expressed as a cell position
273731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param cellY Y coordinate of upper left corner expressed as a cell position
2738aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     * @param cellHSpan Width in cells
273931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param cellVSpan Height in cells
27406569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     * @param resultRect Rect into which to put the results
274131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
2742d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    public void cellToRect(int cellX, int cellY, int cellHSpan, int cellVSpan, Rect resultRect) {
274331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        final int cellWidth = mCellWidth;
274431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        final int cellHeight = mCellHeight;
274531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        final int widthGap = mWidthGap;
274631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        final int heightGap = mHeightGap;
2747aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
27484b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int hStartPadding = getPaddingLeft();
27494b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int vStartPadding = getPaddingTop();
2750aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
275131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int width = cellHSpan * cellWidth + ((cellHSpan - 1) * widthGap);
275231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int height = cellVSpan * cellHeight + ((cellVSpan - 1) * heightGap);
275331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
275431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int x = hStartPadding + cellX * (cellWidth + widthGap);
275531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int y = vStartPadding + cellY * (cellHeight + heightGap);
2756aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
27576569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        resultRect.set(x, y, x + width, y + height);
275831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
2759aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
276031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
2761aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     * Computes the required horizontal and vertical cell spans to always
276231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * fit the given rectangle.
2763aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     *
276431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param width Width in pixels
276531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param height Height in pixels
27668f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy     * @param result An array of length 2 in which to store the result (may be null).
276731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
27688f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy    public int[] rectToCell(int width, int height, int[] result) {
27699987a5c45e7d01a780d73b269bdce8d8a5309219Michael Jurka        return rectToCell(getResources(), width, height, result);
27709987a5c45e7d01a780d73b269bdce8d8a5309219Michael Jurka    }
27719987a5c45e7d01a780d73b269bdce8d8a5309219Michael Jurka
27729987a5c45e7d01a780d73b269bdce8d8a5309219Michael Jurka    public static int[] rectToCell(Resources resources, int width, int height, int[] result) {
277331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // Always assume we're working with the smallest span to make sure we
277431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // reserve enough space in both orientations.
277579e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato        int actualWidth = resources.getDimensionPixelSize(R.dimen.workspace_cell_width);
277679e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato        int actualHeight = resources.getDimensionPixelSize(R.dimen.workspace_cell_height);
277731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int smallerSize = Math.min(actualWidth, actualHeight);
277879e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato
277931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // Always round up to next largest cell
278054c725cc294cd43ed0650179bfae64a622547660Winson Chung        int spanX = (int) Math.ceil(width / (float) smallerSize);
278154c725cc294cd43ed0650179bfae64a622547660Winson Chung        int spanY = (int) Math.ceil(height / (float) smallerSize);
278279e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato
27838f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy        if (result == null) {
27848f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy            return new int[] { spanX, spanY };
27858f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy        }
27868f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy        result[0] = spanX;
27878f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy        result[1] = spanY;
27888f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy        return result;
278931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
279031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
2791f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka    public int[] cellSpansToSize(int hSpans, int vSpans) {
2792f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka        int[] size = new int[2];
2793f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka        size[0] = hSpans * mCellWidth + (hSpans - 1) * mWidthGap;
2794f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka        size[1] = vSpans * mCellHeight + (vSpans - 1) * mHeightGap;
2795f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka        return size;
2796f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka    }
2797f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka
279831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
2799047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy     * Calculate the grid spans needed to fit given item
2800047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy     */
2801047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy    public void calculateSpans(ItemInfo info) {
2802047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        final int minWidth;
2803047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        final int minHeight;
2804047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy
2805047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        if (info instanceof LauncherAppWidgetInfo) {
2806047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy            minWidth = ((LauncherAppWidgetInfo) info).minWidth;
2807047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy            minHeight = ((LauncherAppWidgetInfo) info).minHeight;
2808047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        } else if (info instanceof PendingAddWidgetInfo) {
2809047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy            minWidth = ((PendingAddWidgetInfo) info).minWidth;
2810047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy            minHeight = ((PendingAddWidgetInfo) info).minHeight;
2811047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        } else {
2812047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy            // It's not a widget, so it must be 1x1
2813047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy            info.spanX = info.spanY = 1;
2814047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy            return;
2815047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        }
2816047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        int[] spans = rectToCell(minWidth, minHeight, null);
2817047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        info.spanX = spans[0];
2818047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        info.spanY = spans[1];
2819047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy    }
2820047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy
2821047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy    /**
282231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * Find the first vacant cell, if there is one.
282331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     *
282431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param vacant Holds the x and y coordinate of the vacant cell
282531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param spanX Horizontal cell span.
282631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param spanY Vertical cell span.
2827aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     *
282831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @return True if a vacant cell was found
282931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
283031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public boolean getVacantCell(int[] vacant, int spanX, int spanY) {
283131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
28320280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        return findVacantCell(vacant, spanX, spanY, mCountX, mCountY, mOccupied);
283331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
283431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
283531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    static boolean findVacantCell(int[] vacant, int spanX, int spanY,
283631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            int xCount, int yCount, boolean[][] occupied) {
283731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
28382801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        for (int y = 0; y < yCount; y++) {
28392801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            for (int x = 0; x < xCount; x++) {
284031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                boolean available = !occupied[x][y];
284131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectout:            for (int i = x; i < x + spanX - 1 && x < xCount; i++) {
284231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                    for (int j = y; j < y + spanY - 1 && y < yCount; j++) {
284331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                        available = available && !occupied[i][j];
284431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                        if (!available) break out;
284531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                    }
284631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                }
284731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
284831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                if (available) {
284931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                    vacant[0] = x;
285031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                    vacant[1] = y;
285131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                    return true;
285231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                }
285331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            }
285431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
285531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
285631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        return false;
285731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
285831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
28590280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    private void clearOccupiedCells() {
28600280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        for (int x = 0; x < mCountX; x++) {
28610280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            for (int y = 0; y < mCountY; y++) {
28620280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                mOccupied[x][y] = false;
286331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            }
286431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
28650280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
286631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
2867d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    public void onMove(View view, int newCellX, int newCellY, int newSpanX, int newSpanY) {
28680280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        markCellsAsUnoccupiedForView(view);
2869482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsForView(newCellX, newCellY, newSpanX, newSpanY, mOccupied, true);
28700280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
287131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
2872d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    public void markCellsAsOccupiedForView(View view) {
2873482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsAsOccupiedForView(view, mOccupied);
2874482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2875482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public void markCellsAsOccupiedForView(View view, boolean[][] occupied) {
2876a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        if (view == null || view.getParent() != mShortcutsAndWidgets) return;
28770280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        LayoutParams lp = (LayoutParams) view.getLayoutParams();
2878482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, occupied, true);
28790280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
28800280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
2881d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    public void markCellsAsUnoccupiedForView(View view) {
2882482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsAsUnoccupiedForView(view, mOccupied);
2883482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2884482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public void markCellsAsUnoccupiedForView(View view, boolean occupied[][]) {
2885a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        if (view == null || view.getParent() != mShortcutsAndWidgets) return;
28860280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        LayoutParams lp = (LayoutParams) view.getLayoutParams();
2887482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, occupied, false);
28880280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
28890280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
2890482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private void markCellsForView(int cellX, int cellY, int spanX, int spanY, boolean[][] occupied,
2891482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            boolean value) {
2892482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (cellX < 0 || cellY < 0) return;
28930280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        for (int x = cellX; x < cellX + spanX && x < mCountX; x++) {
28940280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            for (int y = cellY; y < cellY + spanY && y < mCountY; y++) {
2895482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                occupied[x][y] = value;
289631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            }
289731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
289831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
289931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
29002801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    public int getDesiredWidth() {
29018b805b17158886035b38261eb611d8641701ae43Michael Jurka        return getPaddingLeft() + getPaddingRight() + (mCountX * mCellWidth) +
29022801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen                (Math.max((mCountX - 1), 0) * mWidthGap);
29032801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    }
29042801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
29052801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    public int getDesiredHeight()  {
29068b805b17158886035b38261eb611d8641701ae43Michael Jurka        return getPaddingTop() + getPaddingBottom() + (mCountY * mCellHeight) +
29072801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen                (Math.max((mCountY - 1), 0) * mHeightGap);
29082801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    }
29092801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
291066d72178af91d455700875635473be942bc90e54Michael Jurka    public boolean isOccupied(int x, int y) {
291166d72178af91d455700875635473be942bc90e54Michael Jurka        if (x < mCountX && y < mCountY) {
291266d72178af91d455700875635473be942bc90e54Michael Jurka            return mOccupied[x][y];
291366d72178af91d455700875635473be942bc90e54Michael Jurka        } else {
291466d72178af91d455700875635473be942bc90e54Michael Jurka            throw new RuntimeException("Position exceeds the bound of this CellLayout");
291566d72178af91d455700875635473be942bc90e54Michael Jurka        }
291666d72178af91d455700875635473be942bc90e54Michael Jurka    }
291766d72178af91d455700875635473be942bc90e54Michael Jurka
291831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
291931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
292031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        return new CellLayout.LayoutParams(getContext(), attrs);
292131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
292231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
292331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
292431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
292531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        return p instanceof CellLayout.LayoutParams;
292631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
292731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
292831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
292931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
293031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        return new CellLayout.LayoutParams(p);
293131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
293231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
2933aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung    public static class CellLayoutAnimationController extends LayoutAnimationController {
2934aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        public CellLayoutAnimationController(Animation animation, float delay) {
2935aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            super(animation, delay);
2936aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        }
2937aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
2938aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        @Override
2939aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        protected long getDelayForView(View view) {
2940aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            return (int) (Math.random() * 150);
2941aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        }
2942aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung    }
2943aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
294431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public static class LayoutParams extends ViewGroup.MarginLayoutParams {
294531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        /**
294631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         * Horizontal location of the item in the grid.
294731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         */
294831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        @ViewDebug.ExportedProperty
294931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public int cellX;
295031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
295131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        /**
295231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         * Vertical location of the item in the grid.
295331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         */
295431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        @ViewDebug.ExportedProperty
295531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public int cellY;
295631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
295731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        /**
2958482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         * Temporary horizontal location of the item in the grid during reorder
2959482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         */
2960482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        public int tmpCellX;
2961482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2962482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        /**
2963482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         * Temporary vertical location of the item in the grid during reorder
2964482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         */
2965482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        public int tmpCellY;
2966482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2967482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        /**
2968482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         * Indicates that the temporary coordinates should be used to layout the items
2969482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         */
2970482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        public boolean useTmpCoords;
2971482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2972482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        /**
297331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         * Number of cells spanned horizontally by the item.
297431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         */
297531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        @ViewDebug.ExportedProperty
297631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public int cellHSpan;
297731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
297831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        /**
297931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         * Number of cells spanned vertically by the item.
298031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         */
298131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        @ViewDebug.ExportedProperty
298231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public int cellVSpan;
2983aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
29841b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen        /**
29851b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen         * Indicates whether the item will set its x, y, width and height parameters freely,
29861b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen         * or whether these will be computed based on cellX, cellY, cellHSpan and cellVSpan.
29871b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen         */
2988d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        public boolean isLockedToGrid = true;
2989d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
2990482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        /**
2991482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         * Indicates whether this item can be reordered. Always true except in the case of the
2992482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         * the AllApps button.
2993482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         */
2994482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        public boolean canReorder = true;
2995482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
299631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // X coordinate of the view in the layout.
299731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        @ViewDebug.ExportedProperty
299831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int x;
299931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // Y coordinate of the view in the layout.
300031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        @ViewDebug.ExportedProperty
300131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int y;
300231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
300384f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy        boolean dropped;
3004fcb9e7144e58614f5ae0e9b272fb7ce040848c67Romain Guy
300531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public LayoutParams(Context c, AttributeSet attrs) {
300631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            super(c, attrs);
300731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            cellHSpan = 1;
300831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            cellVSpan = 1;
300931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
301031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
301131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public LayoutParams(ViewGroup.LayoutParams source) {
301231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            super(source);
301331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            cellHSpan = 1;
301431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            cellVSpan = 1;
301531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
3016aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
3017aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        public LayoutParams(LayoutParams source) {
3018aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            super(source);
3019aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            this.cellX = source.cellX;
3020aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            this.cellY = source.cellY;
3021aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            this.cellHSpan = source.cellHSpan;
3022aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            this.cellVSpan = source.cellVSpan;
3023aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        }
3024aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
302531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public LayoutParams(int cellX, int cellY, int cellHSpan, int cellVSpan) {
30268f19cdd62f6e2be05e3890916eabd11317ae1bc2Romain Guy            super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
302731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            this.cellX = cellX;
302831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            this.cellY = cellY;
302931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            this.cellHSpan = cellHSpan;
303031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            this.cellVSpan = cellVSpan;
303131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
303231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
30337f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public void setup(int cellWidth, int cellHeight, int widthGap, int heightGap) {
3034d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            if (isLockedToGrid) {
3035d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                final int myCellHSpan = cellHSpan;
3036d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                final int myCellVSpan = cellVSpan;
3037482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                final int myCellX = useTmpCoords ? tmpCellX : cellX;
3038482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                final int myCellY = useTmpCoords ? tmpCellY : cellY;
30391b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen
3040d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                width = myCellHSpan * cellWidth + ((myCellHSpan - 1) * widthGap) -
3041d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                        leftMargin - rightMargin;
3042d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                height = myCellVSpan * cellHeight + ((myCellVSpan - 1) * heightGap) -
3043d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                        topMargin - bottomMargin;
3044eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                x = (int) (myCellX * (cellWidth + widthGap) + leftMargin);
3045eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                y = (int) (myCellY * (cellHeight + heightGap) + topMargin);
3046d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            }
3047d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        }
3048d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
3049aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        public String toString() {
3050aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            return "(" + this.cellX + ", " + this.cellY + ")";
3051aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        }
30527f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
30537f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public void setWidth(int width) {
30547f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            this.width = width;
30557f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
30567f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
30577f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public int getWidth() {
30587f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            return width;
30597f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
30607f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
30617f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public void setHeight(int height) {
30627f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            this.height = height;
30637f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
30647f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
30657f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public int getHeight() {
30667f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            return height;
30677f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
30687f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
30697f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public void setX(int x) {
30707f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            this.x = x;
30717f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
30727f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
30737f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public int getX() {
30747f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            return x;
30757f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
30767f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
30777f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public void setY(int y) {
30787f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            this.y = y;
30797f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
30807f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
30817f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public int getY() {
30827f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            return y;
30837f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
308431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
308531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
30860280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    // This class stores info for two purposes:
30870280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    // 1. When dragging items (mDragInfo in Workspace), we store the View, its cellX & cellY,
30880280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    //    its spanX, spanY, and the screen it is on
30890280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    // 2. When long clicking on an empty cell in a CellLayout, we save information about the
30900280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    //    cellX and cellY coordinates and which page was clicked. We then set this as a tag on
30910280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    //    the CellLayout that was long clicked
3092e5fb0f27bca7afb996258a7163c76ca7390d7bffMichael Jurka    static final class CellInfo {
309331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        View cell;
3094a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka        int cellX = -1;
3095a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka        int cellY = -1;
309631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int spanX;
309731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int spanY;
309831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int screen;
30993d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        long container;
310031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
310131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        @Override
310231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public String toString() {
3103aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            return "Cell[view=" + (cell == null ? "null" : cell.getClass())
3104aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung                    + ", x=" + cellX + ", y=" + cellY + "]";
310531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
310631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
3107d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka
3108d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka    public boolean lastDownOnOccupiedCell() {
3109d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka        return mLastDownOnOccupiedCell;
3110d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka    }
311131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project}
3112