CellLayout.java revision 7bdfc9700b1cad043c04c757f134db1bf3df00da
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;
2050e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keelyimport android.animation.AnimatorSet;
2150e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keelyimport android.animation.ObjectAnimator;
224be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onoratoimport android.animation.AnimatorListenerAdapter;
2300397b1d9233409d9d6b233b077ae12d09768ce8Chet Haaseimport android.animation.TimeInterpolator;
24de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroyimport android.animation.ValueAnimator;
25de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroyimport android.animation.ValueAnimator.AnimatorUpdateListener;
2631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.content.Context;
2779e56263dbcbe85dc434df372bc6e6730aa13477Joe Onoratoimport android.content.res.Resources;
28aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chungimport android.content.res.TypedArray;
294be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onoratoimport android.graphics.Bitmap;
30aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chungimport android.graphics.Canvas;
310dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynnimport android.graphics.Color;
324be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onoratoimport android.graphics.Paint;
33de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroyimport android.graphics.Point;
34de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroyimport android.graphics.PointF;
35b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohenimport android.graphics.PorterDuff;
36b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohenimport android.graphics.PorterDuffXfermode;
3731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.graphics.Rect;
38482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohenimport android.graphics.drawable.ColorDrawable;
396569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroyimport android.graphics.drawable.Drawable;
40b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohenimport android.graphics.drawable.NinePatchDrawable;
4131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.util.AttributeSet;
424be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onoratoimport android.util.Log;
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;
1400dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn
141482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public static final int MODE_DRAG_OVER = 0;
142482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public static final int MODE_ON_DROP = 1;
143482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public static final int MODE_ON_DROP_EXTERNAL = 2;
144482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public static final int MODE_ACCEPT_DROP = 3;
14519f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private static final boolean DESTRUCTIVE_REORDER = false;
146482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private static final boolean DEBUG_VISUALIZE_OCCUPIED = false;
147482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
148a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen    static final int LANDSCAPE = 0;
149a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen    static final int PORTRAIT = 1;
150a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen
1517bdfc9700b1cad043c04c757f134db1bf3df00daAdam Cohen    private static final float REORDER_HINT_MAGNITUDE = 0.12f;
15219f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private static final int REORDER_ANIMATION_DURATION = 150;
15319f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private float mReorderHintAnimationMagnitude;
15419f3792523fe2d55ea791a9286398a6120920690Adam Cohen
155482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private ArrayList<View> mIntersectingViews = new ArrayList<View>();
156482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private Rect mOccupiedRect = new Rect();
157482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private int[] mDirectionVector = new int[2];
15819f3792523fe2d55ea791a9286398a6120920690Adam Cohen    int[] mPreviousReorderDirection = new int[2];
159b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen    private static final int INVALID_DIRECTION = -100;
160c6cc61d45836e4081920883cc4d448ccb0bb8417Adam Cohen    private DropTarget.DragEnforcer mDragEnforcer;
161482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1628a0bff5e35f63321178bbf777ec24d42544866b3Romain Guy    private final static PorterDuffXfermode sAddBlendMode =
1638a0bff5e35f63321178bbf777ec24d42544866b3Romain Guy            new PorterDuffXfermode(PorterDuff.Mode.ADD);
1648a0bff5e35f63321178bbf777ec24d42544866b3Romain Guy
16531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public CellLayout(Context context) {
16631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        this(context, null);
16731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
16831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
16931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public CellLayout(Context context, AttributeSet attrs) {
17031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        this(context, attrs, 0);
17131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
17231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
17331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public CellLayout(Context context, AttributeSet attrs, int defStyle) {
17431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        super(context, attrs, defStyle);
1758b805b17158886035b38261eb611d8641701ae43Michael Jurka        mDragEnforcer = new DropTarget.DragEnforcer(context);
1766569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
1776569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        // A ViewGroup usually does not draw, but CellLayout needs to draw a rectangle to show
1786569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        // the user where a dragged item will land when dropped.
1796569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        setWillNotDraw(false);
1802acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen        mLauncher = (Launcher) context;
181a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka
18231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CellLayout, defStyle, 0);
18331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
184f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        mCellWidth = a.getDimensionPixelSize(R.styleable.CellLayout_cellWidth, 10);
185f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        mCellHeight = a.getDimensionPixelSize(R.styleable.CellLayout_cellHeight, 10);
186234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen        mWidthGap = mOriginalWidthGap = a.getDimensionPixelSize(R.styleable.CellLayout_widthGap, 0);
187234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen        mHeightGap = mOriginalHeightGap = a.getDimensionPixelSize(R.styleable.CellLayout_heightGap, 0);
1884b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        mMaxGap = a.getDimensionPixelSize(R.styleable.CellLayout_maxGap, 0);
189d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        mCountX = LauncherModel.getCellCountX();
190d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        mCountY = LauncherModel.getCellCountY();
1910280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        mOccupied = new boolean[mCountX][mCountY];
192482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        mTmpOccupied = new boolean[mCountX][mCountY];
1935b53f29f809a0dad4a1e0717ba610ce737ee0f43Adam Cohen        mPreviousReorderDirection[0] = INVALID_DIRECTION;
1945b53f29f809a0dad4a1e0717ba610ce737ee0f43Adam Cohen        mPreviousReorderDirection[1] = INVALID_DIRECTION;
19531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
19631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        a.recycle();
19731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
19831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        setAlwaysDrawnWithCacheEnabled(false);
19931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
200046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        final Resources res = getResources();
201de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy
202967289b6d5fec77f5c381d11ffb2319f3bb5e737Winson Chung        mNormalBackground = res.getDrawable(R.drawable.homescreen_blue_normal_holo);
203dea74b7d12b0fcd50bfdb4274f9867ba76d75238Winson Chung        mActiveGlowBackground = res.getDrawable(R.drawable.homescreen_blue_strong_holo);
204b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung
205b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        mOverScrollLeft = res.getDrawable(R.drawable.overscroll_glow_left);
206b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        mOverScrollRight = res.getDrawable(R.drawable.overscroll_glow_right);
207b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        mForegroundPadding =
208b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen                res.getDimensionPixelSize(R.dimen.workspace_overscroll_drawable_padding);
209b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung
21019f3792523fe2d55ea791a9286398a6120920690Adam Cohen        mReorderHintAnimationMagnitude = (REORDER_HINT_MAGNITUDE *
21119f3792523fe2d55ea791a9286398a6120920690Adam Cohen                res.getDimensionPixelSize(R.dimen.app_icon_size));
21219f3792523fe2d55ea791a9286398a6120920690Adam Cohen
213b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung        mNormalBackground.setFilterBitmap(true);
214b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung        mActiveGlowBackground.setFilterBitmap(true);
215de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy
216046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        // Initialize the data structures used for the drag visualization.
217150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung
218ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy        mEaseOutInterpolator = new DecelerateInterpolator(2.5f); // Quint ease out
219de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy
220046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy
221b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung        mDragCell[0] = mDragCell[1] = -1;
2224be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        for (int i = 0; i < mDragOutlines.length; i++) {
223d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            mDragOutlines[i] = new Rect(-1, -1, -1, -1);
224046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        }
225046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy
226046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        // When dragging things around the home screens, we show a green outline of
227046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        // where the item will land. The outlines gradually fade out, leaving a trail
228046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        // behind the drag path.
229046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        // Set up all the animations that are used to implement this fading.
230046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        final int duration = res.getInteger(R.integer.config_dragOutlineFadeTime);
231472b281d5cb4f5660df981a6c912266b9f5703feChet Haase        final float fromAlphaValue = 0;
232472b281d5cb4f5660df981a6c912266b9f5703feChet Haase        final float toAlphaValue = (float)res.getInteger(R.integer.config_dragOutlineMaxAlpha);
2334be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato
2348e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy        Arrays.fill(mDragOutlineAlphas, fromAlphaValue);
2354be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato
2364be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        for (int i = 0; i < mDragOutlineAnims.length; i++) {
237046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy            final InterruptibleInOutAnimator anim =
238046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy                new InterruptibleInOutAnimator(duration, fromAlphaValue, toAlphaValue);
239ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy            anim.getAnimator().setInterpolator(mEaseOutInterpolator);
240046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy            final int thisIndex = i;
241472b281d5cb4f5660df981a6c912266b9f5703feChet Haase            anim.getAnimator().addUpdateListener(new AnimatorUpdateListener() {
242de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                public void onAnimationUpdate(ValueAnimator animation) {
2434be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    final Bitmap outline = (Bitmap)anim.getTag();
2444be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato
2454be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    // If an animation is started and then stopped very quickly, we can still
2464be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    // get spurious updates we've cleared the tag. Guard against this.
2474be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    if (outline == null) {
2483a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka                        @SuppressWarnings("all") // suppress dead code warning
2493a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka                        final boolean debug = false;
2503a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka                        if (debug) {
251fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy                            Object val = animation.getAnimatedValue();
252fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy                            Log.d(TAG, "anim " + thisIndex + " update: " + val +
253fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy                                     ", isStopped " + anim.isStopped());
254fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy                        }
2554be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                        // Try to prevent it from continuing to run
2564be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                        animation.cancel();
2574be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    } else {
258472b281d5cb4f5660df981a6c912266b9f5703feChet Haase                        mDragOutlineAlphas[thisIndex] = (Float) animation.getAnimatedValue();
259d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        CellLayout.this.invalidate(mDragOutlines[thisIndex]);
2604be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    }
261de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                }
262de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy            });
2634be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            // The animation holds a reference to the drag outline bitmap as long is it's
2644be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            // running. This way the bitmap can be GCed when the animations are complete.
265472b281d5cb4f5660df981a6c912266b9f5703feChet Haase            anim.getAnimator().addListener(new AnimatorListenerAdapter() {
2663c4c20fbe682cb4b3ef94f09afe0af09171583f3Michael Jurka                @Override
2674be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                public void onAnimationEnd(Animator animation) {
268472b281d5cb4f5660df981a6c912266b9f5703feChet Haase                    if ((Float) ((ValueAnimator) animation).getAnimatedValue() == 0f) {
2694be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                        anim.setTag(null);
2704be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    }
2714be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                }
2724be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            });
2734be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            mDragOutlineAnims[i] = anim;
274de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy        }
275ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy
27618014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka        mBackgroundRect = new Rect();
277b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        mForegroundRect = new Rect();
278bea15195346bab3c52b0156e92f2b71f0811b210Michael Jurka
279a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets = new ShortcutAndWidgetContainer(context);
280a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.setCellDimensions(mCellWidth, mCellHeight, mWidthGap, mHeightGap);
281a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        addView(mShortcutsAndWidgets);
28218014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka    }
28318014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka
284f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka    static int widthInPortrait(Resources r, int numCells) {
285f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka        // We use this method from Workspace to figure out how many rows/columns Launcher should
286f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka        // have. We ignore the left/right padding on CellLayout because it turns out in our design
287f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka        // the padding extends outside the visible screen size, but it looked fine anyway.
288f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka        int cellWidth = r.getDimensionPixelSize(R.dimen.workspace_cell_width);
2894b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        int minGap = Math.min(r.getDimensionPixelSize(R.dimen.workspace_width_gap),
2904b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                r.getDimensionPixelSize(R.dimen.workspace_height_gap));
291f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka
2924b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        return  minGap * (numCells - 1) + cellWidth * numCells;
293f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka    }
294f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka
295f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka    static int heightInLandscape(Resources r, int numCells) {
296f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka        // We use this method from Workspace to figure out how many rows/columns Launcher should
297f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka        // have. We ignore the left/right padding on CellLayout because it turns out in our design
298f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka        // the padding extends outside the visible screen size, but it looked fine anyway.
299f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka        int cellHeight = r.getDimensionPixelSize(R.dimen.workspace_cell_height);
3004b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        int minGap = Math.min(r.getDimensionPixelSize(R.dimen.workspace_width_gap),
3014b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                r.getDimensionPixelSize(R.dimen.workspace_height_gap));
302f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka
3034b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        return minGap * (numCells - 1) + cellHeight * numCells;
304f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka    }
305f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka
3062801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    public void enableHardwareLayers() {
307a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.enableHardwareLayers();
3082801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    }
3092801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
3102801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    public void setGridSize(int x, int y) {
3112801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        mCountX = x;
3122801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        mCountY = y;
3132801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        mOccupied = new boolean[mCountX][mCountY];
314482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        mTmpOccupied = new boolean[mCountX][mCountY];
3157fbec10b36818f100b631f3d73fe1ad5360975aaAdam Cohen        mTempRectStack.clear();
31676fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        requestLayout();
3172801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    }
3182801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
31996864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy    private void invalidateBubbleTextView(BubbleTextView icon) {
32096864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        final int padding = icon.getPressedOrFocusedBackgroundPadding();
3214b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        invalidate(icon.getLeft() + getPaddingLeft() - padding,
3224b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                icon.getTop() + getPaddingTop() - padding,
3234b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                icon.getRight() + getPaddingLeft() + padding,
3244b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                icon.getBottom() + getPaddingTop() + padding);
32596864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy    }
32696864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy
327b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    void setOverScrollAmount(float r, boolean left) {
328b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        if (left && mOverScrollForegroundDrawable != mOverScrollLeft) {
329b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen            mOverScrollForegroundDrawable = mOverScrollLeft;
330b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        } else if (!left && mOverScrollForegroundDrawable != mOverScrollRight) {
331b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen            mOverScrollForegroundDrawable = mOverScrollRight;
332b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        }
333b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen
334b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        mForegroundAlpha = (int) Math.round((r * 255));
335b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        mOverScrollForegroundDrawable.setAlpha(mForegroundAlpha);
336b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        invalidate();
337b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    }
338b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen
33996864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy    void setPressedOrFocusedIcon(BubbleTextView icon) {
34096864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        // We draw the pressed or focused BubbleTextView's background in CellLayout because it
34196864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        // requires an expanded clip rect (due to the glow's blur radius)
34296864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        BubbleTextView oldIcon = mPressedOrFocusedIcon;
34396864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        mPressedOrFocusedIcon = icon;
34496864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        if (oldIcon != null) {
34596864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy            invalidateBubbleTextView(oldIcon);
34696864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        }
34796864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        if (mPressedOrFocusedIcon != null) {
34896864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy            invalidateBubbleTextView(mPressedOrFocusedIcon);
34996864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        }
35096864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy    }
35196864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy
35233945b21544bc98381df17726a3537c292d8c985Michael Jurka    void setIsDragOverlapping(boolean isDragOverlapping) {
35333945b21544bc98381df17726a3537c292d8c985Michael Jurka        if (mIsDragOverlapping != isDragOverlapping) {
35433945b21544bc98381df17726a3537c292d8c985Michael Jurka            mIsDragOverlapping = isDragOverlapping;
35533945b21544bc98381df17726a3537c292d8c985Michael Jurka            invalidate();
35633945b21544bc98381df17726a3537c292d8c985Michael Jurka        }
35733945b21544bc98381df17726a3537c292d8c985Michael Jurka    }
35833945b21544bc98381df17726a3537c292d8c985Michael Jurka
35933945b21544bc98381df17726a3537c292d8c985Michael Jurka    boolean getIsDragOverlapping() {
36033945b21544bc98381df17726a3537c292d8c985Michael Jurka        return mIsDragOverlapping;
36133945b21544bc98381df17726a3537c292d8c985Michael Jurka    }
36233945b21544bc98381df17726a3537c292d8c985Michael Jurka
363ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen    protected void setOverscrollTransformsDirty(boolean dirty) {
364ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen        mScrollingTransformsDirty = dirty;
365ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen    }
366ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen
367ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen    protected void resetOverscrollTransforms() {
368ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen        if (mScrollingTransformsDirty) {
369ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            setOverscrollTransformsDirty(false);
370ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            setTranslationX(0);
371ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            setRotationY(0);
372ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            // It doesn't matter if we pass true or false here, the important thing is that we
373ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            // pass 0, which results in the overscroll drawable not being drawn any more.
374ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            setOverScrollAmount(0, false);
375ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            setPivotX(getMeasuredWidth() / 2);
376ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            setPivotY(getMeasuredHeight() / 2);
377ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen        }
378ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen    }
379ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen
380a6abce8464b57ce91e8f083951ad263370fc2da8Romain Guy    @Override
3811262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy    protected void onDraw(Canvas canvas) {
3823e7c7634531302271270c8cf418abc959d621cbcMichael Jurka        // When we're large, we are either drawn in a "hover" state (ie when dragging an item to
3833e7c7634531302271270c8cf418abc959d621cbcMichael Jurka        // a neighboring page) or with just a normal background (if backgroundAlpha > 0.0f)
3843e7c7634531302271270c8cf418abc959d621cbcMichael Jurka        // When we're small, we are either drawn normally or in the "accepts drops" state (during
3853e7c7634531302271270c8cf418abc959d621cbcMichael Jurka        // a drag). However, we also drag the mini hover background *over* one of those two
3863e7c7634531302271270c8cf418abc959d621cbcMichael Jurka        // backgrounds
387b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung        if (mBackgroundAlpha > 0.0f) {
388f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen            Drawable bg;
38933945b21544bc98381df17726a3537c292d8c985Michael Jurka
39033945b21544bc98381df17726a3537c292d8c985Michael Jurka            if (mIsDragOverlapping) {
39133945b21544bc98381df17726a3537c292d8c985Michael Jurka                // In the mini case, we draw the active_glow bg *over* the active background
392bdf78559f223ac11e01e3311edd5a48a80383e1eMichael Jurka                bg = mActiveGlowBackground;
393f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen            } else {
394bdf78559f223ac11e01e3311edd5a48a80383e1eMichael Jurka                bg = mNormalBackground;
395f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen            }
39633945b21544bc98381df17726a3537c292d8c985Michael Jurka
39733945b21544bc98381df17726a3537c292d8c985Michael Jurka            bg.setAlpha((int) (mBackgroundAlpha * mBackgroundAlphaMultiplier * 255));
39833945b21544bc98381df17726a3537c292d8c985Michael Jurka            bg.setBounds(mBackgroundRect);
39933945b21544bc98381df17726a3537c292d8c985Michael Jurka            bg.draw(canvas);
400a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka        }
40131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
4028e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy        final Paint paint = mDragOutlinePaint;
4034be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        for (int i = 0; i < mDragOutlines.length; i++) {
404472b281d5cb4f5660df981a6c912266b9f5703feChet Haase            final float alpha = mDragOutlineAlphas[i];
4054be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            if (alpha > 0) {
406d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                final Rect r = mDragOutlines[i];
4074be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                final Bitmap b = (Bitmap) mDragOutlineAnims[i].getTag();
408472b281d5cb4f5660df981a6c912266b9f5703feChet Haase                paint.setAlpha((int)(alpha + .5f));
409d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                canvas.drawBitmap(b, null, r, paint);
410150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung            }
4116569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        }
41296864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy
41396864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        // We draw the pressed or focused BubbleTextView's background in CellLayout because it
41496864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        // requires an expanded clip rect (due to the glow's blur radius)
41596864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        if (mPressedOrFocusedIcon != null) {
41696864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy            final int padding = mPressedOrFocusedIcon.getPressedOrFocusedBackgroundPadding();
41796864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy            final Bitmap b = mPressedOrFocusedIcon.getPressedOrFocusedBackground();
41896864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy            if (b != null) {
41996864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy                canvas.drawBitmap(b,
4204b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                        mPressedOrFocusedIcon.getLeft() + getPaddingLeft() - padding,
4214b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                        mPressedOrFocusedIcon.getTop() + getPaddingTop() - padding,
42296864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy                        null);
42396864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy            }
42496864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        }
42569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
426482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (DEBUG_VISUALIZE_OCCUPIED) {
427482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            int[] pt = new int[2];
428482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            ColorDrawable cd = new ColorDrawable(Color.RED);
429482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            cd.setBounds(0, 0, 80, 80);
430482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            for (int i = 0; i < mCountX; i++) {
431482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                for (int j = 0; j < mCountY; j++) {
432482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    if (mOccupied[i][j]) {
433482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        cellToPoint(i, j, pt);
434482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        canvas.save();
435482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        canvas.translate(pt[0], pt[1]);
436482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        cd.draw(canvas);
437482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        canvas.restore();
438482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    }
439482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                }
440482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
441482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
442482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
443850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn        int previewOffset = FolderRingAnimator.sPreviewSize;
444850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn
44569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        // The folder outer / inner ring image(s)
44669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        for (int i = 0; i < mFolderOuterRings.size(); i++) {
44769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            FolderRingAnimator fra = mFolderOuterRings.get(i);
44869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
44969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            // Draw outer ring
45069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            Drawable d = FolderRingAnimator.sSharedOuterRingDrawable;
45169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            int width = (int) fra.getOuterRingSize();
45269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            int height = width;
45369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            cellToPoint(fra.mCellX, fra.mCellY, mTempLocation);
45469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
45569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            int centerX = mTempLocation[0] + mCellWidth / 2;
456850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn            int centerY = mTempLocation[1] + previewOffset / 2;
45769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
45869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            canvas.save();
45969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            canvas.translate(centerX - width / 2, centerY - height / 2);
46069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            d.setBounds(0, 0, width, height);
46169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            d.draw(canvas);
46269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            canvas.restore();
46369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
46469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            // Draw inner ring
46569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            d = FolderRingAnimator.sSharedInnerRingDrawable;
46669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            width = (int) fra.getInnerRingSize();
46769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            height = width;
46869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            cellToPoint(fra.mCellX, fra.mCellY, mTempLocation);
46969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
47069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            centerX = mTempLocation[0] + mCellWidth / 2;
471850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn            centerY = mTempLocation[1] + previewOffset / 2;
47269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            canvas.save();
47369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            canvas.translate(centerX - width / 2, centerY - width / 2);
47469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            d.setBounds(0, 0, width, height);
47569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            d.draw(canvas);
47669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            canvas.restore();
47769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        }
478c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen
479c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        if (mFolderLeaveBehindCell[0] >= 0 && mFolderLeaveBehindCell[1] >= 0) {
480c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            Drawable d = FolderIcon.sSharedFolderLeaveBehind;
481c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            int width = d.getIntrinsicWidth();
482c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            int height = d.getIntrinsicHeight();
483c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen
484c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            cellToPoint(mFolderLeaveBehindCell[0], mFolderLeaveBehindCell[1], mTempLocation);
485c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            int centerX = mTempLocation[0] + mCellWidth / 2;
486850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn            int centerY = mTempLocation[1] + previewOffset / 2;
487c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen
488c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            canvas.save();
489c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            canvas.translate(centerX - width / 2, centerY - width / 2);
490c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            d.setBounds(0, 0, width, height);
491c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            d.draw(canvas);
492c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            canvas.restore();
493c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        }
49469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen    }
49569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
496b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    @Override
497b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    protected void dispatchDraw(Canvas canvas) {
498b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        super.dispatchDraw(canvas);
499b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        if (mForegroundAlpha > 0) {
500b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen            mOverScrollForegroundDrawable.setBounds(mForegroundRect);
501b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen            Paint p = ((NinePatchDrawable) mOverScrollForegroundDrawable).getPaint();
5028a0bff5e35f63321178bbf777ec24d42544866b3Romain Guy            p.setXfermode(sAddBlendMode);
503b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen            mOverScrollForegroundDrawable.draw(canvas);
504b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen            p.setXfermode(null);
505b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        }
506b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    }
507b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen
50869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen    public void showFolderAccept(FolderRingAnimator fra) {
50969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        mFolderOuterRings.add(fra);
51069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen    }
51169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
51269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen    public void hideFolderAccept(FolderRingAnimator fra) {
51369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        if (mFolderOuterRings.contains(fra)) {
51469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            mFolderOuterRings.remove(fra);
51569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        }
51669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        invalidate();
5176569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    }
5186569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
519c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen    public void setFolderLeaveBehindCell(int x, int y) {
520c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        mFolderLeaveBehindCell[0] = x;
521c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        mFolderLeaveBehindCell[1] = y;
522c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        invalidate();
523c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen    }
524c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen
525c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen    public void clearFolderLeaveBehind() {
526c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        mFolderLeaveBehindCell[0] = -1;
527c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        mFolderLeaveBehindCell[1] = -1;
528c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        invalidate();
529c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen    }
530c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen
5316569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    @Override
532e6235dd225404239b55c459245543f3302326112Michael Jurka    public boolean shouldDelayChildPressedState() {
533e6235dd225404239b55c459245543f3302326112Michael Jurka        return false;
534e6235dd225404239b55c459245543f3302326112Michael Jurka    }
535e6235dd225404239b55c459245543f3302326112Michael Jurka
536e6235dd225404239b55c459245543f3302326112Michael Jurka    @Override
53783f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey    public void cancelLongPress() {
53883f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey        super.cancelLongPress();
53983f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey
54083f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey        // Cancel long press for all children
54183f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey        final int count = getChildCount();
54283f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey        for (int i = 0; i < count; i++) {
54383f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey            final View child = getChildAt(i);
54483f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey            child.cancelLongPress();
54583f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey        }
54683f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey    }
54783f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey
548dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    public void setOnInterceptTouchListener(View.OnTouchListener listener) {
549dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka        mInterceptTouchListener = listener;
550dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    }
551dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka
55231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    int getCountX() {
553d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        return mCountX;
55431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
55531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
55631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    int getCountY() {
557d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        return mCountY;
55831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
55931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
5600dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn    public void setIsHotseat(boolean isHotseat) {
5610dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn        mIsHotseat = isHotseat;
5620dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn    }
5630dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn
5640dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn    public boolean addViewToCellLayout(View child, int index, int childId, LayoutParams params,
565850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn            boolean markCells) {
566aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        final LayoutParams lp = params;
567aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
568de38e42fe89fd7490221427908cd97c51da21b44Andrew Flynn        // Hotseat icons - remove text
5690dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn        if (child instanceof BubbleTextView) {
5700dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn            BubbleTextView bubbleChild = (BubbleTextView) child;
5710dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn
572de38e42fe89fd7490221427908cd97c51da21b44Andrew Flynn            Resources res = getResources();
573de38e42fe89fd7490221427908cd97c51da21b44Andrew Flynn            if (mIsHotseat) {
574de38e42fe89fd7490221427908cd97c51da21b44Andrew Flynn                bubbleChild.setTextColor(res.getColor(android.R.color.transparent));
575de38e42fe89fd7490221427908cd97c51da21b44Andrew Flynn            } else {
576de38e42fe89fd7490221427908cd97c51da21b44Andrew Flynn                bubbleChild.setTextColor(res.getColor(R.color.workspace_icon_text_color));
5770dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn            }
5780dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn        }
5790dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn
58031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // Generate an id for each view, this assumes we have at most 256x256 cells
58131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // per workspace screen
582d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        if (lp.cellX >= 0 && lp.cellX <= mCountX - 1 && lp.cellY >= 0 && lp.cellY <= mCountY - 1) {
583aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            // If the horizontal or vertical span is set to -1, it is taken to
584aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            // mean that it spans the extent of the CellLayout
585d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen            if (lp.cellHSpan < 0) lp.cellHSpan = mCountX;
586d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen            if (lp.cellVSpan < 0) lp.cellVSpan = mCountY;
587aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
588aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            child.setId(childId);
58931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
590a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            mShortcutsAndWidgets.addView(child, index, lp);
591dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka
592f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka            if (markCells) markCellsAsOccupiedForView(child);
5930280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
594aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            return true;
595aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        }
596aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        return false;
59731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
5983e7c7634531302271270c8cf418abc959d621cbcMichael Jurka
59931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
6000280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public void removeAllViews() {
6010280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        clearOccupiedCells();
602a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.removeAllViews();
6030280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
6040280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
6050280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    @Override
6060280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public void removeAllViewsInLayout() {
607a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        if (mShortcutsAndWidgets.getChildCount() > 0) {
6087cfc2825c3a1029f962d2fc387ae2eaa85b51798Michael Jurka            clearOccupiedCells();
609a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            mShortcutsAndWidgets.removeAllViewsInLayout();
6107cfc2825c3a1029f962d2fc387ae2eaa85b51798Michael Jurka        }
6110280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
6120280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
613f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka    public void removeViewWithoutMarkingCells(View view) {
614a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.removeView(view);
615f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka    }
616f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka
6170280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    @Override
6180280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public void removeView(View view) {
6190280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        markCellsAsUnoccupiedForView(view);
620a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.removeView(view);
6210280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
6220280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
6230280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    @Override
6240280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public void removeViewAt(int index) {
625a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        markCellsAsUnoccupiedForView(mShortcutsAndWidgets.getChildAt(index));
626a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.removeViewAt(index);
6270280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
6280280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
6290280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    @Override
6300280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public void removeViewInLayout(View view) {
6310280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        markCellsAsUnoccupiedForView(view);
632a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.removeViewInLayout(view);
6330280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
6340280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
6350280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    @Override
6360280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public void removeViews(int start, int count) {
6370280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        for (int i = start; i < start + count; i++) {
638a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            markCellsAsUnoccupiedForView(mShortcutsAndWidgets.getChildAt(i));
6390280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        }
640a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.removeViews(start, count);
6410280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
6420280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
6430280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    @Override
6440280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public void removeViewsInLayout(int start, int count) {
6450280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        for (int i = start; i < start + count; i++) {
646a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            markCellsAsUnoccupiedForView(mShortcutsAndWidgets.getChildAt(i));
6470280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        }
648a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.removeViewsInLayout(start, count);
649abded66084680bb31cc7ea403c88f44f79a3c884Michael Jurka    }
650abded66084680bb31cc7ea403c88f44f79a3c884Michael Jurka
65131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
65231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    protected void onAttachedToWindow() {
65331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        super.onAttachedToWindow();
65431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        mCellInfo.screen = ((ViewGroup) getParent()).indexOfChild(this);
65531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
65631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
657af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka    public void setTagToCellInfoForPoint(int touchX, int touchY) {
65831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        final CellInfo cellInfo = mCellInfo;
659eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung        Rect frame = mRect;
6608b805b17158886035b38261eb611d8641701ae43Michael Jurka        final int x = touchX + getScrollX();
6618b805b17158886035b38261eb611d8641701ae43Michael Jurka        final int y = touchY + getScrollY();
662a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        final int count = mShortcutsAndWidgets.getChildCount();
66331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
664af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka        boolean found = false;
665af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka        for (int i = count - 1; i >= 0; i--) {
666a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            final View child = mShortcutsAndWidgets.getChildAt(i);
667d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
668af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka
6691b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen            if ((child.getVisibility() == VISIBLE || child.getAnimation() != null) &&
6701b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen                    lp.isLockedToGrid) {
671af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                child.getHitRect(frame);
6720be025d64c1f84138fe430a58875886e66aae767Winson Chung
673eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                float scale = child.getScaleX();
674eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                frame = new Rect(child.getLeft(), child.getTop(), child.getRight(),
675eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                        child.getBottom());
6760be025d64c1f84138fe430a58875886e66aae767Winson Chung                // The child hit rect is relative to the CellLayoutChildren parent, so we need to
6770be025d64c1f84138fe430a58875886e66aae767Winson Chung                // offset that by this CellLayout's padding to test an (x,y) point that is relative
6780be025d64c1f84138fe430a58875886e66aae767Winson Chung                // to this view.
6798b805b17158886035b38261eb611d8641701ae43Michael Jurka                frame.offset(getPaddingLeft(), getPaddingTop());
680eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                frame.inset((int) (frame.width() * (1f - scale) / 2),
681eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                        (int) (frame.height() * (1f - scale) / 2));
6820be025d64c1f84138fe430a58875886e66aae767Winson Chung
683af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                if (frame.contains(x, y)) {
684af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                    cellInfo.cell = child;
685af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                    cellInfo.cellX = lp.cellX;
686af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                    cellInfo.cellY = lp.cellY;
687af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                    cellInfo.spanX = lp.cellHSpan;
688af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                    cellInfo.spanY = lp.cellVSpan;
689af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                    found = true;
690af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                    break;
69131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                }
69231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            }
693af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka        }
694aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
695d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka        mLastDownOnOccupiedCell = found;
696d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka
697af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka        if (!found) {
6980be025d64c1f84138fe430a58875886e66aae767Winson Chung            final int cellXY[] = mTmpXY;
699af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka            pointToCellExact(x, y, cellXY);
70031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
701af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka            cellInfo.cell = null;
702af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka            cellInfo.cellX = cellXY[0];
703af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka            cellInfo.cellY = cellXY[1];
704af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka            cellInfo.spanX = 1;
705af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka            cellInfo.spanY = 1;
706af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka        }
707af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka        setTag(cellInfo);
708af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka    }
70931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
710af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka    @Override
711af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka    public boolean onInterceptTouchEvent(MotionEvent ev) {
712c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        // First we clear the tag to ensure that on every touch down we start with a fresh slate,
713c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        // even in the case where we return early. Not clearing here was causing bugs whereby on
714c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        // long-press we'd end up picking up an item from a previous drag operation.
715c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        final int action = ev.getAction();
716c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen
717c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        if (action == MotionEvent.ACTION_DOWN) {
718c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen            clearTagCellInfo();
719c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        }
720c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen
721dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka        if (mInterceptTouchListener != null && mInterceptTouchListener.onTouch(this, ev)) {
722dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka            return true;
723dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka        }
72431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
725af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka        if (action == MotionEvent.ACTION_DOWN) {
726af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka            setTagToCellInfoForPoint((int) ev.getX(), (int) ev.getY());
72731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
728eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung
72931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        return false;
73031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
73131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
732c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen    private void clearTagCellInfo() {
733c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        final CellInfo cellInfo = mCellInfo;
734c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        cellInfo.cell = null;
735c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        cellInfo.cellX = -1;
736c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        cellInfo.cellY = -1;
737c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        cellInfo.spanX = 0;
738c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        cellInfo.spanY = 0;
739c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        setTag(cellInfo);
740c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen    }
741c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen
74231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public CellInfo getTag() {
7430280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        return (CellInfo) super.getTag();
74431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
74531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
7466569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    /**
747aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     * Given a point, return the cell that strictly encloses that point
74831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param x X coordinate of the point
74931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param y Y coordinate of the point
75031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param result Array of 2 ints to hold the x and y coordinate of the cell
75131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
75231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    void pointToCellExact(int x, int y, int[] result) {
7534b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int hStartPadding = getPaddingLeft();
7544b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int vStartPadding = getPaddingTop();
75531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
75631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        result[0] = (x - hStartPadding) / (mCellWidth + mWidthGap);
75731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        result[1] = (y - vStartPadding) / (mCellHeight + mHeightGap);
75831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
759d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        final int xAxis = mCountX;
760d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        final int yAxis = mCountY;
76131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
76231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        if (result[0] < 0) result[0] = 0;
76331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        if (result[0] >= xAxis) result[0] = xAxis - 1;
76431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        if (result[1] < 0) result[1] = 0;
76531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        if (result[1] >= yAxis) result[1] = yAxis - 1;
76631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
767aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
76831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
76931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * Given a point, return the cell that most closely encloses that point
77031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param x X coordinate of the point
77131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param y Y coordinate of the point
77231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param result Array of 2 ints to hold the x and y coordinate of the cell
77331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
77431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    void pointToCellRounded(int x, int y, int[] result) {
77531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        pointToCellExact(x + (mCellWidth / 2), y + (mCellHeight / 2), result);
77631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
77731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
77831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
77931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * Given a cell coordinate, return the point that represents the upper left corner of that cell
780aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     *
781aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     * @param cellX X coordinate of the cell
78231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param cellY Y coordinate of the cell
783aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     *
78431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param result Array of 2 ints to hold the x and y coordinate of the point
78531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
78631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    void cellToPoint(int cellX, int cellY, int[] result) {
7874b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int hStartPadding = getPaddingLeft();
7884b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int vStartPadding = getPaddingTop();
78931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
79031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        result[0] = hStartPadding + cellX * (mCellWidth + mWidthGap);
79131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        result[1] = vStartPadding + cellY * (mCellHeight + mHeightGap);
79231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
79331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
794e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen    /**
795482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * Given a cell coordinate, return the point that represents the center of the cell
796e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen     *
797e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen     * @param cellX X coordinate of the cell
798e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen     * @param cellY Y coordinate of the cell
799e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen     *
800e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen     * @param result Array of 2 ints to hold the x and y coordinate of the point
801e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen     */
802e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen    void cellToCenterPoint(int cellX, int cellY, int[] result) {
80347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        regionToCenterPoint(cellX, cellY, 1, 1, result);
80447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    }
80547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
80647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    /**
80747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * Given a cell coordinate and span return the point that represents the center of the regio
80847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     *
80947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param cellX X coordinate of the cell
81047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param cellY Y coordinate of the cell
81147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     *
81247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param result Array of 2 ints to hold the x and y coordinate of the point
81347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     */
81447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    void regionToCenterPoint(int cellX, int cellY, int spanX, int spanY, int[] result) {
8154b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int hStartPadding = getPaddingLeft();
8164b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int vStartPadding = getPaddingTop();
81747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        result[0] = hStartPadding + cellX * (mCellWidth + mWidthGap) +
81847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                (spanX * mCellWidth + (spanX - 1) * mWidthGap) / 2;
81947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        result[1] = vStartPadding + cellY * (mCellHeight + mHeightGap) +
82047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                (spanY * mCellHeight + (spanY - 1) * mHeightGap) / 2;
821e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen    }
822e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen
82319f3792523fe2d55ea791a9286398a6120920690Adam Cohen     /**
82419f3792523fe2d55ea791a9286398a6120920690Adam Cohen     * Given a cell coordinate and span fills out a corresponding pixel rect
82519f3792523fe2d55ea791a9286398a6120920690Adam Cohen     *
82619f3792523fe2d55ea791a9286398a6120920690Adam Cohen     * @param cellX X coordinate of the cell
82719f3792523fe2d55ea791a9286398a6120920690Adam Cohen     * @param cellY Y coordinate of the cell
82819f3792523fe2d55ea791a9286398a6120920690Adam Cohen     * @param result Rect in which to write the result
82919f3792523fe2d55ea791a9286398a6120920690Adam Cohen     */
83019f3792523fe2d55ea791a9286398a6120920690Adam Cohen     void regionToRect(int cellX, int cellY, int spanX, int spanY, Rect result) {
83119f3792523fe2d55ea791a9286398a6120920690Adam Cohen        final int hStartPadding = getPaddingLeft();
83219f3792523fe2d55ea791a9286398a6120920690Adam Cohen        final int vStartPadding = getPaddingTop();
83319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        final int left = hStartPadding + cellX * (mCellWidth + mWidthGap);
83419f3792523fe2d55ea791a9286398a6120920690Adam Cohen        final int top = vStartPadding + cellY * (mCellHeight + mHeightGap);
83519f3792523fe2d55ea791a9286398a6120920690Adam Cohen        result.set(left, top, left + (spanX * mCellWidth + (spanX - 1) * mWidthGap),
83619f3792523fe2d55ea791a9286398a6120920690Adam Cohen                top + (spanY * mCellHeight + (spanY - 1) * mHeightGap));
83719f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
83819f3792523fe2d55ea791a9286398a6120920690Adam Cohen
839482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public float getDistanceFromCell(float x, float y, int[] cell) {
840482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        cellToCenterPoint(cell[0], cell[1], mTmpPoint);
841482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        float distance = (float) Math.sqrt( Math.pow(x - mTmpPoint[0], 2) +
842482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                Math.pow(y - mTmpPoint[1], 2));
843482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return distance;
844482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
845482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
84684f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy    int getCellWidth() {
84784f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy        return mCellWidth;
84884f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy    }
84984f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy
85084f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy    int getCellHeight() {
85184f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy        return mCellHeight;
85284f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy    }
85384f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy
854d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    int getWidthGap() {
855d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        return mWidthGap;
856d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    }
857d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
858d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    int getHeightGap() {
859d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        return mHeightGap;
860d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    }
861d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
8627f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen    Rect getContentRect(Rect r) {
8637f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        if (r == null) {
8647f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            r = new Rect();
8657f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
8667f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        int left = getPaddingLeft();
8677f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        int top = getPaddingTop();
8688b805b17158886035b38261eb611d8641701ae43Michael Jurka        int right = left + getWidth() - getPaddingLeft() - getPaddingRight();
8698b805b17158886035b38261eb611d8641701ae43Michael Jurka        int bottom = top + getHeight() - getPaddingTop() - getPaddingBottom();
8707f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        r.set(left, top, right, bottom);
8717f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        return r;
8727f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen    }
8737f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
874a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen    static void getMetrics(Rect metrics, Resources res, int measureWidth, int measureHeight,
875a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen            int countX, int countY, int orientation) {
876a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen        int numWidthGaps = countX - 1;
877a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen        int numHeightGaps = countY - 1;
878f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen
879f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        int widthGap;
880f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        int heightGap;
881f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        int cellWidth;
882f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        int cellHeight;
883f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        int paddingLeft;
884f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        int paddingRight;
885f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        int paddingTop;
886f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        int paddingBottom;
887f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen
888a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen        int maxGap = res.getDimensionPixelSize(R.dimen.workspace_max_gap);
889f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        if (orientation == LANDSCAPE) {
890f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            cellWidth = res.getDimensionPixelSize(R.dimen.workspace_cell_width_land);
891f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            cellHeight = res.getDimensionPixelSize(R.dimen.workspace_cell_height_land);
892f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            widthGap = res.getDimensionPixelSize(R.dimen.workspace_width_gap_land);
893f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            heightGap = res.getDimensionPixelSize(R.dimen.workspace_height_gap_land);
894f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            paddingLeft = res.getDimensionPixelSize(R.dimen.cell_layout_left_padding_land);
895f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            paddingRight = res.getDimensionPixelSize(R.dimen.cell_layout_right_padding_land);
896f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            paddingTop = res.getDimensionPixelSize(R.dimen.cell_layout_top_padding_land);
897f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            paddingBottom = res.getDimensionPixelSize(R.dimen.cell_layout_bottom_padding_land);
898f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        } else {
899f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            // PORTRAIT
900f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            cellWidth = res.getDimensionPixelSize(R.dimen.workspace_cell_width_port);
901f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            cellHeight = res.getDimensionPixelSize(R.dimen.workspace_cell_height_port);
902f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            widthGap = res.getDimensionPixelSize(R.dimen.workspace_width_gap_port);
903f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            heightGap = res.getDimensionPixelSize(R.dimen.workspace_height_gap_port);
904f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            paddingLeft = res.getDimensionPixelSize(R.dimen.cell_layout_left_padding_port);
905f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            paddingRight = res.getDimensionPixelSize(R.dimen.cell_layout_right_padding_port);
906f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            paddingTop = res.getDimensionPixelSize(R.dimen.cell_layout_top_padding_port);
907f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            paddingBottom = res.getDimensionPixelSize(R.dimen.cell_layout_bottom_padding_port);
908f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        }
909f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen
910f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        if (widthGap < 0 || heightGap < 0) {
911f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            int hSpace = measureWidth - paddingLeft - paddingRight;
912f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            int vSpace = measureHeight - paddingTop - paddingBottom;
913a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen            int hFreeSpace = hSpace - (countX * cellWidth);
914a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen            int vFreeSpace = vSpace - (countY * cellHeight);
915a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen            widthGap = Math.min(maxGap, numWidthGaps > 0 ? (hFreeSpace / numWidthGaps) : 0);
916a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen            heightGap = Math.min(maxGap, numHeightGaps > 0 ? (vFreeSpace / numHeightGaps) : 0);
917f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        }
918f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        metrics.set(cellWidth, cellHeight, widthGap, heightGap);
919f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen    }
920f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen
92131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
92231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
92331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
924aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
925aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
92631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
92731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int heightSpecSize =  MeasureSpec.getSize(heightMeasureSpec);
928aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
92931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        if (widthSpecMode == MeasureSpec.UNSPECIFIED || heightSpecMode == MeasureSpec.UNSPECIFIED) {
93031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            throw new RuntimeException("CellLayout cannot have UNSPECIFIED dimensions");
93131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
93231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
933d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        int numWidthGaps = mCountX - 1;
934d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        int numHeightGaps = mCountY - 1;
935d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen
936234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen        if (mOriginalWidthGap < 0 || mOriginalHeightGap < 0) {
937dd13e3d0f9925b7bb80c37e21d039aab4fa7e7a1Michael Jurka            int hSpace = widthSpecSize - getPaddingLeft() - getPaddingRight();
938dd13e3d0f9925b7bb80c37e21d039aab4fa7e7a1Michael Jurka            int vSpace = heightSpecSize - getPaddingTop() - getPaddingBottom();
939f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            int hFreeSpace = hSpace - (mCountX * mCellWidth);
940f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            int vFreeSpace = vSpace - (mCountY * mCellHeight);
9414b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung            mWidthGap = Math.min(mMaxGap, numWidthGaps > 0 ? (hFreeSpace / numWidthGaps) : 0);
9424b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung            mHeightGap = Math.min(mMaxGap,numHeightGaps > 0 ? (vFreeSpace / numHeightGaps) : 0);
943a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            mShortcutsAndWidgets.setCellDimensions(mCellWidth, mCellHeight, mWidthGap, mHeightGap);
944234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen        } else {
945234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen            mWidthGap = mOriginalWidthGap;
946234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen            mHeightGap = mOriginalHeightGap;
947ece7f5b3b55cab646941123e03589241a61678e2Winson Chung        }
9485f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka
9498c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka        // Initial values correspond to widthSpecMode == MeasureSpec.EXACTLY
9508c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka        int newWidth = widthSpecSize;
9518c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka        int newHeight = heightSpecSize;
9528c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka        if (widthSpecMode == MeasureSpec.AT_MOST) {
9538b805b17158886035b38261eb611d8641701ae43Michael Jurka            newWidth = getPaddingLeft() + getPaddingRight() + (mCountX * mCellWidth) +
9548c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka                ((mCountX - 1) * mWidthGap);
9558b805b17158886035b38261eb611d8641701ae43Michael Jurka            newHeight = getPaddingTop() + getPaddingBottom() + (mCountY * mCellHeight) +
9568c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka                ((mCountY - 1) * mHeightGap);
9578c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka            setMeasuredDimension(newWidth, newHeight);
9588c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka        }
95931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
9608c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka        int count = getChildCount();
96131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        for (int i = 0; i < count; i++) {
96231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            View child = getChildAt(i);
9638b805b17158886035b38261eb611d8641701ae43Michael Jurka            int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(newWidth - getPaddingLeft() -
9648b805b17158886035b38261eb611d8641701ae43Michael Jurka                    getPaddingRight(), MeasureSpec.EXACTLY);
9658b805b17158886035b38261eb611d8641701ae43Michael Jurka            int childheightMeasureSpec = MeasureSpec.makeMeasureSpec(newHeight - getPaddingTop() -
9668b805b17158886035b38261eb611d8641701ae43Michael Jurka                    getPaddingBottom(), MeasureSpec.EXACTLY);
96731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            child.measure(childWidthMeasureSpec, childheightMeasureSpec);
96831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
9698c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka        setMeasuredDimension(newWidth, newHeight);
97031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
97131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
97231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
97328750fba6a2d141eb9a1e566718c17236030b815Michael Jurka    protected void onLayout(boolean changed, int l, int t, int r, int b) {
97431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int count = getChildCount();
97531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        for (int i = 0; i < count; i++) {
9768c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka            View child = getChildAt(i);
9778b805b17158886035b38261eb611d8641701ae43Michael Jurka            child.layout(getPaddingLeft(), getPaddingTop(),
9788b805b17158886035b38261eb611d8641701ae43Michael Jurka                    r - l - getPaddingRight(), b - t - getPaddingBottom());
97931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
98031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
98131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
98231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
983dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
984dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka        super.onSizeChanged(w, h, oldw, oldh);
98518014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka        mBackgroundRect.set(0, 0, w, h);
986b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        mForegroundRect.set(mForegroundPadding, mForegroundPadding,
987b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen                w - 2 * mForegroundPadding, h - 2 * mForegroundPadding);
988dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    }
989dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka
990dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    @Override
99131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    protected void setChildrenDrawingCacheEnabled(boolean enabled) {
992a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.setChildrenDrawingCacheEnabled(enabled);
99331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
99431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
99531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
99631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    protected void setChildrenDrawnWithCacheEnabled(boolean enabled) {
997a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.setChildrenDrawnWithCacheEnabled(enabled);
99831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
99931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
10005f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka    public float getBackgroundAlpha() {
10015f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka        return mBackgroundAlpha;
1002dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    }
1003dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka
10041b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen    public void setBackgroundAlphaMultiplier(float multiplier) {
1005a3d30adbfd4f013260f1f5ba3a56bc9bb4a11717Michael Jurka        if (mBackgroundAlphaMultiplier != multiplier) {
1006a3d30adbfd4f013260f1f5ba3a56bc9bb4a11717Michael Jurka            mBackgroundAlphaMultiplier = multiplier;
1007a3d30adbfd4f013260f1f5ba3a56bc9bb4a11717Michael Jurka            invalidate();
1008a3d30adbfd4f013260f1f5ba3a56bc9bb4a11717Michael Jurka        }
10091b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen    }
10101b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen
1011ddb821981e0919bbd3b4c9a2b6aa1811d6c86bb6Adam Cohen    public float getBackgroundAlphaMultiplier() {
1012ddb821981e0919bbd3b4c9a2b6aa1811d6c86bb6Adam Cohen        return mBackgroundAlphaMultiplier;
1013ddb821981e0919bbd3b4c9a2b6aa1811d6c86bb6Adam Cohen    }
1014ddb821981e0919bbd3b4c9a2b6aa1811d6c86bb6Adam Cohen
10155f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka    public void setBackgroundAlpha(float alpha) {
1016afaa05014e0bf3ed1192f9ddec2af4283bc50248Michael Jurka        if (mBackgroundAlpha != alpha) {
1017afaa05014e0bf3ed1192f9ddec2af4283bc50248Michael Jurka            mBackgroundAlpha = alpha;
1018afaa05014e0bf3ed1192f9ddec2af4283bc50248Michael Jurka            invalidate();
1019afaa05014e0bf3ed1192f9ddec2af4283bc50248Michael Jurka        }
1020dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    }
1021dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka
1022a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka    public void setShortcutAndWidgetAlpha(float alpha) {
10230142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka        final int childCount = getChildCount();
10240142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka        for (int i = 0; i < childCount; i++) {
1025dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka            getChildAt(i).setAlpha(alpha);
1026dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka        }
1027dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    }
1028dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka
1029a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka    public ShortcutAndWidgetContainer getShortcutsAndWidgets() {
1030a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        if (getChildCount() > 0) {
1031a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            return (ShortcutAndWidgetContainer) getChildAt(0);
1032a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        }
1033a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        return null;
1034a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka    }
1035a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka
1036440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy    public View getChildAt(int x, int y) {
1037a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        return mShortcutsAndWidgets.getChildAt(x, y);
1038440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy    }
1039440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy
104076fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    public boolean animateChildToPosition(final View child, int cellX, int cellY, int duration,
1041482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            int delay, boolean permanent, boolean adjustOccupied) {
1042a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        ShortcutAndWidgetContainer clc = getShortcutsAndWidgets();
1043482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        boolean[][] occupied = mOccupied;
1044482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (!permanent) {
1045482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            occupied = mTmpOccupied;
1046482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1047482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
104819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if (clc.indexOfChild(child) != -1) {
1049bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
1050bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            final ItemInfo info = (ItemInfo) child.getTag();
1051bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen
1052bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            // We cancel any existing animations
1053bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            if (mReorderAnimators.containsKey(lp)) {
1054bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                mReorderAnimators.get(lp).cancel();
1055bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                mReorderAnimators.remove(lp);
1056bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            }
1057bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen
1058482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            final int oldX = lp.x;
1059482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            final int oldY = lp.y;
1060482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (adjustOccupied) {
1061482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                occupied[lp.cellX][lp.cellY] = false;
1062482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                occupied[cellX][cellY] = true;
1063482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1064bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            lp.isLockedToGrid = true;
1065482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (permanent) {
1066482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                lp.cellX = info.cellX = cellX;
1067482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                lp.cellY = info.cellY = cellY;
1068482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            } else {
1069482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                lp.tmpCellX = cellX;
1070482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                lp.tmpCellY = cellY;
1071482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1072bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            clc.setupLp(lp);
1073bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            lp.isLockedToGrid = false;
1074482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            final int newX = lp.x;
1075482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            final int newY = lp.y;
1076bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen
107776fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen            lp.x = oldX;
107876fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen            lp.y = oldY;
107976fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
1080482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            // Exit early if we're not actually moving the view
1081482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (oldX == newX && oldY == newY) {
1082482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                lp.isLockedToGrid = true;
1083482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                return true;
1084482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1085482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1086482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
1087482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            va.setDuration(duration);
1088482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            mReorderAnimators.put(lp, va);
1089482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1090482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            va.addUpdateListener(new AnimatorUpdateListener() {
1091482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                @Override
1092bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                public void onAnimationUpdate(ValueAnimator animation) {
1093482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    float r = ((Float) animation.getAnimatedValue()).floatValue();
109419f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    lp.x = (int) ((1 - r) * oldX + r * newX);
109519f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    lp.y = (int) ((1 - r) * oldY + r * newY);
10966b8a02d63a5d9cab8209381993e37db6a6afb753Adam Cohen                    child.requestLayout();
1097bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                }
1098bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            });
1099482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            va.addListener(new AnimatorListenerAdapter() {
1100bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                boolean cancelled = false;
1101bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                public void onAnimationEnd(Animator animation) {
1102bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    // If the animation was cancelled, it means that another animation
1103bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    // has interrupted this one, and we don't want to lock the item into
1104bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    // place just yet.
1105bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    if (!cancelled) {
1106bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                        lp.isLockedToGrid = true;
1107482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        child.requestLayout();
1108bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    }
1109bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    if (mReorderAnimators.containsKey(lp)) {
1110bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                        mReorderAnimators.remove(lp);
1111bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    }
1112bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                }
1113bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                public void onAnimationCancel(Animator animation) {
1114bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    cancelled = true;
1115bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                }
1116bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            });
1117482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            va.setStartDelay(delay);
1118482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            va.start();
1119bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            return true;
1120bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        }
1121bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        return false;
1122bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    }
1123bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen
11246569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    /**
11256569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     * Estimate where the top left cell of the dragged item will land if it is dropped.
11266569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     *
11276569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     * @param originX The X value of the top left corner of the item
11286569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     * @param originY The Y value of the top left corner of the item
11296569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     * @param spanX The number of horizontal cells that the item spans
11306569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     * @param spanY The number of vertical cells that the item spans
11316569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     * @param result The estimated drop cell X and Y.
11326569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     */
11336569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    void estimateDropCell(int originX, int originY, int spanX, int spanY, int[] result) {
1134d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        final int countX = mCountX;
1135d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        final int countY = mCountY;
11366569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
1137a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka        // pointToCellRounded takes the top left of a cell but will pad that with
1138a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka        // cellWidth/2 and cellHeight/2 when finding the matching cell
1139a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka        pointToCellRounded(originX, originY, result);
11406569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
11416569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        // If the item isn't fully on this screen, snap to the edges
11426569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        int rightOverhang = result[0] + spanX - countX;
11436569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        if (rightOverhang > 0) {
11446569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy            result[0] -= rightOverhang; // Snap to right
11456569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        }
11466569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        result[0] = Math.max(0, result[0]); // Snap to left
11476569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        int bottomOverhang = result[1] + spanY - countY;
11486569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        if (bottomOverhang > 0) {
11496569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy            result[1] -= bottomOverhang; // Snap to bottom
11506569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        }
11516569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        result[1] = Math.max(0, result[1]); // Snap to top
11526569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    }
11536569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
1154482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    void visualizeDropLocation(View v, Bitmap dragOutline, int originX, int originY, int cellX,
1155482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            int cellY, int spanX, int spanY, boolean resize, Point dragOffset, Rect dragRegion) {
115608ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy        final int oldDragCellX = mDragCell[0];
115708ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy        final int oldDragCellY = mDragCell[1];
1158482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1159b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung        if (v != null && dragOffset == null) {
1160a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung            mDragCenter.set(originX + (v.getWidth() / 2), originY + (v.getHeight() / 2));
1161a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung        } else {
1162a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung            mDragCenter.set(originX, originY);
1163a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung        }
11646569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
11652801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        if (dragOutline == null && v == null) {
11662801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            return;
11672801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        }
11682801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
1169482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (cellX != oldDragCellX || cellY != oldDragCellY) {
1170482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            mDragCell[0] = cellX;
1171482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            mDragCell[1] = cellY;
11726569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy            // Find the top left corner of the rect the object will occupy
1173de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy            final int[] topLeft = mTmpPoint;
1174482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            cellToPoint(cellX, cellY, topLeft);
1175de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy
11764be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            int left = topLeft[0];
11774be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            int top = topLeft[1];
11786569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
1179b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung            if (v != null && dragOffset == null) {
118099e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                // When drawing the drag outline, it did not account for margin offsets
118199e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                // added by the view's parent.
118299e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                MarginLayoutParams lp = (MarginLayoutParams) v.getLayoutParams();
118399e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                left += lp.leftMargin;
118499e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                top += lp.topMargin;
118599e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen
118699e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                // Offsets due to the size difference between the View and the dragOutline.
118799e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                // There is a size difference to account for the outer blur, which may lie
118899e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                // outside the bounds of the view.
1189a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung                top += (v.getHeight() - dragOutline.getHeight()) / 2;
1190ae915cecd36af4973061a1cb0b58c5be1be699a0Adam Cohen                // We center about the x axis
1191ae915cecd36af4973061a1cb0b58c5be1be699a0Adam Cohen                left += ((mCellWidth * spanX) + ((spanX - 1) * mWidthGap)
1192ae915cecd36af4973061a1cb0b58c5be1be699a0Adam Cohen                        - dragOutline.getWidth()) / 2;
11936639687cd67bab1aeef2a75e5c6bc458b20dc082Adam Cohen            } else {
1194b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                if (dragOffset != null && dragRegion != null) {
1195b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                    // Center the drag region *horizontally* in the cell and apply a drag
1196b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                    // outline offset
1197b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                    left += dragOffset.x + ((mCellWidth * spanX) + ((spanX - 1) * mWidthGap)
1198b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                             - dragRegion.width()) / 2;
1199b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                    top += dragOffset.y;
1200b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                } else {
1201b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                    // Center the drag outline in the cell
1202b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                    left += ((mCellWidth * spanX) + ((spanX - 1) * mWidthGap)
1203b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                            - dragOutline.getWidth()) / 2;
1204b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                    top += ((mCellHeight * spanY) + ((spanY - 1) * mHeightGap)
1205b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                            - dragOutline.getHeight()) / 2;
1206b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                }
1207a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung            }
12084be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            final int oldIndex = mDragOutlineCurrent;
120908ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy            mDragOutlineAnims[oldIndex].animateOut();
121008ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy            mDragOutlineCurrent = (oldIndex + 1) % mDragOutlines.length;
1211d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            Rect r = mDragOutlines[mDragOutlineCurrent];
1212d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            r.set(left, top, left + dragOutline.getWidth(), top + dragOutline.getHeight());
1213d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            if (resize) {
1214482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                cellToRect(cellX, cellY, spanX, spanY, r);
1215d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            }
1216150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung
121708ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy            mDragOutlineAnims[mDragOutlineCurrent].setTag(dragOutline);
121808ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy            mDragOutlineAnims[mDragOutlineCurrent].animateIn();
12196569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        }
12206569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    }
12216569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
1222e0310965022e7a1adb7ad489505d404186608689Adam Cohen    public void clearDragOutlines() {
1223e0310965022e7a1adb7ad489505d404186608689Adam Cohen        final int oldIndex = mDragOutlineCurrent;
1224e0310965022e7a1adb7ad489505d404186608689Adam Cohen        mDragOutlineAnims[oldIndex].animateOut();
1225d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        mDragCell[0] = mDragCell[1] = -1;
1226e0310965022e7a1adb7ad489505d404186608689Adam Cohen    }
1227e0310965022e7a1adb7ad489505d404186608689Adam Cohen
122831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
122970864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey     * Find a vacant area that will fit the given bounds nearest the requested
123070864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey     * cell location. Uses Euclidean distance to score multiple vacant areas.
1231aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     *
123251afc022fa76c79f0d1ece470ddc126c08fea8a4Romain Guy     * @param pixelX The X location at which you want to search for a vacant area.
123351afc022fa76c79f0d1ece470ddc126c08fea8a4Romain Guy     * @param pixelY The Y location at which you want to search for a vacant area.
123470864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey     * @param spanX Horizontal span of the object.
123570864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey     * @param spanY Vertical span of the object.
1236de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy     * @param result Array in which to place the result, or null (in which case a new array will
1237de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy     *        be allocated)
123870864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey     * @return The X, Y cell of a vacant area that can contain this object,
123970864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey     *         nearest the requested location.
124031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
1241d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    int[] findNearestVacantArea(int pixelX, int pixelY, int spanX, int spanY,
1242d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            int[] result) {
1243de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy        return findNearestVacantArea(pixelX, pixelY, spanX, spanY, null, result);
12446a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka    }
1245aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
12466a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka    /**
12476a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     * Find a vacant area that will fit the given bounds nearest the requested
12486a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     * cell location. Uses Euclidean distance to score multiple vacant areas.
12496a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     *
12506a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     * @param pixelX The X location at which you want to search for a vacant area.
12516a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     * @param pixelY The Y location at which you want to search for a vacant area.
1252d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param minSpanX The minimum horizontal span required
1253d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param minSpanY The minimum vertical span required
1254d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param spanX Horizontal span of the object.
1255d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param spanY Vertical span of the object.
1256d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param result Array in which to place the result, or null (in which case a new array will
1257d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *        be allocated)
1258d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @return The X, Y cell of a vacant area that can contain this object,
1259d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *         nearest the requested location.
1260d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     */
1261d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    int[] findNearestVacantArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX,
1262d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            int spanY, int[] result, int[] resultSpan) {
1263d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        return findNearestVacantArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, null,
1264d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                result, resultSpan);
1265d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    }
1266d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen
1267d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    /**
1268d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * Find a vacant area that will fit the given bounds nearest the requested
1269d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * cell location. Uses Euclidean distance to score multiple vacant areas.
1270d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *
1271d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param pixelX The X location at which you want to search for a vacant area.
1272d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param pixelY The Y location at which you want to search for a vacant area.
12736a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     * @param spanX Horizontal span of the object.
12746a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     * @param spanY Vertical span of the object.
1275df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param ignoreOccupied If true, the result can be an occupied cell
1276df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param result Array in which to place the result, or null (in which case a new array will
1277df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     *        be allocated)
12786a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     * @return The X, Y cell of a vacant area that can contain this object,
12796a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     *         nearest the requested location.
12806a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     */
1281df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    int[] findNearestArea(int pixelX, int pixelY, int spanX, int spanY, View ignoreView,
1282df0353815c629fc678824b07a234b89a1ff94208Adam Cohen            boolean ignoreOccupied, int[] result) {
1283d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        return findNearestArea(pixelX, pixelY, spanX, spanY,
1284482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                spanX, spanY, ignoreView, ignoreOccupied, result, null, mOccupied);
1285d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    }
1286d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen
1287d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    private final Stack<Rect> mTempRectStack = new Stack<Rect>();
1288d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    private void lazyInitTempRectStack() {
1289d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        if (mTempRectStack.isEmpty()) {
1290d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            for (int i = 0; i < mCountX * mCountY; i++) {
1291d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                mTempRectStack.push(new Rect());
1292d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            }
1293d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        }
1294d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    }
1295482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1296d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    private void recycleTempRects(Stack<Rect> used) {
1297d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        while (!used.isEmpty()) {
1298d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            mTempRectStack.push(used.pop());
1299d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        }
1300d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    }
1301d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen
1302d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    /**
1303d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * Find a vacant area that will fit the given bounds nearest the requested
1304d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * cell location. Uses Euclidean distance to score multiple vacant areas.
1305d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *
1306d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param pixelX The X location at which you want to search for a vacant area.
1307d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param pixelY The Y location at which you want to search for a vacant area.
1308d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param minSpanX The minimum horizontal span required
1309d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param minSpanY The minimum vertical span required
1310d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param spanX Horizontal span of the object.
1311d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param spanY Vertical span of the object.
1312d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param ignoreOccupied If true, the result can be an occupied cell
1313d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param result Array in which to place the result, or null (in which case a new array will
1314d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *        be allocated)
1315d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @return The X, Y cell of a vacant area that can contain this object,
1316d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *         nearest the requested location.
1317d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     */
1318d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    int[] findNearestArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, int spanY,
1319482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            View ignoreView, boolean ignoreOccupied, int[] result, int[] resultSpan,
1320482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            boolean[][] occupied) {
1321d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        lazyInitTempRectStack();
1322c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka        // mark space take by ignoreView as available (method checks if ignoreView is null)
1323482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsAsUnoccupiedForView(ignoreView, occupied);
1324c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka
1325e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        // For items with a spanX / spanY > 1, the passed in point (pixelX, pixelY) corresponds
1326e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        // to the center of the item, but we are searching based on the top-left cell, so
1327e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        // we translate the point over to correspond to the top-left.
1328e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        pixelX -= (mCellWidth + mWidthGap) * (spanX - 1) / 2f;
1329e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        pixelY -= (mCellHeight + mHeightGap) * (spanY - 1) / 2f;
1330e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen
133170864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey        // Keep track of best-scoring drop area
1332de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy        final int[] bestXY = result != null ? result : new int[2];
133370864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey        double bestDistance = Double.MAX_VALUE;
1334d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        final Rect bestRect = new Rect(-1, -1, -1, -1);
1335d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        final Stack<Rect> validRegions = new Stack<Rect>();
1336aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
1337de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy        final int countX = mCountX;
1338de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy        final int countY = mCountY;
1339de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy
1340d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        if (minSpanX <= 0 || minSpanY <= 0 || spanX <= 0 || spanY <= 0 ||
1341d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                spanX < minSpanX || spanY < minSpanY) {
1342d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            return bestXY;
1343d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        }
1344d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen
1345d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        for (int y = 0; y < countY - (minSpanY - 1); y++) {
1346c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka            inner:
1347d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            for (int x = 0; x < countX - (minSpanX - 1); x++) {
1348d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                int ySize = -1;
1349d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                int xSize = -1;
1350df0353815c629fc678824b07a234b89a1ff94208Adam Cohen                if (ignoreOccupied) {
1351d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    // First, let's see if this thing fits anywhere
1352d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    for (int i = 0; i < minSpanX; i++) {
1353d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        for (int j = 0; j < minSpanY; j++) {
1354df0353815c629fc678824b07a234b89a1ff94208Adam Cohen                            if (occupied[x + i][y + j]) {
1355df0353815c629fc678824b07a234b89a1ff94208Adam Cohen                                continue inner;
1356df0353815c629fc678824b07a234b89a1ff94208Adam Cohen                            }
1357c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                        }
1358c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                    }
1359d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    xSize = minSpanX;
1360d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    ySize = minSpanY;
1361d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen
1362d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    // We know that the item will fit at _some_ acceptable size, now let's see
1363d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    // how big we can make it. We'll alternate between incrementing x and y spans
1364d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    // until we hit a limit.
1365d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    boolean incX = true;
1366d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    boolean hitMaxX = xSize >= spanX;
1367d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    boolean hitMaxY = ySize >= spanY;
1368d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    while (!(hitMaxX && hitMaxY)) {
1369d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        if (incX && !hitMaxX) {
1370d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            for (int j = 0; j < ySize; j++) {
1371d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                if (x + xSize > countX -1 || occupied[x + xSize][y + j]) {
1372d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                    // We can't move out horizontally
1373d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                    hitMaxX = true;
1374d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                }
1375d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            }
1376d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            if (!hitMaxX) {
1377d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                xSize++;
1378d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            }
1379d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        } else if (!hitMaxY) {
1380d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            for (int i = 0; i < xSize; i++) {
1381d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                if (y + ySize > countY - 1 || occupied[x + i][y + ySize]) {
1382d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                    // We can't move out vertically
1383d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                    hitMaxY = true;
1384d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                }
1385d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            }
1386d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            if (!hitMaxY) {
1387d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                ySize++;
1388d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            }
1389d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        }
1390d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        hitMaxX |= xSize >= spanX;
1391d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        hitMaxY |= ySize >= spanY;
1392d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        incX = !incX;
1393d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    }
1394d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    incX = true;
1395d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    hitMaxX = xSize >= spanX;
1396d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    hitMaxY = ySize >= spanY;
1397c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                }
13980be025d64c1f84138fe430a58875886e66aae767Winson Chung                final int[] cellXY = mTmpXY;
1399e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen                cellToCenterPoint(x, y, cellXY);
1400c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka
1401d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                // We verify that the current rect is not a sub-rect of any of our previous
1402d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                // candidates. In this case, the current rect is disqualified in favour of the
1403d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                // containing rect.
1404d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                Rect currentRect = mTempRectStack.pop();
1405d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                currentRect.set(x, y, x + xSize, y + ySize);
1406d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                boolean contained = false;
1407d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                for (Rect r : validRegions) {
1408d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    if (r.contains(currentRect)) {
1409d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        contained = true;
1410d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        break;
1411d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    }
1412d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                }
1413d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                validRegions.push(currentRect);
1414c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                double distance = Math.sqrt(Math.pow(cellXY[0] - pixelX, 2)
1415c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                        + Math.pow(cellXY[1] - pixelY, 2));
1416482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1417d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                if ((distance <= bestDistance && !contained) ||
1418d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        currentRect.contains(bestRect)) {
1419c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                    bestDistance = distance;
1420c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                    bestXY[0] = x;
1421c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                    bestXY[1] = y;
1422d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    if (resultSpan != null) {
1423d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        resultSpan[0] = xSize;
1424d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        resultSpan[1] = ySize;
1425d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    }
1426d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    bestRect.set(currentRect);
1427c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                }
142831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            }
142931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
1430c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka        // re-mark space taken by ignoreView as occupied
1431482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsAsOccupiedForView(ignoreView, occupied);
143231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
1433c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        // Return -1, -1 if no suitable location found
1434c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        if (bestDistance == Double.MAX_VALUE) {
1435c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            bestXY[0] = -1;
1436c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            bestXY[1] = -1;
143770864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey        }
1438d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        recycleTempRects(validRegions);
1439c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        return bestXY;
144031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
1441aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
1442482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     /**
1443482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * Find a vacant area that will fit the given bounds nearest the requested
1444482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * cell location, and will also weigh in a suggested direction vector of the
1445482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * desired location. This method computers distance based on unit grid distances,
1446482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * not pixel distances.
1447482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     *
144847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param cellX The X cell nearest to which you want to search for a vacant area.
144947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param cellY The Y cell nearest which you want to search for a vacant area.
1450482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * @param spanX Horizontal span of the object.
1451482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * @param spanY Vertical span of the object.
145247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param direction The favored direction in which the views should move from x, y
145347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param exactDirectionOnly If this parameter is true, then only solutions where the direction
145447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     *        matches exactly. Otherwise we find the best matching direction.
145547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param occoupied The array which represents which cells in the CellLayout are occupied
145647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param blockOccupied The array which represents which cells in the specified block (cellX,
145747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     *        cellY, spanX, spanY) are occupied. This is used when try to move a group of views.
1458482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * @param result Array in which to place the result, or null (in which case a new array will
1459482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     *        be allocated)
1460482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * @return The X, Y cell of a vacant area that can contain this object,
1461482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     *         nearest the requested location.
1462482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     */
1463482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private int[] findNearestArea(int cellX, int cellY, int spanX, int spanY, int[] direction,
146447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            boolean[][] occupied, boolean blockOccupied[][], int[] result) {
1465482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // Keep track of best-scoring drop area
1466482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        final int[] bestXY = result != null ? result : new int[2];
1467482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        float bestDistance = Float.MAX_VALUE;
1468482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        int bestDirectionScore = Integer.MIN_VALUE;
1469482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1470482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        final int countX = mCountX;
1471482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        final int countY = mCountY;
1472482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1473482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int y = 0; y < countY - (spanY - 1); y++) {
1474482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            inner:
1475482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            for (int x = 0; x < countX - (spanX - 1); x++) {
1476482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                // First, let's see if this thing fits anywhere
1477482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                for (int i = 0; i < spanX; i++) {
1478482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    for (int j = 0; j < spanY; j++) {
147947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        if (occupied[x + i][y + j] && (blockOccupied == null || blockOccupied[i][j])) {
1480482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                            continue inner;
1481482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        }
1482482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    }
1483482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                }
1484482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1485482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                float distance = (float)
1486482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        Math.sqrt((x - cellX) * (x - cellX) + (y - cellY) * (y - cellY));
1487482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                int[] curDirection = mTmpPoint;
148847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                computeDirectionVector(x - cellX, y - cellY, curDirection);
148947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                // The direction score is just the dot product of the two candidate direction
149047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                // and that passed in.
1491482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                int curDirectionScore = direction[0] * curDirection[0] +
1492482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        direction[1] * curDirection[1];
149347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                boolean exactDirectionOnly = false;
149447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                boolean directionMatches = direction[0] == curDirection[0] &&
149547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        direction[0] == curDirection[0];
149647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                if ((directionMatches || !exactDirectionOnly) &&
149747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        Float.compare(distance,  bestDistance) < 0 || (Float.compare(distance,
1498482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        bestDistance) == 0 && curDirectionScore > bestDirectionScore)) {
1499482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    bestDistance = distance;
1500482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    bestDirectionScore = curDirectionScore;
1501482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    bestXY[0] = x;
1502482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    bestXY[1] = y;
1503482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                }
1504482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1505482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1506482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1507482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // Return -1, -1 if no suitable location found
1508482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (bestDistance == Float.MAX_VALUE) {
1509482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            bestXY[0] = -1;
1510482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            bestXY[1] = -1;
1511482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1512482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return bestXY;
1513482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1514482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
151547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    private int[] findNearestAreaInDirection(int cellX, int cellY, int spanX, int spanY,
151647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            int[] direction,boolean[][] occupied,
151747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            boolean blockOccupied[][], int[] result) {
151847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        // Keep track of best-scoring drop area
151947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        final int[] bestXY = result != null ? result : new int[2];
152047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        bestXY[0] = -1;
152147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        bestXY[1] = -1;
152247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        float bestDistance = Float.MAX_VALUE;
152347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
152447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        // We use this to march in a single direction
15255b53f29f809a0dad4a1e0717ba610ce737ee0f43Adam Cohen        if ((direction[0] != 0 && direction[1] != 0) ||
15265b53f29f809a0dad4a1e0717ba610ce737ee0f43Adam Cohen                (direction[0] == 0 && direction[1] == 0)) {
152747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            return bestXY;
152847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
152947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
153047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        // This will only incrememnet one of x or y based on the assertion above
153147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        int x = cellX + direction[0];
153247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        int y = cellY + direction[1];
153347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        while (x >= 0 && x + spanX <= mCountX && y >= 0 && y + spanY <= mCountY) {
153447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
153547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            boolean fail = false;
153647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            for (int i = 0; i < spanX; i++) {
153747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                for (int j = 0; j < spanY; j++) {
153847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    if (occupied[x + i][y + j] && (blockOccupied == null || blockOccupied[i][j])) {
153947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        fail = true;
154047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    }
154147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                }
154247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            }
154347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            if (!fail) {
154447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                float distance = (float)
154547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        Math.sqrt((x - cellX) * (x - cellX) + (y - cellY) * (y - cellY));
154647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                if (Float.compare(distance,  bestDistance) < 0) {
154747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    bestDistance = distance;
154847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    bestXY[0] = x;
154947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    bestXY[1] = y;
155047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                }
155147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            }
155247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            x += direction[0];
155347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            y += direction[1];
155447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
155547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        return bestXY;
155647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    }
155747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
1558482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private boolean addViewToTempLocation(View v, Rect rectOccupiedByPotentialDrop,
15598baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            int[] direction, ItemConfiguration currentState) {
15608baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        CellAndSpan c = currentState.map.get(v);
1561482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        boolean success = false;
15628baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, false);
1563482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsForRect(rectOccupiedByPotentialDrop, mTmpOccupied, true);
1564482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
15658baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        findNearestArea(c.x, c.y, c.spanX, c.spanY, direction, mTmpOccupied, null, mTempLocation);
1566482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1567482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (mTempLocation[0] >= 0 && mTempLocation[1] >= 0) {
15688baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            c.x = mTempLocation[0];
15698baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            c.y = mTempLocation[1];
1570482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            success = true;
1571482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1572482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
15738baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, true);
1574482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return success;
1575482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1576482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
157747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    // This method looks in the specified direction to see if there is an additional view
157847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    // immediately adjecent in that direction
157947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    private boolean addViewInDirection(ArrayList<View> views, Rect boundingRect, int[] direction,
158019f3792523fe2d55ea791a9286398a6120920690Adam Cohen            boolean[][] occupied, View dragView, ItemConfiguration currentState) {
158147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        boolean found = false;
158247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
1583a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        int childCount = mShortcutsAndWidgets.getChildCount();
158447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        Rect r0 = new Rect(boundingRect);
158547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        Rect r1 = new Rect();
158647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
158747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        int deltaX = 0;
158847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        int deltaY = 0;
158947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        if (direction[1] < 0) {
159047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            r0.set(r0.left, r0.top - 1, r0.right, r0.bottom);
159147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            deltaY = -1;
159247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        } else if (direction[1] > 0) {
159347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            r0.set(r0.left, r0.top, r0.right, r0.bottom + 1);
159447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            deltaY = 1;
159547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        } else if (direction[0] < 0) {
159647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            r0.set(r0.left - 1, r0.top, r0.right, r0.bottom);
159747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            deltaX = -1;
159847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        } else if (direction[0] > 0) {
159947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            r0.set(r0.left, r0.top, r0.right + 1, r0.bottom);
160047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            deltaX = 1;
160147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
160247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
160347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        for (int i = 0; i < childCount; i++) {
1604a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            View child = mShortcutsAndWidgets.getChildAt(i);
160519f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (views.contains(child) || child == dragView) continue;
16068baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = currentState.map.get(child);
160747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
16088baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
16098baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            r1.set(c.x, c.y, c.x + c.spanX, c.y + c.spanY);
161047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            if (Rect.intersects(r0, r1)) {
161147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                if (!lp.canReorder) {
161247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    return false;
161347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                }
161447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                boolean pushed = false;
16158baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                for (int x = c.x; x < c.x + c.spanX; x++) {
16168baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                    for (int y = c.y; y < c.y + c.spanY; y++) {
161747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        boolean inBounds = x - deltaX >= 0 && x -deltaX < mCountX
161847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                                && y - deltaY >= 0 && y - deltaY < mCountY;
161947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        if (inBounds && occupied[x - deltaX][y - deltaY]) {
162047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                            pushed = true;
162147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        }
162247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    }
162347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                }
162447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                if (pushed) {
162547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    views.add(child);
16268baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                    boundingRect.union(c.x, c.y, c.x + c.spanX, c.y + c.spanY);
162747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    found = true;
162847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                }
162947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            }
163047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
163147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        return found;
163247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    }
163347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
16348baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen    private boolean addViewsToTempLocation(ArrayList<View> views, Rect rectOccupiedByPotentialDrop,
163519f3792523fe2d55ea791a9286398a6120920690Adam Cohen            int[] direction, boolean push, View dragView, ItemConfiguration currentState) {
163647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        if (views.size() == 0) return true;
163747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
163847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        boolean success = false;
163947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        Rect boundingRect = null;
16408baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // We construct a rect which represents the entire group of views passed in
164147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        for (View v: views) {
16428baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = currentState.map.get(v);
164347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            if (boundingRect == null) {
16448baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                boundingRect = new Rect(c.x, c.y, c.x + c.spanX, c.y + c.spanY);
164547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            } else {
16468baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                boundingRect.union(c.x, c.y, c.x + c.spanX, c.y + c.spanY);
164747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            }
164847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
164947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
16508baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        @SuppressWarnings("unchecked")
165147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        ArrayList<View> dup = (ArrayList<View>) views.clone();
16528baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // We try and expand the group of views in the direction vector passed, based on
16538baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // whether they are physically adjacent, ie. based on "push mechanics".
165419f3792523fe2d55ea791a9286398a6120920690Adam Cohen        while (push && addViewInDirection(dup, boundingRect, direction, mTmpOccupied, dragView,
16558baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                currentState)) {
165647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
16578baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen
16588baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // Mark the occupied state as false for the group of views we want to move.
165947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        for (View v: dup) {
16608baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = currentState.map.get(v);
16618baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, false);
166247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
166347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
166447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        boolean[][] blockOccupied = new boolean[boundingRect.width()][boundingRect.height()];
166547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        int top = boundingRect.top;
166647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        int left = boundingRect.left;
16678baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // We mark more precisely which parts of the bounding rect are truly occupied, allowing
16688baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // for tetris-style interlocking.
166947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        for (View v: dup) {
16708baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = currentState.map.get(v);
16718baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            markCellsForView(c.x - left, c.y - top, c.spanX, c.spanY, blockOccupied, true);
167247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
167347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
167447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        markCellsForRect(rectOccupiedByPotentialDrop, mTmpOccupied, true);
167547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
16768baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        if (push) {
16778baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            findNearestAreaInDirection(boundingRect.left, boundingRect.top, boundingRect.width(),
16788baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                    boundingRect.height(), direction, mTmpOccupied, blockOccupied, mTempLocation);
16798baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        } else {
16808baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            findNearestArea(boundingRect.left, boundingRect.top, boundingRect.width(),
16818baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                    boundingRect.height(), direction, mTmpOccupied, blockOccupied, mTempLocation);
16828baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        }
168347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
16848baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // If we successfuly found a location by pushing the block of views, we commit it
168547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        if (mTempLocation[0] >= 0 && mTempLocation[1] >= 0) {
16868baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            int deltaX = mTempLocation[0] - boundingRect.left;
16878baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            int deltaY = mTempLocation[1] - boundingRect.top;
168847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            for (View v: dup) {
16898baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                CellAndSpan c = currentState.map.get(v);
16908baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                c.x += deltaX;
16918baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                c.y += deltaY;
169247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            }
169347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            success = true;
169447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
1695482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
16968baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // In either case, we set the occupied array as marked for the location of the views
16978baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        for (View v: dup) {
16988baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = currentState.map.get(v);
16998baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, true);
1700482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1701482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return success;
1702482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1703482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1704482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private void markCellsForRect(Rect r, boolean[][] occupied, boolean value) {
1705482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsForView(r.left, r.top, r.width(), r.height(), occupied, value);
1706482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1707482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1708482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private boolean rearrangementExists(int cellX, int cellY, int spanX, int spanY, int[] direction,
17098baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            View ignoreView, ItemConfiguration solution) {
1710e3e03bcd313ba8060f2832b6a16dea6fd6d532eaWinson Chung        // Return early if get invalid cell positions
1711e3e03bcd313ba8060f2832b6a16dea6fd6d532eaWinson Chung        if (cellX < 0 || cellY < 0) return false;
1712482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
17138baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        mIntersectingViews.clear();
1714482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        mOccupiedRect.set(cellX, cellY, cellX + spanX, cellY + spanY);
1715482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
17168baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // Mark the desired location of the view currently being dragged.
1717482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (ignoreView != null) {
17188baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = solution.map.get(ignoreView);
171919f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (c != null) {
172019f3792523fe2d55ea791a9286398a6120920690Adam Cohen                c.x = cellX;
172119f3792523fe2d55ea791a9286398a6120920690Adam Cohen                c.y = cellY;
172219f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
1723482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1724482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        Rect r0 = new Rect(cellX, cellY, cellX + spanX, cellY + spanY);
1725482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        Rect r1 = new Rect();
17268baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        for (View child: solution.map.keySet()) {
1727482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (child == ignoreView) continue;
17288baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = solution.map.get(child);
1729482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
17308baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            r1.set(c.x, c.y, c.x + c.spanX, c.y + c.spanY);
1731482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (Rect.intersects(r0, r1)) {
1732482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                if (!lp.canReorder) {
1733482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    return false;
1734482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                }
1735482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                mIntersectingViews.add(child);
1736482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1737482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
173847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
17398baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // We try to move the intersecting views as a block using the push mechanic
174019f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if (addViewsToTempLocation(mIntersectingViews, mOccupiedRect, direction, true, ignoreView,
174119f3792523fe2d55ea791a9286398a6120920690Adam Cohen                solution)) {
174247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            return true;
174347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
174447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        // Try the opposite direction
174547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        direction[0] *= -1;
174647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        direction[1] *= -1;
174719f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if (addViewsToTempLocation(mIntersectingViews, mOccupiedRect, direction, true, ignoreView,
174819f3792523fe2d55ea791a9286398a6120920690Adam Cohen                solution)) {
174947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            return true;
175047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
175147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        // Switch the direction back
175247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        direction[0] *= -1;
175347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        direction[1] *= -1;
175447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
17558baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // Next we try moving the views as a block , but without requiring the push mechanic
175619f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if (addViewsToTempLocation(mIntersectingViews, mOccupiedRect, direction, false, ignoreView,
175719f3792523fe2d55ea791a9286398a6120920690Adam Cohen                solution)) {
1758482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            return true;
1759482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
176047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
1761482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // Ok, they couldn't move as a block, let's move them individually
1762482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (View v : mIntersectingViews) {
17638baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            if (!addViewToTempLocation(v, mOccupiedRect, direction, solution)) {
1764482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                return false;
1765482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1766482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1767482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return true;
1768482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1769482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1770482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    /*
1771482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * Returns a pair (x, y), where x,y are in {-1, 0, 1} corresponding to vector between
1772482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * the provided point and the provided cell
1773482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     */
177447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    private void computeDirectionVector(float deltaX, float deltaY, int[] result) {
1775482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        double angle = Math.atan(((float) deltaY) / deltaX);
1776482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1777482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        result[0] = 0;
1778482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        result[1] = 0;
1779482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (Math.abs(Math.cos(angle)) > 0.5f) {
1780482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            result[0] = (int) Math.signum(deltaX);
1781482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1782482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (Math.abs(Math.sin(angle)) > 0.5f) {
1783482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            result[1] = (int) Math.signum(deltaY);
1784482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1785482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1786482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
17878baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen    private void copyOccupiedArray(boolean[][] occupied) {
17888baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        for (int i = 0; i < mCountX; i++) {
17898baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            for (int j = 0; j < mCountY; j++) {
17908baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                occupied[i][j] = mOccupied[i][j];
17918baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            }
17928baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        }
17938baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen    }
17948baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen
1795482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    ItemConfiguration simpleSwap(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX,
1796482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            int spanY, int[] direction, View dragView, boolean decX, ItemConfiguration solution) {
17978baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // Copy the current state into the solution. This solution will be manipulated as necessary.
17988baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        copyCurrentStateToSolution(solution, false);
17998baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // Copy the current occupied array into the temporary occupied array. This array will be
18008baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // manipulated as necessary to find a solution.
18018baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        copyOccupiedArray(mTmpOccupied);
1802482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1803482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // We find the nearest cell into which we would place the dragged item, assuming there's
1804482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // nothing in its way.
1805482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        int result[] = new int[2];
1806482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        result = findNearestArea(pixelX, pixelY, spanX, spanY, result);
1807482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1808482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        boolean success = false;
1809482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // First we try the exact nearest position of the item being dragged,
1810482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // we will then want to try to move this around to other neighbouring positions
18118baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        success = rearrangementExists(result[0], result[1], spanX, spanY, direction, dragView,
18128baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                solution);
1813482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1814482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (!success) {
1815482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            // We try shrinking the widget down to size in an alternating pattern, shrink 1 in
1816482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            // x, then 1 in y etc.
1817482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (spanX > minSpanX && (minSpanY == spanY || decX)) {
1818482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                return simpleSwap(pixelX, pixelY, minSpanX, minSpanY, spanX - 1, spanY, direction,
1819482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        dragView, false, solution);
1820482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            } else if (spanY > minSpanY) {
1821482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                return simpleSwap(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY - 1, direction,
1822482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        dragView, true, solution);
1823482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1824482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.isSolution = false;
1825482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        } else {
1826482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.isSolution = true;
1827482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewX = result[0];
1828482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewY = result[1];
1829482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewSpanX = spanX;
1830482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewSpanY = spanY;
1831482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1832482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return solution;
1833482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1834482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1835482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private void copyCurrentStateToSolution(ItemConfiguration solution, boolean temp) {
1836a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        int childCount = mShortcutsAndWidgets.getChildCount();
1837482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < childCount; i++) {
1838a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            View child = mShortcutsAndWidgets.getChildAt(i);
1839482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
18408baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c;
1841482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (temp) {
18428baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                c = new CellAndSpan(lp.tmpCellX, lp.tmpCellY, lp.cellHSpan, lp.cellVSpan);
1843482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            } else {
18448baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                c = new CellAndSpan(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan);
1845482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
18468baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            solution.map.put(child, c);
1847482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1848482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1849482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1850482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private void copySolutionToTempState(ItemConfiguration solution, View dragView) {
1851482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < mCountX; i++) {
1852482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            for (int j = 0; j < mCountY; j++) {
1853482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                mTmpOccupied[i][j] = false;
1854482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1855482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1856482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1857a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        int childCount = mShortcutsAndWidgets.getChildCount();
1858482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < childCount; i++) {
1859a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            View child = mShortcutsAndWidgets.getChildAt(i);
1860482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (child == dragView) continue;
1861482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
18628baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = solution.map.get(child);
18638baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            if (c != null) {
18648baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                lp.tmpCellX = c.x;
18658baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                lp.tmpCellY = c.y;
18668baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                lp.cellHSpan = c.spanX;
18678baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                lp.cellVSpan = c.spanY;
18688baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, true);
1869482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1870482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1871482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsForView(solution.dragViewX, solution.dragViewY, solution.dragViewSpanX,
1872482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                solution.dragViewSpanY, mTmpOccupied, true);
1873482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1874482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1875482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private void animateItemsToSolution(ItemConfiguration solution, View dragView, boolean
1876482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            commitDragView) {
1877482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1878482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        boolean[][] occupied = DESTRUCTIVE_REORDER ? mOccupied : mTmpOccupied;
1879482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < mCountX; i++) {
1880482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            for (int j = 0; j < mCountY; j++) {
1881482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                occupied[i][j] = false;
1882482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1883482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1884482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1885a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        int childCount = mShortcutsAndWidgets.getChildCount();
1886482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < childCount; i++) {
1887a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            View child = mShortcutsAndWidgets.getChildAt(i);
1888482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (child == dragView) continue;
18898baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = solution.map.get(child);
18908baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            if (c != null) {
189119f3792523fe2d55ea791a9286398a6120920690Adam Cohen                animateChildToPosition(child, c.x, c.y, REORDER_ANIMATION_DURATION, 0,
189219f3792523fe2d55ea791a9286398a6120920690Adam Cohen                        DESTRUCTIVE_REORDER, false);
18938baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                markCellsForView(c.x, c.y, c.spanX, c.spanY, occupied, true);
1894482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1895482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1896482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (commitDragView) {
1897482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            markCellsForView(solution.dragViewX, solution.dragViewY, solution.dragViewSpanX,
1898482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    solution.dragViewSpanY, occupied, true);
1899482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1900482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1901482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
190219f3792523fe2d55ea791a9286398a6120920690Adam Cohen    // This method starts or changes the reorder hint animations
190319f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private void beginOrAdjustHintAnimations(ItemConfiguration solution, View dragView, int delay) {
190419f3792523fe2d55ea791a9286398a6120920690Adam Cohen        int childCount = mShortcutsAndWidgets.getChildCount();
190519f3792523fe2d55ea791a9286398a6120920690Adam Cohen        int timeForPriorAnimationToComplete = getMaxCompletionTime();
190619f3792523fe2d55ea791a9286398a6120920690Adam Cohen        for (int i = 0; i < childCount; i++) {
190719f3792523fe2d55ea791a9286398a6120920690Adam Cohen            View child = mShortcutsAndWidgets.getChildAt(i);
190819f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (child == dragView) continue;
190919f3792523fe2d55ea791a9286398a6120920690Adam Cohen            CellAndSpan c = solution.map.get(child);
191019f3792523fe2d55ea791a9286398a6120920690Adam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
191119f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (c != null) {
191219f3792523fe2d55ea791a9286398a6120920690Adam Cohen                ReorderHintAnimation rha = new ReorderHintAnimation(child, lp.cellX, lp.cellY,
191319f3792523fe2d55ea791a9286398a6120920690Adam Cohen                        c.x, c.y, c.spanX, c.spanY);
191419f3792523fe2d55ea791a9286398a6120920690Adam Cohen                rha.animate(timeForPriorAnimationToComplete);
191519f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
191619f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
191719f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
191819f3792523fe2d55ea791a9286398a6120920690Adam Cohen
191919f3792523fe2d55ea791a9286398a6120920690Adam Cohen    // Class which represents the reorder hint animations. These animations show that an item is
192019f3792523fe2d55ea791a9286398a6120920690Adam Cohen    // in a temporary state, and hint at where the item will return to.
192119f3792523fe2d55ea791a9286398a6120920690Adam Cohen    class ReorderHintAnimation {
192219f3792523fe2d55ea791a9286398a6120920690Adam Cohen        View child;
192319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        float deltaX;
192419f3792523fe2d55ea791a9286398a6120920690Adam Cohen        float deltaY;
192550e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely        private static final int DURATION = 300;
192619f3792523fe2d55ea791a9286398a6120920690Adam Cohen        private int repeatCount;
192719f3792523fe2d55ea791a9286398a6120920690Adam Cohen        private boolean cancelOnCycleComplete = false;
192819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        ValueAnimator va;
192919f3792523fe2d55ea791a9286398a6120920690Adam Cohen
193019f3792523fe2d55ea791a9286398a6120920690Adam Cohen        public ReorderHintAnimation(View child, int cellX0, int cellY0, int cellX1, int cellY1,
193119f3792523fe2d55ea791a9286398a6120920690Adam Cohen                int spanX, int spanY) {
193219f3792523fe2d55ea791a9286398a6120920690Adam Cohen            regionToCenterPoint(cellX0, cellY0, spanX, spanY, mTmpPoint);
193319f3792523fe2d55ea791a9286398a6120920690Adam Cohen            final int x0 = mTmpPoint[0];
193419f3792523fe2d55ea791a9286398a6120920690Adam Cohen            final int y0 = mTmpPoint[1];
193519f3792523fe2d55ea791a9286398a6120920690Adam Cohen            regionToCenterPoint(cellX1, cellY1, spanX, spanY, mTmpPoint);
193619f3792523fe2d55ea791a9286398a6120920690Adam Cohen            final int x1 = mTmpPoint[0];
193719f3792523fe2d55ea791a9286398a6120920690Adam Cohen            final int y1 = mTmpPoint[1];
193819f3792523fe2d55ea791a9286398a6120920690Adam Cohen            final int dX = x1 - x0;
193919f3792523fe2d55ea791a9286398a6120920690Adam Cohen            final int dY = y1 - y0;
194019f3792523fe2d55ea791a9286398a6120920690Adam Cohen            deltaX = 0;
194119f3792523fe2d55ea791a9286398a6120920690Adam Cohen            deltaY = 0;
194219f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (dX == dY && dX == 0) {
194319f3792523fe2d55ea791a9286398a6120920690Adam Cohen            } else {
194419f3792523fe2d55ea791a9286398a6120920690Adam Cohen                if (dY == 0) {
194519f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    deltaX = mReorderHintAnimationMagnitude;
194619f3792523fe2d55ea791a9286398a6120920690Adam Cohen                } else if (dX == 0) {
194719f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    deltaY = mReorderHintAnimationMagnitude;
194819f3792523fe2d55ea791a9286398a6120920690Adam Cohen                } else {
194919f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    double angle = Math.atan( (float) (dY) / dX);
195019f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    deltaX = (int) (Math.cos(angle) * mReorderHintAnimationMagnitude);
195119f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    deltaY = (int) (Math.sin(angle) * mReorderHintAnimationMagnitude);
195219f3792523fe2d55ea791a9286398a6120920690Adam Cohen                }
195319f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
195450e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely            child.setPivotY(child.getMeasuredHeight() * 0.5f);
195550e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely            child.setPivotX(child.getMeasuredWidth() * 0.5f);
195619f3792523fe2d55ea791a9286398a6120920690Adam Cohen            this.child = child;
195719f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
195819f3792523fe2d55ea791a9286398a6120920690Adam Cohen
195919f3792523fe2d55ea791a9286398a6120920690Adam Cohen        void animate(int delay) {
196019f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (mShakeAnimators.containsKey(child)) {
196119f3792523fe2d55ea791a9286398a6120920690Adam Cohen                ReorderHintAnimation oldAnimation = mShakeAnimators.get(child);
196219f3792523fe2d55ea791a9286398a6120920690Adam Cohen                oldAnimation.completeAnimation();
196319f3792523fe2d55ea791a9286398a6120920690Adam Cohen                mShakeAnimators.remove(child);
196419f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
196519f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (deltaX == 0 && deltaY == 0) {
196619f3792523fe2d55ea791a9286398a6120920690Adam Cohen                return;
196719f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
196819f3792523fe2d55ea791a9286398a6120920690Adam Cohen            va = ValueAnimator.ofFloat(0f, 1f);
196919f3792523fe2d55ea791a9286398a6120920690Adam Cohen            va.setRepeatMode(ValueAnimator.REVERSE);
197019f3792523fe2d55ea791a9286398a6120920690Adam Cohen            va.setRepeatCount(ValueAnimator.INFINITE);
19717bdfc9700b1cad043c04c757f134db1bf3df00daAdam Cohen            va.setDuration(DURATION);
19727bdfc9700b1cad043c04c757f134db1bf3df00daAdam Cohen            va.setStartDelay((int) ((Math.max(REORDER_ANIMATION_DURATION, delay)
19737bdfc9700b1cad043c04c757f134db1bf3df00daAdam Cohen                    + Math.random() * 60)));
197419f3792523fe2d55ea791a9286398a6120920690Adam Cohen            va.addUpdateListener(new AnimatorUpdateListener() {
197519f3792523fe2d55ea791a9286398a6120920690Adam Cohen                @Override
197619f3792523fe2d55ea791a9286398a6120920690Adam Cohen                public void onAnimationUpdate(ValueAnimator animation) {
197719f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    float r = ((Float) animation.getAnimatedValue()).floatValue();
197819f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    float x = r * deltaX;
197919f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    float y = r * deltaY;
198019f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    child.setTranslationX(x);
198119f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    child.setTranslationY(y);
198250e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely                    float sf = 4.0f / child.getWidth();
198350e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely                    float s = 1.0f - r * sf;
198450e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely                    child.setScaleX(s);
198550e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely                    child.setScaleY(s);
198619f3792523fe2d55ea791a9286398a6120920690Adam Cohen                }
198719f3792523fe2d55ea791a9286398a6120920690Adam Cohen            });
198819f3792523fe2d55ea791a9286398a6120920690Adam Cohen            va.addListener(new AnimatorListenerAdapter() {
198919f3792523fe2d55ea791a9286398a6120920690Adam Cohen                public void onAnimationRepeat(Animator animation) {
199019f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    repeatCount++;
199119f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    // We make sure to end only after a full period
199219f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    if (cancelOnCycleComplete && repeatCount % 2 == 0) {
199319f3792523fe2d55ea791a9286398a6120920690Adam Cohen                        va.cancel();
199419f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    }
199519f3792523fe2d55ea791a9286398a6120920690Adam Cohen                }
199619f3792523fe2d55ea791a9286398a6120920690Adam Cohen            });
199719f3792523fe2d55ea791a9286398a6120920690Adam Cohen            mShakeAnimators.put(child, this);
199819f3792523fe2d55ea791a9286398a6120920690Adam Cohen            va.start();
199919f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
200019f3792523fe2d55ea791a9286398a6120920690Adam Cohen
200119f3792523fe2d55ea791a9286398a6120920690Adam Cohen
200219f3792523fe2d55ea791a9286398a6120920690Adam Cohen        private void completeAnimation() {
200319f3792523fe2d55ea791a9286398a6120920690Adam Cohen            cancelOnCycleComplete = true;
200419f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
200550e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely        private void completeAnimationImmediately() {
200650e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely            va.cancel();
200750e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely
200850e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely            AnimatorSet s = new AnimatorSet();
200950e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely            s.playTogether(
201050e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely                ObjectAnimator.ofFloat(child, "scaleX", 1f),
201150e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely                ObjectAnimator.ofFloat(child, "scaleY", 1f),
201250e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely                ObjectAnimator.ofFloat(child, "translationX", 0f),
2013faf22e15f18479ee84ef15869694cd581df38dc5Brandon Keely                ObjectAnimator.ofFloat(child, "translationY", 0f)
201450e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely            );
201550e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely            s.setDuration(REORDER_ANIMATION_DURATION);
201650e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely            s.setInterpolator(new android.view.animation.DecelerateInterpolator(1.5f));
201750e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely            s.start();
201850e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely        }
201950e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely
202019f3792523fe2d55ea791a9286398a6120920690Adam Cohen
202119f3792523fe2d55ea791a9286398a6120920690Adam Cohen        // Returns the time required to complete the current oscillating animation
202219f3792523fe2d55ea791a9286398a6120920690Adam Cohen        private int completionTime() {
202319f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (repeatCount % 2 == 0) {
202419f3792523fe2d55ea791a9286398a6120920690Adam Cohen                return (int) (va.getDuration() - va.getCurrentPlayTime() + DURATION);
202519f3792523fe2d55ea791a9286398a6120920690Adam Cohen            } else {
202619f3792523fe2d55ea791a9286398a6120920690Adam Cohen                return (int) (va.getDuration() - va.getCurrentPlayTime());
202719f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
202819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
202919f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
203019f3792523fe2d55ea791a9286398a6120920690Adam Cohen
203119f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private void completeAndClearReorderHintAnimations() {
203219f3792523fe2d55ea791a9286398a6120920690Adam Cohen        for (ReorderHintAnimation a: mShakeAnimators.values()) {
203350e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely            a.completeAnimationImmediately();
203419f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
203519f3792523fe2d55ea791a9286398a6120920690Adam Cohen        mShakeAnimators.clear();
203619f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
203719f3792523fe2d55ea791a9286398a6120920690Adam Cohen
203819f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private int getMaxCompletionTime() {
203919f3792523fe2d55ea791a9286398a6120920690Adam Cohen        int maxTime = 0;
204019f3792523fe2d55ea791a9286398a6120920690Adam Cohen        for (ReorderHintAnimation a: mShakeAnimators.values()) {
204119f3792523fe2d55ea791a9286398a6120920690Adam Cohen            maxTime = Math.max(maxTime, a.completionTime());
204219f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
204319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        return maxTime;
204419f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
204519f3792523fe2d55ea791a9286398a6120920690Adam Cohen
2046482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private void commitTempPlacement() {
2047482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < mCountX; i++) {
2048482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            for (int j = 0; j < mCountY; j++) {
2049482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                mOccupied[i][j] = mTmpOccupied[i][j];
2050482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
2051482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2052a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        int childCount = mShortcutsAndWidgets.getChildCount();
2053482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < childCount; i++) {
2054ea889a294be004f4b1c21e9b874f9e63abfb8bd6Adam Cohen            View child = mShortcutsAndWidgets.getChildAt(i);
2055ea889a294be004f4b1c21e9b874f9e63abfb8bd6Adam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
2056ea889a294be004f4b1c21e9b874f9e63abfb8bd6Adam Cohen            ItemInfo info = (ItemInfo) child.getTag();
20572acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen            // We do a null check here because the item info can be null in the case of the
20582acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen            // AllApps button in the hotseat.
20592acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen            if (info != null) {
20602acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen                info.cellX = lp.cellX = lp.tmpCellX;
20612acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen                info.cellY = lp.cellY = lp.tmpCellY;
2062bebf042666cffe52039b875a549a582abd78a431Adam Cohen                info.spanX = lp.cellHSpan;
2063bebf042666cffe52039b875a549a582abd78a431Adam Cohen                info.spanY = lp.cellVSpan;
20642acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen            }
2065482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
20662acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen        mLauncher.getWorkspace().updateItemLocationsInDatabase(this);
2067482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2068482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2069482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public void setUseTempCoords(boolean useTempCoords) {
2070a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        int childCount = mShortcutsAndWidgets.getChildCount();
2071482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < childCount; i++) {
2072a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            LayoutParams lp = (LayoutParams) mShortcutsAndWidgets.getChildAt(i).getLayoutParams();
2073482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            lp.useTmpCoords = useTempCoords;
2074482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2075482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2076482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2077482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    ItemConfiguration findConfigurationNoShuffle(int pixelX, int pixelY, int minSpanX, int minSpanY,
2078482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            int spanX, int spanY, View dragView, ItemConfiguration solution) {
2079482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        int[] result = new int[2];
2080482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        int[] resultSpan = new int[2];
2081482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        findNearestVacantArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, null, result,
2082482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                resultSpan);
2083482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (result[0] >= 0 && result[1] >= 0) {
2084482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            copyCurrentStateToSolution(solution, false);
2085482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewX = result[0];
2086482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewY = result[1];
2087482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewSpanX = resultSpan[0];
2088482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewSpanY = resultSpan[1];
2089482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.isSolution = true;
2090482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        } else {
2091482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.isSolution = false;
2092482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2093482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return solution;
2094482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2095482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2096482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public void prepareChildForDrag(View child) {
2097482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsAsUnoccupiedForView(child);
2098482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2099482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
210019f3792523fe2d55ea791a9286398a6120920690Adam Cohen    /* This seems like it should be obvious and straight-forward, but when the direction vector
210119f3792523fe2d55ea791a9286398a6120920690Adam Cohen    needs to match with the notion of the dragView pushing other views, we have to employ
210219f3792523fe2d55ea791a9286398a6120920690Adam Cohen    a slightly more subtle notion of the direction vector. The question is what two points is
210319f3792523fe2d55ea791a9286398a6120920690Adam Cohen    the vector between? The center of the dragView and its desired destination? Not quite, as
210419f3792523fe2d55ea791a9286398a6120920690Adam Cohen    this doesn't necessarily coincide with the interaction of the dragView and items occupying
210519f3792523fe2d55ea791a9286398a6120920690Adam Cohen    those cells. Instead we use some heuristics to often lock the vector to up, down, left
210619f3792523fe2d55ea791a9286398a6120920690Adam Cohen    or right, which helps make pushing feel right.
210719f3792523fe2d55ea791a9286398a6120920690Adam Cohen    */
210819f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private void getDirectionVectorForDrop(int dragViewCenterX, int dragViewCenterY, int spanX,
210919f3792523fe2d55ea791a9286398a6120920690Adam Cohen            int spanY, View dragView, int[] resultDirection) {
211019f3792523fe2d55ea791a9286398a6120920690Adam Cohen        int[] targetDestination = new int[2];
211119f3792523fe2d55ea791a9286398a6120920690Adam Cohen
211219f3792523fe2d55ea791a9286398a6120920690Adam Cohen        findNearestArea(dragViewCenterX, dragViewCenterY, spanX, spanY, targetDestination);
211319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        Rect dragRect = new Rect();
211419f3792523fe2d55ea791a9286398a6120920690Adam Cohen        regionToRect(targetDestination[0], targetDestination[1], spanX, spanY, dragRect);
211519f3792523fe2d55ea791a9286398a6120920690Adam Cohen        dragRect.offset(dragViewCenterX - dragRect.centerX(), dragViewCenterY - dragRect.centerY());
211619f3792523fe2d55ea791a9286398a6120920690Adam Cohen
211719f3792523fe2d55ea791a9286398a6120920690Adam Cohen        Rect dropRegionRect = new Rect();
211819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        getViewsIntersectingRegion(targetDestination[0], targetDestination[1], spanX, spanY,
211919f3792523fe2d55ea791a9286398a6120920690Adam Cohen                dragView, dropRegionRect, mIntersectingViews);
212019f3792523fe2d55ea791a9286398a6120920690Adam Cohen
212119f3792523fe2d55ea791a9286398a6120920690Adam Cohen        int dropRegionSpanX = dropRegionRect.width();
212219f3792523fe2d55ea791a9286398a6120920690Adam Cohen        int dropRegionSpanY = dropRegionRect.height();
212319f3792523fe2d55ea791a9286398a6120920690Adam Cohen
212419f3792523fe2d55ea791a9286398a6120920690Adam Cohen        regionToRect(dropRegionRect.left, dropRegionRect.top, dropRegionRect.width(),
212519f3792523fe2d55ea791a9286398a6120920690Adam Cohen                dropRegionRect.height(), dropRegionRect);
212619f3792523fe2d55ea791a9286398a6120920690Adam Cohen
212719f3792523fe2d55ea791a9286398a6120920690Adam Cohen        int deltaX = (dropRegionRect.centerX() - dragViewCenterX) / spanX;
212819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        int deltaY = (dropRegionRect.centerY() - dragViewCenterY) / spanY;
212919f3792523fe2d55ea791a9286398a6120920690Adam Cohen
213019f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if (dropRegionSpanX == mCountX || spanX == mCountX) {
213119f3792523fe2d55ea791a9286398a6120920690Adam Cohen            deltaX = 0;
213219f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
213319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if (dropRegionSpanY == mCountY || spanY == mCountY) {
213419f3792523fe2d55ea791a9286398a6120920690Adam Cohen            deltaY = 0;
213519f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
213619f3792523fe2d55ea791a9286398a6120920690Adam Cohen
213719f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if (deltaX == 0 && deltaY == 0) {
213819f3792523fe2d55ea791a9286398a6120920690Adam Cohen            // No idea what to do, give a random direction.
213919f3792523fe2d55ea791a9286398a6120920690Adam Cohen            resultDirection[0] = 1;
214019f3792523fe2d55ea791a9286398a6120920690Adam Cohen            resultDirection[1] = 0;
214119f3792523fe2d55ea791a9286398a6120920690Adam Cohen        } else {
214219f3792523fe2d55ea791a9286398a6120920690Adam Cohen            computeDirectionVector(deltaX, deltaY, resultDirection);
214319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
214419f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
214519f3792523fe2d55ea791a9286398a6120920690Adam Cohen
214619f3792523fe2d55ea791a9286398a6120920690Adam Cohen    // For a given cell and span, fetch the set of views intersecting the region.
214719f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private void getViewsIntersectingRegion(int cellX, int cellY, int spanX, int spanY,
214819f3792523fe2d55ea791a9286398a6120920690Adam Cohen            View dragView, Rect boundingRect, ArrayList<View> intersectingViews) {
214919f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if (boundingRect != null) {
215019f3792523fe2d55ea791a9286398a6120920690Adam Cohen            boundingRect.set(cellX, cellY, cellX + spanX, cellY + spanY);
215119f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
215219f3792523fe2d55ea791a9286398a6120920690Adam Cohen        intersectingViews.clear();
215319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        Rect r0 = new Rect(cellX, cellY, cellX + spanX, cellY + spanY);
215419f3792523fe2d55ea791a9286398a6120920690Adam Cohen        Rect r1 = new Rect();
215519f3792523fe2d55ea791a9286398a6120920690Adam Cohen        final int count = mShortcutsAndWidgets.getChildCount();
215619f3792523fe2d55ea791a9286398a6120920690Adam Cohen        for (int i = 0; i < count; i++) {
215719f3792523fe2d55ea791a9286398a6120920690Adam Cohen            View child = mShortcutsAndWidgets.getChildAt(i);
215819f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (child == dragView) continue;
215919f3792523fe2d55ea791a9286398a6120920690Adam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
216019f3792523fe2d55ea791a9286398a6120920690Adam Cohen            r1.set(lp.cellX, lp.cellY, lp.cellX + lp.cellHSpan, lp.cellY + lp.cellVSpan);
216119f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (Rect.intersects(r0, r1)) {
216219f3792523fe2d55ea791a9286398a6120920690Adam Cohen                mIntersectingViews.add(child);
216319f3792523fe2d55ea791a9286398a6120920690Adam Cohen                if (boundingRect != null) {
216419f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    boundingRect.union(r1);
216519f3792523fe2d55ea791a9286398a6120920690Adam Cohen                }
216619f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
216719f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
216819f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
216919f3792523fe2d55ea791a9286398a6120920690Adam Cohen
217019f3792523fe2d55ea791a9286398a6120920690Adam Cohen    boolean isNearestDropLocationOccupied(int pixelX, int pixelY, int spanX, int spanY,
217119f3792523fe2d55ea791a9286398a6120920690Adam Cohen            View dragView, int[] result) {
217219f3792523fe2d55ea791a9286398a6120920690Adam Cohen        result = findNearestArea(pixelX, pixelY, spanX, spanY, result);
217319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        getViewsIntersectingRegion(result[0], result[1], spanX, spanY, dragView, null,
217419f3792523fe2d55ea791a9286398a6120920690Adam Cohen                mIntersectingViews);
217519f3792523fe2d55ea791a9286398a6120920690Adam Cohen        return !mIntersectingViews.isEmpty();
217619f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
217719f3792523fe2d55ea791a9286398a6120920690Adam Cohen
217819f3792523fe2d55ea791a9286398a6120920690Adam Cohen    void revertTempState() {
217919f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if (!isItemPlacementDirty() || DESTRUCTIVE_REORDER) return;
218019f3792523fe2d55ea791a9286398a6120920690Adam Cohen        final int count = mShortcutsAndWidgets.getChildCount();
218119f3792523fe2d55ea791a9286398a6120920690Adam Cohen        for (int i = 0; i < count; i++) {
218219f3792523fe2d55ea791a9286398a6120920690Adam Cohen            View child = mShortcutsAndWidgets.getChildAt(i);
218319f3792523fe2d55ea791a9286398a6120920690Adam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
218419f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (lp.tmpCellX != lp.cellX || lp.tmpCellY != lp.cellY) {
218519f3792523fe2d55ea791a9286398a6120920690Adam Cohen                lp.tmpCellX = lp.cellX;
218619f3792523fe2d55ea791a9286398a6120920690Adam Cohen                lp.tmpCellY = lp.cellY;
218719f3792523fe2d55ea791a9286398a6120920690Adam Cohen                animateChildToPosition(child, lp.cellX, lp.cellY, REORDER_ANIMATION_DURATION,
218819f3792523fe2d55ea791a9286398a6120920690Adam Cohen                        0, false, false);
218919f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
219019f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
219119f3792523fe2d55ea791a9286398a6120920690Adam Cohen        completeAndClearReorderHintAnimations();
219219f3792523fe2d55ea791a9286398a6120920690Adam Cohen        setItemPlacementDirty(false);
219319f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
219419f3792523fe2d55ea791a9286398a6120920690Adam Cohen
2195bebf042666cffe52039b875a549a582abd78a431Adam Cohen    boolean createAreaForResize(int cellX, int cellY, int spanX, int spanY,
2196bebf042666cffe52039b875a549a582abd78a431Adam Cohen            View dragView, int[] direction, boolean commit) {
2197bebf042666cffe52039b875a549a582abd78a431Adam Cohen        int[] pixelXY = new int[2];
2198bebf042666cffe52039b875a549a582abd78a431Adam Cohen        regionToCenterPoint(cellX, cellY, spanX, spanY, pixelXY);
2199bebf042666cffe52039b875a549a582abd78a431Adam Cohen
2200bebf042666cffe52039b875a549a582abd78a431Adam Cohen        // First we determine if things have moved enough to cause a different layout
2201bebf042666cffe52039b875a549a582abd78a431Adam Cohen        ItemConfiguration swapSolution = simpleSwap(pixelXY[0], pixelXY[1], spanX, spanY,
2202bebf042666cffe52039b875a549a582abd78a431Adam Cohen                 spanX,  spanY, direction, dragView,  true,  new ItemConfiguration());
2203bebf042666cffe52039b875a549a582abd78a431Adam Cohen
2204bebf042666cffe52039b875a549a582abd78a431Adam Cohen        setUseTempCoords(true);
2205bebf042666cffe52039b875a549a582abd78a431Adam Cohen        if (swapSolution != null && swapSolution.isSolution) {
2206bebf042666cffe52039b875a549a582abd78a431Adam Cohen            // If we're just testing for a possible location (MODE_ACCEPT_DROP), we don't bother
2207bebf042666cffe52039b875a549a582abd78a431Adam Cohen            // committing anything or animating anything as we just want to determine if a solution
2208bebf042666cffe52039b875a549a582abd78a431Adam Cohen            // exists
2209bebf042666cffe52039b875a549a582abd78a431Adam Cohen            copySolutionToTempState(swapSolution, dragView);
2210bebf042666cffe52039b875a549a582abd78a431Adam Cohen            setItemPlacementDirty(true);
2211bebf042666cffe52039b875a549a582abd78a431Adam Cohen            animateItemsToSolution(swapSolution, dragView, commit);
2212bebf042666cffe52039b875a549a582abd78a431Adam Cohen
2213bebf042666cffe52039b875a549a582abd78a431Adam Cohen            if (commit) {
2214bebf042666cffe52039b875a549a582abd78a431Adam Cohen                commitTempPlacement();
2215bebf042666cffe52039b875a549a582abd78a431Adam Cohen                completeAndClearReorderHintAnimations();
2216bebf042666cffe52039b875a549a582abd78a431Adam Cohen                setItemPlacementDirty(false);
2217bebf042666cffe52039b875a549a582abd78a431Adam Cohen            } else {
2218bebf042666cffe52039b875a549a582abd78a431Adam Cohen                beginOrAdjustHintAnimations(swapSolution, dragView,
2219bebf042666cffe52039b875a549a582abd78a431Adam Cohen                        REORDER_ANIMATION_DURATION);
2220bebf042666cffe52039b875a549a582abd78a431Adam Cohen            }
2221bebf042666cffe52039b875a549a582abd78a431Adam Cohen            mShortcutsAndWidgets.requestLayout();
2222bebf042666cffe52039b875a549a582abd78a431Adam Cohen        }
2223bebf042666cffe52039b875a549a582abd78a431Adam Cohen        return swapSolution.isSolution;
2224bebf042666cffe52039b875a549a582abd78a431Adam Cohen    }
2225bebf042666cffe52039b875a549a582abd78a431Adam Cohen
2226482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    int[] createArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, int spanY,
2227482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            View dragView, int[] result, int resultSpan[], int mode) {
2228482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // First we determine if things have moved enough to cause a different layout
222947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        result = findNearestArea(pixelX, pixelY, spanX, spanY, result);
2230482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2231482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (resultSpan == null) {
2232482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            resultSpan = new int[2];
2233482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2234482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
223519f3792523fe2d55ea791a9286398a6120920690Adam Cohen        // When we are checking drop validity or actually dropping, we don't recompute the
223619f3792523fe2d55ea791a9286398a6120920690Adam Cohen        // direction vector, since we want the solution to match the preview, and it's possible
223719f3792523fe2d55ea791a9286398a6120920690Adam Cohen        // that the exact position of the item has changed to result in a new reordering outcome.
2238b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen        if ((mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL || mode == MODE_ACCEPT_DROP)
2239b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen               && mPreviousReorderDirection[0] != INVALID_DIRECTION) {
224019f3792523fe2d55ea791a9286398a6120920690Adam Cohen            mDirectionVector[0] = mPreviousReorderDirection[0];
224119f3792523fe2d55ea791a9286398a6120920690Adam Cohen            mDirectionVector[1] = mPreviousReorderDirection[1];
224219f3792523fe2d55ea791a9286398a6120920690Adam Cohen            // We reset this vector after drop
2243b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen            if (mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL) {
2244b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen                mPreviousReorderDirection[0] = INVALID_DIRECTION;
2245b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen                mPreviousReorderDirection[1] = INVALID_DIRECTION;
224619f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
224719f3792523fe2d55ea791a9286398a6120920690Adam Cohen        } else {
224819f3792523fe2d55ea791a9286398a6120920690Adam Cohen            getDirectionVectorForDrop(pixelX, pixelY, spanX, spanY, dragView, mDirectionVector);
224919f3792523fe2d55ea791a9286398a6120920690Adam Cohen            mPreviousReorderDirection[0] = mDirectionVector[0];
225019f3792523fe2d55ea791a9286398a6120920690Adam Cohen            mPreviousReorderDirection[1] = mDirectionVector[1];
225119f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
225219f3792523fe2d55ea791a9286398a6120920690Adam Cohen
2253482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        ItemConfiguration swapSolution = simpleSwap(pixelX, pixelY, minSpanX, minSpanY,
2254482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                 spanX,  spanY, mDirectionVector, dragView,  true,  new ItemConfiguration());
2255482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2256482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // We attempt the approach which doesn't shuffle views at all
2257482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        ItemConfiguration noShuffleSolution = findConfigurationNoShuffle(pixelX, pixelY, minSpanX,
2258482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                minSpanY, spanX, spanY, dragView, new ItemConfiguration());
2259482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2260482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        ItemConfiguration finalSolution = null;
2261482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (swapSolution.isSolution && swapSolution.area() >= noShuffleSolution.area()) {
2262482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            finalSolution = swapSolution;
2263482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        } else if (noShuffleSolution.isSolution) {
2264482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            finalSolution = noShuffleSolution;
2265482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2266482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2267482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        boolean foundSolution = true;
2268482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (!DESTRUCTIVE_REORDER) {
2269482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            setUseTempCoords(true);
2270482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2271482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2272482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (finalSolution != null) {
2273482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            result[0] = finalSolution.dragViewX;
2274482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            result[1] = finalSolution.dragViewY;
2275482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            resultSpan[0] = finalSolution.dragViewSpanX;
2276482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            resultSpan[1] = finalSolution.dragViewSpanY;
2277482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2278482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            // If we're just testing for a possible location (MODE_ACCEPT_DROP), we don't bother
2279482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            // committing anything or animating anything as we just want to determine if a solution
2280482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            // exists
2281482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (mode == MODE_DRAG_OVER || mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL) {
2282482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                if (!DESTRUCTIVE_REORDER) {
2283482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    copySolutionToTempState(finalSolution, dragView);
2284482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                }
2285482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                setItemPlacementDirty(true);
2286482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                animateItemsToSolution(finalSolution, dragView, mode == MODE_ON_DROP);
2287482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
228819f3792523fe2d55ea791a9286398a6120920690Adam Cohen                if (!DESTRUCTIVE_REORDER &&
228919f3792523fe2d55ea791a9286398a6120920690Adam Cohen                        (mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL)) {
2290482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    commitTempPlacement();
229119f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    completeAndClearReorderHintAnimations();
229219f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    setItemPlacementDirty(false);
229319f3792523fe2d55ea791a9286398a6120920690Adam Cohen                } else {
229419f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    beginOrAdjustHintAnimations(finalSolution, dragView,
229519f3792523fe2d55ea791a9286398a6120920690Adam Cohen                            REORDER_ANIMATION_DURATION);
2296482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                }
2297482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
2298482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        } else {
2299482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            foundSolution = false;
2300482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            result[0] = result[1] = resultSpan[0] = resultSpan[1] = -1;
2301482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2302482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2303482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if ((mode == MODE_ON_DROP || !foundSolution) && !DESTRUCTIVE_REORDER) {
2304482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            setUseTempCoords(false);
2305482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2306482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2307a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.requestLayout();
2308482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return result;
2309482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2310482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
231119f3792523fe2d55ea791a9286398a6120920690Adam Cohen    void setItemPlacementDirty(boolean dirty) {
231219f3792523fe2d55ea791a9286398a6120920690Adam Cohen        mItemPlacementDirty = dirty;
2313482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
231419f3792523fe2d55ea791a9286398a6120920690Adam Cohen    boolean isItemPlacementDirty() {
231519f3792523fe2d55ea791a9286398a6120920690Adam Cohen        return mItemPlacementDirty;
2316482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2317482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2318482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private class ItemConfiguration {
23198baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        HashMap<View, CellAndSpan> map = new HashMap<View, CellAndSpan>();
2320482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        boolean isSolution = false;
2321482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        int dragViewX, dragViewY, dragViewSpanX, dragViewSpanY;
2322482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2323482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        int area() {
2324482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            return dragViewSpanX * dragViewSpanY;
2325482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
23268baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen    }
23278baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen
23288baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen    private class CellAndSpan {
23298baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        int x, y;
23308baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        int spanX, spanY;
23318baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen
23328baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        public CellAndSpan(int x, int y, int spanX, int spanY) {
23338baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            this.x = x;
23348baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            this.y = y;
23358baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            this.spanX = spanX;
23368baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            this.spanY = spanY;
2337482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2338482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2339482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2340df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    /**
2341df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * Find a vacant area that will fit the given bounds nearest the requested
2342df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * cell location. Uses Euclidean distance to score multiple vacant areas.
2343df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     *
2344df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param pixelX The X location at which you want to search for a vacant area.
2345df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param pixelY The Y location at which you want to search for a vacant area.
2346df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param spanX Horizontal span of the object.
2347df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param spanY Vertical span of the object.
2348df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param ignoreView Considers space occupied by this view as unoccupied
2349df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param result Previously returned value to possibly recycle.
2350df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @return The X, Y cell of a vacant area that can contain this object,
2351df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     *         nearest the requested location.
2352df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     */
2353df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    int[] findNearestVacantArea(
2354df0353815c629fc678824b07a234b89a1ff94208Adam Cohen            int pixelX, int pixelY, int spanX, int spanY, View ignoreView, int[] result) {
2355df0353815c629fc678824b07a234b89a1ff94208Adam Cohen        return findNearestArea(pixelX, pixelY, spanX, spanY, ignoreView, true, result);
2356df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    }
2357df0353815c629fc678824b07a234b89a1ff94208Adam Cohen
2358df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    /**
2359d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * Find a vacant area that will fit the given bounds nearest the requested
2360d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * cell location. Uses Euclidean distance to score multiple vacant areas.
2361d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *
2362d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param pixelX The X location at which you want to search for a vacant area.
2363d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param pixelY The Y location at which you want to search for a vacant area.
2364d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param minSpanX The minimum horizontal span required
2365d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param minSpanY The minimum vertical span required
2366d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param spanX Horizontal span of the object.
2367d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param spanY Vertical span of the object.
2368d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param ignoreView Considers space occupied by this view as unoccupied
2369d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param result Previously returned value to possibly recycle.
2370d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @return The X, Y cell of a vacant area that can contain this object,
2371d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *         nearest the requested location.
2372d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     */
2373d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    int[] findNearestVacantArea(int pixelX, int pixelY, int minSpanX, int minSpanY,
2374d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            int spanX, int spanY, View ignoreView, int[] result, int[] resultSpan) {
2375482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return findNearestArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, ignoreView, true,
2376482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                result, resultSpan, mOccupied);
2377d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    }
2378d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen
2379d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    /**
2380df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * Find a starting cell position that will fit the given bounds nearest the requested
2381df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * cell location. Uses Euclidean distance to score multiple vacant areas.
2382df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     *
2383df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param pixelX The X location at which you want to search for a vacant area.
2384df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param pixelY The Y location at which you want to search for a vacant area.
2385df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param spanX Horizontal span of the object.
2386df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param spanY Vertical span of the object.
2387df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param ignoreView Considers space occupied by this view as unoccupied
2388df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param result Previously returned value to possibly recycle.
2389df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @return The X, Y cell of a vacant area that can contain this object,
2390df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     *         nearest the requested location.
2391df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     */
2392df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    int[] findNearestArea(
2393df0353815c629fc678824b07a234b89a1ff94208Adam Cohen            int pixelX, int pixelY, int spanX, int spanY, int[] result) {
2394df0353815c629fc678824b07a234b89a1ff94208Adam Cohen        return findNearestArea(pixelX, pixelY, spanX, spanY, null, false, result);
2395df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    }
2396df0353815c629fc678824b07a234b89a1ff94208Adam Cohen
23970280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    boolean existsEmptyCell() {
23980280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        return findCellForSpan(null, 1, 1);
23990280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
24000280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
24010280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    /**
24020280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * Finds the upper-left coordinate of the first rectangle in the grid that can
24030280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * hold a cell of the specified dimensions. If intersectX and intersectY are not -1,
24040280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * then this method will only return coordinates for rectangles that contain the cell
24050280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * (intersectX, intersectY)
24060280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     *
24070280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param cellXY The array that will contain the position of a vacant cell if such a cell
24080280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     *               can be found.
24090280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param spanX The horizontal span of the cell we want to find.
24100280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param spanY The vertical span of the cell we want to find.
24110280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     *
24120280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @return True if a vacant cell of the specified dimension was found, false otherwise.
24130280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     */
24140280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    boolean findCellForSpan(int[] cellXY, int spanX, int spanY) {
2415482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return findCellForSpanThatIntersectsIgnoring(cellXY, spanX, spanY, -1, -1, null, mOccupied);
24160280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
24170280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
24180280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    /**
24190280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * Like above, but ignores any cells occupied by the item "ignoreView"
24200280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     *
24210280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param cellXY The array that will contain the position of a vacant cell if such a cell
24220280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     *               can be found.
24230280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param spanX The horizontal span of the cell we want to find.
24240280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param spanY The vertical span of the cell we want to find.
24250280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param ignoreView The home screen item we should treat as not occupying any space
24260280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @return
24270280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     */
24280280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    boolean findCellForSpanIgnoring(int[] cellXY, int spanX, int spanY, View ignoreView) {
2429482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return findCellForSpanThatIntersectsIgnoring(cellXY, spanX, spanY, -1, -1,
2430482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                ignoreView, mOccupied);
24310280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
24320280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
24330280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    /**
24340280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * Like above, but if intersectX and intersectY are not -1, then this method will try to
24350280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * return coordinates for rectangles that contain the cell [intersectX, intersectY]
24360280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     *
24370280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param spanX The horizontal span of the cell we want to find.
24380280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param spanY The vertical span of the cell we want to find.
24390280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param ignoreView The home screen item we should treat as not occupying any space
24400280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param intersectX The X coordinate of the cell that we should try to overlap
24410280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param intersectX The Y coordinate of the cell that we should try to overlap
24420280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     *
24430280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @return True if a vacant cell of the specified dimension was found, false otherwise.
24440280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     */
24450280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    boolean findCellForSpanThatIntersects(int[] cellXY, int spanX, int spanY,
24460280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            int intersectX, int intersectY) {
24470280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        return findCellForSpanThatIntersectsIgnoring(
2448482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                cellXY, spanX, spanY, intersectX, intersectY, null, mOccupied);
24490280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
24500280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
24510280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    /**
24520280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * The superset of the above two methods
24530280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     */
24540280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    boolean findCellForSpanThatIntersectsIgnoring(int[] cellXY, int spanX, int spanY,
2455482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            int intersectX, int intersectY, View ignoreView, boolean occupied[][]) {
2456c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka        // mark space take by ignoreView as available (method checks if ignoreView is null)
2457482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsAsUnoccupiedForView(ignoreView, occupied);
24580280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
245928750fba6a2d141eb9a1e566718c17236030b815Michael Jurka        boolean foundCell = false;
24600280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        while (true) {
24610280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            int startX = 0;
24620280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            if (intersectX >= 0) {
24630280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                startX = Math.max(startX, intersectX - (spanX - 1));
24640280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            }
24650280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            int endX = mCountX - (spanX - 1);
24660280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            if (intersectX >= 0) {
24670280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                endX = Math.min(endX, intersectX + (spanX - 1) + (spanX == 1 ? 1 : 0));
24680280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            }
24690280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            int startY = 0;
24700280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            if (intersectY >= 0) {
24710280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                startY = Math.max(startY, intersectY - (spanY - 1));
24720280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            }
24730280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            int endY = mCountY - (spanY - 1);
24740280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            if (intersectY >= 0) {
24750280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                endY = Math.min(endY, intersectY + (spanY - 1) + (spanY == 1 ? 1 : 0));
24760280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            }
24770280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
2478bbc60d8e79416e37cbede55c159bf6aaa6c171d5Winson Chung            for (int y = startY; y < endY && !foundCell; y++) {
24790280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                inner:
2480bbc60d8e79416e37cbede55c159bf6aaa6c171d5Winson Chung                for (int x = startX; x < endX; x++) {
24810280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                    for (int i = 0; i < spanX; i++) {
24820280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                        for (int j = 0; j < spanY; j++) {
2483482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                            if (occupied[x + i][y + j]) {
2484bbc60d8e79416e37cbede55c159bf6aaa6c171d5Winson Chung                                // small optimization: we can skip to after the column we just found
24850280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                                // an occupied cell
2486bbc60d8e79416e37cbede55c159bf6aaa6c171d5Winson Chung                                x += i;
24870280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                                continue inner;
24880280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                            }
24890280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                        }
24900280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                    }
24910280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                    if (cellXY != null) {
24920280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                        cellXY[0] = x;
24930280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                        cellXY[1] = y;
24940280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                    }
249528750fba6a2d141eb9a1e566718c17236030b815Michael Jurka                    foundCell = true;
249628750fba6a2d141eb9a1e566718c17236030b815Michael Jurka                    break;
24970280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                }
24980280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            }
24990280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            if (intersectX == -1 && intersectY == -1) {
25000280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                break;
25010280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            } else {
25020280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                // if we failed to find anything, try again but without any requirements of
25030280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                // intersecting
25040280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                intersectX = -1;
25050280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                intersectY = -1;
25060280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                continue;
25070280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            }
25080280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        }
25090280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
2510c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka        // re-mark space taken by ignoreView as occupied
2511482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsAsOccupiedForView(ignoreView, occupied);
251228750fba6a2d141eb9a1e566718c17236030b815Michael Jurka        return foundCell;
25130280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
25140280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
251531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
2516c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung     * A drag event has begun over this layout.
2517c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung     * It may have begun over this layout (in which case onDragChild is called first),
2518c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung     * or it may have begun on another layout.
2519c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung     */
2520c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung    void onDragEnter() {
2521c6cc61d45836e4081920883cc4d448ccb0bb8417Adam Cohen        mDragEnforcer.onDragEnter();
2522c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung        mDragging = true;
2523c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung    }
2524c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung
2525c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung    /**
25260280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * Called when drag has left this CellLayout or has been completed (successfully or not)
25276569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     */
25280280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    void onDragExit() {
2529c6cc61d45836e4081920883cc4d448ccb0bb8417Adam Cohen        mDragEnforcer.onDragExit();
25304be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        // This can actually be called when we aren't in a drag, e.g. when adding a new
25314be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        // item to this layout via the customize drawer.
25324be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        // Guard against that case.
25334be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        if (mDragging) {
25344be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            mDragging = false;
25354be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        }
253608ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy
253708ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy        // Invalidate the drag data
2538d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        mDragCell[0] = mDragCell[1] = -1;
253908ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy        mDragOutlineAnims[mDragOutlineCurrent].animateOut();
254008ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy        mDragOutlineCurrent = (mDragOutlineCurrent + 1) % mDragOutlineAnims.length;
254119f3792523fe2d55ea791a9286398a6120920690Adam Cohen        revertTempState();
254233945b21544bc98381df17726a3537c292d8c985Michael Jurka        setIsDragOverlapping(false);
25436569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    }
25446569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
25456569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    /**
2546aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     * Mark a child as having been dropped.
2547de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy     * At the beginning of the drag operation, the child may have been on another
2548ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy     * screen, but it is re-parented before this method is called.
254931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     *
255031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param child The child that is being dropped
255131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
2552716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    void onDropChild(View child) {
2553d94533d04a5f8f5485f106d10af60169857ea899Romain Guy        if (child != null) {
2554d94533d04a5f8f5485f106d10af60169857ea899Romain Guy            LayoutParams lp = (LayoutParams) child.getLayoutParams();
255584f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy            lp.dropped = true;
2556d94533d04a5f8f5485f106d10af60169857ea899Romain Guy            child.requestLayout();
2557d94533d04a5f8f5485f106d10af60169857ea899Romain Guy        }
255831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
255931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
256031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
256131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * Computes a bounding rectangle for a range of cells
2562aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     *
256331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param cellX X coordinate of upper left corner expressed as a cell position
256431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param cellY Y coordinate of upper left corner expressed as a cell position
2565aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     * @param cellHSpan Width in cells
256631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param cellVSpan Height in cells
25676569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     * @param resultRect Rect into which to put the results
256831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
2569d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    public void cellToRect(int cellX, int cellY, int cellHSpan, int cellVSpan, Rect resultRect) {
257031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        final int cellWidth = mCellWidth;
257131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        final int cellHeight = mCellHeight;
257231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        final int widthGap = mWidthGap;
257331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        final int heightGap = mHeightGap;
2574aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
25754b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int hStartPadding = getPaddingLeft();
25764b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int vStartPadding = getPaddingTop();
2577aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
257831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int width = cellHSpan * cellWidth + ((cellHSpan - 1) * widthGap);
257931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int height = cellVSpan * cellHeight + ((cellVSpan - 1) * heightGap);
258031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
258131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int x = hStartPadding + cellX * (cellWidth + widthGap);
258231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int y = vStartPadding + cellY * (cellHeight + heightGap);
2583aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
25846569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        resultRect.set(x, y, x + width, y + height);
258531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
2586aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
258731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
2588aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     * Computes the required horizontal and vertical cell spans to always
258931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * fit the given rectangle.
2590aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     *
259131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param width Width in pixels
259231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param height Height in pixels
25938f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy     * @param result An array of length 2 in which to store the result (may be null).
259431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
25958f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy    public int[] rectToCell(int width, int height, int[] result) {
25969987a5c45e7d01a780d73b269bdce8d8a5309219Michael Jurka        return rectToCell(getResources(), width, height, result);
25979987a5c45e7d01a780d73b269bdce8d8a5309219Michael Jurka    }
25989987a5c45e7d01a780d73b269bdce8d8a5309219Michael Jurka
25999987a5c45e7d01a780d73b269bdce8d8a5309219Michael Jurka    public static int[] rectToCell(Resources resources, int width, int height, int[] result) {
260031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // Always assume we're working with the smallest span to make sure we
260131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // reserve enough space in both orientations.
260279e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato        int actualWidth = resources.getDimensionPixelSize(R.dimen.workspace_cell_width);
260379e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato        int actualHeight = resources.getDimensionPixelSize(R.dimen.workspace_cell_height);
260431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int smallerSize = Math.min(actualWidth, actualHeight);
260579e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato
260631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // Always round up to next largest cell
260754c725cc294cd43ed0650179bfae64a622547660Winson Chung        int spanX = (int) Math.ceil(width / (float) smallerSize);
260854c725cc294cd43ed0650179bfae64a622547660Winson Chung        int spanY = (int) Math.ceil(height / (float) smallerSize);
260979e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato
26108f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy        if (result == null) {
26118f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy            return new int[] { spanX, spanY };
26128f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy        }
26138f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy        result[0] = spanX;
26148f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy        result[1] = spanY;
26158f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy        return result;
261631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
261731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
2618f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka    public int[] cellSpansToSize(int hSpans, int vSpans) {
2619f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka        int[] size = new int[2];
2620f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka        size[0] = hSpans * mCellWidth + (hSpans - 1) * mWidthGap;
2621f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka        size[1] = vSpans * mCellHeight + (vSpans - 1) * mHeightGap;
2622f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka        return size;
2623f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka    }
2624f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka
262531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
2626047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy     * Calculate the grid spans needed to fit given item
2627047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy     */
2628047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy    public void calculateSpans(ItemInfo info) {
2629047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        final int minWidth;
2630047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        final int minHeight;
2631047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy
2632047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        if (info instanceof LauncherAppWidgetInfo) {
2633047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy            minWidth = ((LauncherAppWidgetInfo) info).minWidth;
2634047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy            minHeight = ((LauncherAppWidgetInfo) info).minHeight;
2635047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        } else if (info instanceof PendingAddWidgetInfo) {
2636047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy            minWidth = ((PendingAddWidgetInfo) info).minWidth;
2637047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy            minHeight = ((PendingAddWidgetInfo) info).minHeight;
2638047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        } else {
2639047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy            // It's not a widget, so it must be 1x1
2640047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy            info.spanX = info.spanY = 1;
2641047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy            return;
2642047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        }
2643047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        int[] spans = rectToCell(minWidth, minHeight, null);
2644047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        info.spanX = spans[0];
2645047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        info.spanY = spans[1];
2646047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy    }
2647047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy
2648047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy    /**
264931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * Find the first vacant cell, if there is one.
265031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     *
265131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param vacant Holds the x and y coordinate of the vacant cell
265231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param spanX Horizontal cell span.
265331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param spanY Vertical cell span.
2654aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     *
265531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @return True if a vacant cell was found
265631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
265731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public boolean getVacantCell(int[] vacant, int spanX, int spanY) {
265831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
26590280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        return findVacantCell(vacant, spanX, spanY, mCountX, mCountY, mOccupied);
266031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
266131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
266231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    static boolean findVacantCell(int[] vacant, int spanX, int spanY,
266331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            int xCount, int yCount, boolean[][] occupied) {
266431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
26652801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        for (int y = 0; y < yCount; y++) {
26662801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            for (int x = 0; x < xCount; x++) {
266731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                boolean available = !occupied[x][y];
266831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectout:            for (int i = x; i < x + spanX - 1 && x < xCount; i++) {
266931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                    for (int j = y; j < y + spanY - 1 && y < yCount; j++) {
267031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                        available = available && !occupied[i][j];
267131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                        if (!available) break out;
267231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                    }
267331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                }
267431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
267531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                if (available) {
267631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                    vacant[0] = x;
267731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                    vacant[1] = y;
267831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                    return true;
267931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                }
268031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            }
268131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
268231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
268331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        return false;
268431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
268531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
26860280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    private void clearOccupiedCells() {
26870280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        for (int x = 0; x < mCountX; x++) {
26880280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            for (int y = 0; y < mCountY; y++) {
26890280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                mOccupied[x][y] = false;
269031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            }
269131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
26920280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
269331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
2694d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    public void onMove(View view, int newCellX, int newCellY, int newSpanX, int newSpanY) {
26950280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        markCellsAsUnoccupiedForView(view);
2696482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsForView(newCellX, newCellY, newSpanX, newSpanY, mOccupied, true);
26970280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
269831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
2699d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    public void markCellsAsOccupiedForView(View view) {
2700482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsAsOccupiedForView(view, mOccupied);
2701482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2702482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public void markCellsAsOccupiedForView(View view, boolean[][] occupied) {
2703a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        if (view == null || view.getParent() != mShortcutsAndWidgets) return;
27040280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        LayoutParams lp = (LayoutParams) view.getLayoutParams();
2705482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, occupied, true);
27060280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
27070280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
2708d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    public void markCellsAsUnoccupiedForView(View view) {
2709482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsAsUnoccupiedForView(view, mOccupied);
2710482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2711482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public void markCellsAsUnoccupiedForView(View view, boolean occupied[][]) {
2712a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        if (view == null || view.getParent() != mShortcutsAndWidgets) return;
27130280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        LayoutParams lp = (LayoutParams) view.getLayoutParams();
2714482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, occupied, false);
27150280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
27160280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
2717482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private void markCellsForView(int cellX, int cellY, int spanX, int spanY, boolean[][] occupied,
2718482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            boolean value) {
2719482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (cellX < 0 || cellY < 0) return;
27200280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        for (int x = cellX; x < cellX + spanX && x < mCountX; x++) {
27210280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            for (int y = cellY; y < cellY + spanY && y < mCountY; y++) {
2722482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                occupied[x][y] = value;
272331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            }
272431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
272531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
272631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
27272801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    public int getDesiredWidth() {
27288b805b17158886035b38261eb611d8641701ae43Michael Jurka        return getPaddingLeft() + getPaddingRight() + (mCountX * mCellWidth) +
27292801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen                (Math.max((mCountX - 1), 0) * mWidthGap);
27302801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    }
27312801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
27322801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    public int getDesiredHeight()  {
27338b805b17158886035b38261eb611d8641701ae43Michael Jurka        return getPaddingTop() + getPaddingBottom() + (mCountY * mCellHeight) +
27342801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen                (Math.max((mCountY - 1), 0) * mHeightGap);
27352801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    }
27362801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
273766d72178af91d455700875635473be942bc90e54Michael Jurka    public boolean isOccupied(int x, int y) {
273866d72178af91d455700875635473be942bc90e54Michael Jurka        if (x < mCountX && y < mCountY) {
273966d72178af91d455700875635473be942bc90e54Michael Jurka            return mOccupied[x][y];
274066d72178af91d455700875635473be942bc90e54Michael Jurka        } else {
274166d72178af91d455700875635473be942bc90e54Michael Jurka            throw new RuntimeException("Position exceeds the bound of this CellLayout");
274266d72178af91d455700875635473be942bc90e54Michael Jurka        }
274366d72178af91d455700875635473be942bc90e54Michael Jurka    }
274466d72178af91d455700875635473be942bc90e54Michael Jurka
274531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
274631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
274731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        return new CellLayout.LayoutParams(getContext(), attrs);
274831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
274931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
275031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
275131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
275231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        return p instanceof CellLayout.LayoutParams;
275331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
275431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
275531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
275631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
275731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        return new CellLayout.LayoutParams(p);
275831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
275931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
2760aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung    public static class CellLayoutAnimationController extends LayoutAnimationController {
2761aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        public CellLayoutAnimationController(Animation animation, float delay) {
2762aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            super(animation, delay);
2763aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        }
2764aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
2765aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        @Override
2766aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        protected long getDelayForView(View view) {
2767aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            return (int) (Math.random() * 150);
2768aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        }
2769aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung    }
2770aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
277131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public static class LayoutParams extends ViewGroup.MarginLayoutParams {
277231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        /**
277331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         * Horizontal location of the item in the grid.
277431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         */
277531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        @ViewDebug.ExportedProperty
277631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public int cellX;
277731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
277831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        /**
277931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         * Vertical location of the item in the grid.
278031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         */
278131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        @ViewDebug.ExportedProperty
278231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public int cellY;
278331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
278431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        /**
2785482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         * Temporary horizontal location of the item in the grid during reorder
2786482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         */
2787482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        public int tmpCellX;
2788482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2789482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        /**
2790482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         * Temporary vertical location of the item in the grid during reorder
2791482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         */
2792482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        public int tmpCellY;
2793482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2794482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        /**
2795482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         * Indicates that the temporary coordinates should be used to layout the items
2796482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         */
2797482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        public boolean useTmpCoords;
2798482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2799482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        /**
280031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         * Number of cells spanned horizontally by the item.
280131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         */
280231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        @ViewDebug.ExportedProperty
280331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public int cellHSpan;
280431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
280531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        /**
280631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         * Number of cells spanned vertically by the item.
280731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         */
280831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        @ViewDebug.ExportedProperty
280931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public int cellVSpan;
2810aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
28111b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen        /**
28121b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen         * Indicates whether the item will set its x, y, width and height parameters freely,
28131b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen         * or whether these will be computed based on cellX, cellY, cellHSpan and cellVSpan.
28141b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen         */
2815d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        public boolean isLockedToGrid = true;
2816d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
2817482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        /**
2818482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         * Indicates whether this item can be reordered. Always true except in the case of the
2819482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         * the AllApps button.
2820482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         */
2821482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        public boolean canReorder = true;
2822482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
282331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // X coordinate of the view in the layout.
282431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        @ViewDebug.ExportedProperty
282531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int x;
282631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // Y coordinate of the view in the layout.
282731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        @ViewDebug.ExportedProperty
282831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int y;
282931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
283084f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy        boolean dropped;
2831fcb9e7144e58614f5ae0e9b272fb7ce040848c67Romain Guy
283231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public LayoutParams(Context c, AttributeSet attrs) {
283331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            super(c, attrs);
283431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            cellHSpan = 1;
283531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            cellVSpan = 1;
283631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
283731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
283831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public LayoutParams(ViewGroup.LayoutParams source) {
283931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            super(source);
284031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            cellHSpan = 1;
284131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            cellVSpan = 1;
284231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
2843aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
2844aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        public LayoutParams(LayoutParams source) {
2845aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            super(source);
2846aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            this.cellX = source.cellX;
2847aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            this.cellY = source.cellY;
2848aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            this.cellHSpan = source.cellHSpan;
2849aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            this.cellVSpan = source.cellVSpan;
2850aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        }
2851aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
285231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public LayoutParams(int cellX, int cellY, int cellHSpan, int cellVSpan) {
28538f19cdd62f6e2be05e3890916eabd11317ae1bc2Romain Guy            super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
285431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            this.cellX = cellX;
285531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            this.cellY = cellY;
285631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            this.cellHSpan = cellHSpan;
285731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            this.cellVSpan = cellVSpan;
285831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
285931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
28607f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public void setup(int cellWidth, int cellHeight, int widthGap, int heightGap) {
2861d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            if (isLockedToGrid) {
2862d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                final int myCellHSpan = cellHSpan;
2863d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                final int myCellVSpan = cellVSpan;
2864482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                final int myCellX = useTmpCoords ? tmpCellX : cellX;
2865482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                final int myCellY = useTmpCoords ? tmpCellY : cellY;
28661b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen
2867d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                width = myCellHSpan * cellWidth + ((myCellHSpan - 1) * widthGap) -
2868d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                        leftMargin - rightMargin;
2869d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                height = myCellVSpan * cellHeight + ((myCellVSpan - 1) * heightGap) -
2870d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                        topMargin - bottomMargin;
2871eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                x = (int) (myCellX * (cellWidth + widthGap) + leftMargin);
2872eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                y = (int) (myCellY * (cellHeight + heightGap) + topMargin);
2873d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            }
2874d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        }
2875d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
2876aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        public String toString() {
2877aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            return "(" + this.cellX + ", " + this.cellY + ")";
2878aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        }
28797f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
28807f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public void setWidth(int width) {
28817f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            this.width = width;
28827f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
28837f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
28847f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public int getWidth() {
28857f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            return width;
28867f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
28877f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
28887f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public void setHeight(int height) {
28897f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            this.height = height;
28907f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
28917f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
28927f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public int getHeight() {
28937f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            return height;
28947f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
28957f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
28967f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public void setX(int x) {
28977f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            this.x = x;
28987f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
28997f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
29007f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public int getX() {
29017f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            return x;
29027f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
29037f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
29047f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public void setY(int y) {
29057f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            this.y = y;
29067f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
29077f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
29087f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public int getY() {
29097f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            return y;
29107f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
291131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
291231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
29130280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    // This class stores info for two purposes:
29140280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    // 1. When dragging items (mDragInfo in Workspace), we store the View, its cellX & cellY,
29150280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    //    its spanX, spanY, and the screen it is on
29160280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    // 2. When long clicking on an empty cell in a CellLayout, we save information about the
29170280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    //    cellX and cellY coordinates and which page was clicked. We then set this as a tag on
29180280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    //    the CellLayout that was long clicked
2919e5fb0f27bca7afb996258a7163c76ca7390d7bffMichael Jurka    static final class CellInfo {
292031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        View cell;
2921a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka        int cellX = -1;
2922a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka        int cellY = -1;
292331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int spanX;
292431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int spanY;
292531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int screen;
29263d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        long container;
292731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
292831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        @Override
292931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public String toString() {
2930aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            return "Cell[view=" + (cell == null ? "null" : cell.getClass())
2931aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung                    + ", x=" + cellX + ", y=" + cellY + "]";
293231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
293331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
2934d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka
2935d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka    public boolean lastDownOnOccupiedCell() {
2936d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka        return mLastDownOnOccupiedCell;
2937d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka    }
293831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project}
2939