CellLayout.java revision 19f3792523fe2d55ea791a9286398a6120920690
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;
204be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onoratoimport android.animation.AnimatorListenerAdapter;
2100397b1d9233409d9d6b233b077ae12d09768ce8Chet Haaseimport android.animation.TimeInterpolator;
22de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroyimport android.animation.ValueAnimator;
23de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroyimport android.animation.ValueAnimator.AnimatorUpdateListener;
2431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.content.Context;
2579e56263dbcbe85dc434df372bc6e6730aa13477Joe Onoratoimport android.content.res.Resources;
26aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chungimport android.content.res.TypedArray;
274be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onoratoimport android.graphics.Bitmap;
28aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chungimport android.graphics.Canvas;
290dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynnimport android.graphics.Color;
304be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onoratoimport android.graphics.Paint;
31de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroyimport android.graphics.Point;
32de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroyimport android.graphics.PointF;
33b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohenimport android.graphics.PorterDuff;
34b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohenimport android.graphics.PorterDuffXfermode;
3531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.graphics.Rect;
36482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohenimport android.graphics.drawable.ColorDrawable;
376569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroyimport android.graphics.drawable.Drawable;
38b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohenimport android.graphics.drawable.NinePatchDrawable;
3931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.util.AttributeSet;
404be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onoratoimport android.util.Log;
4131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.MotionEvent;
4231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.View;
4331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.ViewDebug;
4431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.ViewGroup;
45aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chungimport android.view.animation.Animation;
46150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chungimport android.view.animation.DecelerateInterpolator;
47aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chungimport android.view.animation.LayoutAnimationController;
4831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
496639687cd67bab1aeef2a75e5c6bc458b20dc082Adam Cohenimport com.android.launcher.R;
5069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohenimport com.android.launcher2.FolderIcon.FolderRingAnimator;
518e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy
5269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohenimport java.util.ArrayList;
53c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohenimport java.util.Arrays;
54bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohenimport java.util.HashMap;
55d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohenimport java.util.Stack;
56c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen
57bdb5c5342adc550559fd723af461e53248f2fba8Michael Jurkapublic class CellLayout extends ViewGroup {
58aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung    static final String TAG = "CellLayout";
59aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
604b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung    private int mOriginalCellWidth;
614b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung    private int mOriginalCellHeight;
6231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private int mCellWidth;
6331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private int mCellHeight;
64aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
65d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen    private int mCountX;
66d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen    private int mCountY;
6731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
68234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen    private int mOriginalWidthGap;
69234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen    private int mOriginalHeightGap;
7031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private int mWidthGap;
7131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private int mHeightGap;
724b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung    private int mMaxGap;
73ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen    private boolean mScrollingTransformsDirty = false;
7431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
7531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private final Rect mRect = new Rect();
7631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private final CellInfo mCellInfo = new CellInfo();
77aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
78de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy    // These are temporary variables to prevent having to allocate a new object just to
79de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy    // return an (x, y) value from helper functions. Do NOT use them to maintain other state.
800be025d64c1f84138fe430a58875886e66aae767Winson Chung    private final int[] mTmpXY = new int[2];
81de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy    private final int[] mTmpPoint = new int[2];
82de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy    private final PointF mTmpPointF = new PointF();
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
124de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy    private Drawable mCrosshairsDrawable = null;
12549250ad530385fcdd6072ca54697f670ec503b59Patrick Dubroy    private InterruptibleInOutAnimator mCrosshairsAnimator = null;
126de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy    private float mCrosshairsVisibility = 0.0f;
127de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy
128482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private HashMap<CellLayout.LayoutParams, Animator> mReorderAnimators = new
129482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            HashMap<CellLayout.LayoutParams, Animator>();
13019f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private HashMap<View, ReorderHintAnimation>
13119f3792523fe2d55ea791a9286398a6120920690Adam Cohen            mShakeAnimators = new HashMap<View, ReorderHintAnimation>();
13219f3792523fe2d55ea791a9286398a6120920690Adam Cohen
13319f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private boolean mItemPlacementDirty = false;
134bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen
1356569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    // When a drag operation is in progress, holds the nearest cell to the touch point
1366569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    private final int[] mDragCell = new int[2];
13731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
1384be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato    private boolean mDragging = false;
1394be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato
140ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy    private TimeInterpolator mEaseOutInterpolator;
141a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka    private ShortcutAndWidgetContainer mShortcutsAndWidgets;
142ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy
1430dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn    private boolean mIsHotseat = false;
144eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung    private float mChildScale = 1f;
145eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung    private float mHotseatChildScale = 1f;
1460dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn
147482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public static final int MODE_DRAG_OVER = 0;
148482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public static final int MODE_ON_DROP = 1;
149482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public static final int MODE_ON_DROP_EXTERNAL = 2;
150482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public static final int MODE_ACCEPT_DROP = 3;
15119f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private static final boolean DESTRUCTIVE_REORDER = false;
152482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private static final boolean DEBUG_VISUALIZE_OCCUPIED = false;
153482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
15419f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private static final float REORDER_HINT_MAGNITUDE = 0.27f;
15519f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private static final int REORDER_ANIMATION_DURATION = 150;
15619f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private float mReorderHintAnimationMagnitude;
15719f3792523fe2d55ea791a9286398a6120920690Adam Cohen
158482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private ArrayList<View> mIntersectingViews = new ArrayList<View>();
159482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private Rect mOccupiedRect = new Rect();
160482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private int[] mDirectionVector = new int[2];
16119f3792523fe2d55ea791a9286398a6120920690Adam Cohen    int[] mPreviousReorderDirection = new int[2];
162482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
16331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public CellLayout(Context context) {
16431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        this(context, null);
16531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
16631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
16731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public CellLayout(Context context, AttributeSet attrs) {
16831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        this(context, attrs, 0);
16931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
17031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
17131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public CellLayout(Context context, AttributeSet attrs, int defStyle) {
17231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        super(context, attrs, defStyle);
1736569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
1746569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        // A ViewGroup usually does not draw, but CellLayout needs to draw a rectangle to show
1756569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        // the user where a dragged item will land when dropped.
1766569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        setWillNotDraw(false);
177a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka
17831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CellLayout, defStyle, 0);
17931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
1804b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        mOriginalCellWidth =
1814b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung            mCellWidth = a.getDimensionPixelSize(R.styleable.CellLayout_cellWidth, 10);
1824b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        mOriginalCellHeight =
1834b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung            mCellHeight = a.getDimensionPixelSize(R.styleable.CellLayout_cellHeight, 10);
184234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen        mWidthGap = mOriginalWidthGap = a.getDimensionPixelSize(R.styleable.CellLayout_widthGap, 0);
185234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen        mHeightGap = mOriginalHeightGap = a.getDimensionPixelSize(R.styleable.CellLayout_heightGap, 0);
1864b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        mMaxGap = a.getDimensionPixelSize(R.styleable.CellLayout_maxGap, 0);
187d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        mCountX = LauncherModel.getCellCountX();
188d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        mCountY = LauncherModel.getCellCountY();
1890280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        mOccupied = new boolean[mCountX][mCountY];
190482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        mTmpOccupied = new boolean[mCountX][mCountY];
19131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
19231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        a.recycle();
19331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
19431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        setAlwaysDrawnWithCacheEnabled(false);
19531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
196046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        final Resources res = getResources();
197de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy
198967289b6d5fec77f5c381d11ffb2319f3bb5e737Winson Chung        mNormalBackground = res.getDrawable(R.drawable.homescreen_blue_normal_holo);
199dea74b7d12b0fcd50bfdb4274f9867ba76d75238Winson Chung        mActiveGlowBackground = res.getDrawable(R.drawable.homescreen_blue_strong_holo);
200b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung
201b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        mOverScrollLeft = res.getDrawable(R.drawable.overscroll_glow_left);
202b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        mOverScrollRight = res.getDrawable(R.drawable.overscroll_glow_right);
203b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        mForegroundPadding =
204b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen                res.getDimensionPixelSize(R.dimen.workspace_overscroll_drawable_padding);
205b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung
20619f3792523fe2d55ea791a9286398a6120920690Adam Cohen        mReorderHintAnimationMagnitude = (REORDER_HINT_MAGNITUDE *
20719f3792523fe2d55ea791a9286398a6120920690Adam Cohen                res.getDimensionPixelSize(R.dimen.app_icon_size));
20819f3792523fe2d55ea791a9286398a6120920690Adam Cohen
209b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung        mNormalBackground.setFilterBitmap(true);
210b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung        mActiveGlowBackground.setFilterBitmap(true);
211de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy
212eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung        int iconScale = res.getInteger(R.integer.app_icon_scale_percent);
213eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung        if (iconScale >= 0) {
214eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung            mChildScale = iconScale / 100f;
215eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung        }
216eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung        int hotseatIconScale = res.getInteger(R.integer.app_icon_hotseat_scale_percent);
217eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung        if (hotseatIconScale >= 0) {
218eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung            mHotseatChildScale = hotseatIconScale / 100f;
219eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung        }
2200dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn
221046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        // Initialize the data structures used for the drag visualization.
222150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung
223046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        mCrosshairsDrawable = res.getDrawable(R.drawable.gardening_crosshairs);
224ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy        mEaseOutInterpolator = new DecelerateInterpolator(2.5f); // Quint ease out
225de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy
226046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        // Set up the animation for fading the crosshairs in and out
227046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        int animDuration = res.getInteger(R.integer.config_crosshairsFadeInTime);
22849250ad530385fcdd6072ca54697f670ec503b59Patrick Dubroy        mCrosshairsAnimator = new InterruptibleInOutAnimator(animDuration, 0.0f, 1.0f);
229472b281d5cb4f5660df981a6c912266b9f5703feChet Haase        mCrosshairsAnimator.getAnimator().addUpdateListener(new AnimatorUpdateListener() {
230046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy            public void onAnimationUpdate(ValueAnimator animation) {
231046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy                mCrosshairsVisibility = ((Float) animation.getAnimatedValue()).floatValue();
2328e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy                invalidate();
233046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy            }
234046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        });
235ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy        mCrosshairsAnimator.getAnimator().setInterpolator(mEaseOutInterpolator);
236046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy
237b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung        mDragCell[0] = mDragCell[1] = -1;
2384be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        for (int i = 0; i < mDragOutlines.length; i++) {
239d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            mDragOutlines[i] = new Rect(-1, -1, -1, -1);
240046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        }
241046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy
242046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        // When dragging things around the home screens, we show a green outline of
243046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        // where the item will land. The outlines gradually fade out, leaving a trail
244046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        // behind the drag path.
245046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        // Set up all the animations that are used to implement this fading.
246046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        final int duration = res.getInteger(R.integer.config_dragOutlineFadeTime);
247472b281d5cb4f5660df981a6c912266b9f5703feChet Haase        final float fromAlphaValue = 0;
248472b281d5cb4f5660df981a6c912266b9f5703feChet Haase        final float toAlphaValue = (float)res.getInteger(R.integer.config_dragOutlineMaxAlpha);
2494be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato
2508e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy        Arrays.fill(mDragOutlineAlphas, fromAlphaValue);
2514be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato
2524be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        for (int i = 0; i < mDragOutlineAnims.length; i++) {
253046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy            final InterruptibleInOutAnimator anim =
254046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy                new InterruptibleInOutAnimator(duration, fromAlphaValue, toAlphaValue);
255ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy            anim.getAnimator().setInterpolator(mEaseOutInterpolator);
256046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy            final int thisIndex = i;
257472b281d5cb4f5660df981a6c912266b9f5703feChet Haase            anim.getAnimator().addUpdateListener(new AnimatorUpdateListener() {
258de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                public void onAnimationUpdate(ValueAnimator animation) {
2594be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    final Bitmap outline = (Bitmap)anim.getTag();
2604be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato
2614be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    // If an animation is started and then stopped very quickly, we can still
2624be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    // get spurious updates we've cleared the tag. Guard against this.
2634be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    if (outline == null) {
264fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy                        if (false) {
265fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy                            Object val = animation.getAnimatedValue();
266fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy                            Log.d(TAG, "anim " + thisIndex + " update: " + val +
267fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy                                     ", isStopped " + anim.isStopped());
268fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy                        }
2694be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                        // Try to prevent it from continuing to run
2704be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                        animation.cancel();
2714be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    } else {
272472b281d5cb4f5660df981a6c912266b9f5703feChet Haase                        mDragOutlineAlphas[thisIndex] = (Float) animation.getAnimatedValue();
273d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        CellLayout.this.invalidate(mDragOutlines[thisIndex]);
2744be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    }
275de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                }
276de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy            });
2774be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            // The animation holds a reference to the drag outline bitmap as long is it's
2784be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            // running. This way the bitmap can be GCed when the animations are complete.
279472b281d5cb4f5660df981a6c912266b9f5703feChet Haase            anim.getAnimator().addListener(new AnimatorListenerAdapter() {
2803c4c20fbe682cb4b3ef94f09afe0af09171583f3Michael Jurka                @Override
2814be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                public void onAnimationEnd(Animator animation) {
282472b281d5cb4f5660df981a6c912266b9f5703feChet Haase                    if ((Float) ((ValueAnimator) animation).getAnimatedValue() == 0f) {
2834be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                        anim.setTag(null);
2844be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    }
2854be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                }
2864be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            });
2874be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            mDragOutlineAnims[i] = anim;
288de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy        }
289ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy
29018014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka        mBackgroundRect = new Rect();
291b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        mForegroundRect = new Rect();
292bea15195346bab3c52b0156e92f2b71f0811b210Michael Jurka
293a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets = new ShortcutAndWidgetContainer(context);
294a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.setCellDimensions(mCellWidth, mCellHeight, mWidthGap, mHeightGap);
295a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        addView(mShortcutsAndWidgets);
29618014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka    }
29718014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka
298f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka    static int widthInPortrait(Resources r, int numCells) {
299f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka        // We use this method from Workspace to figure out how many rows/columns Launcher should
300f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka        // have. We ignore the left/right padding on CellLayout because it turns out in our design
301f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka        // the padding extends outside the visible screen size, but it looked fine anyway.
302f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka        int cellWidth = r.getDimensionPixelSize(R.dimen.workspace_cell_width);
3034b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        int minGap = Math.min(r.getDimensionPixelSize(R.dimen.workspace_width_gap),
3044b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                r.getDimensionPixelSize(R.dimen.workspace_height_gap));
305f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka
3064b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        return  minGap * (numCells - 1) + cellWidth * numCells;
307f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka    }
308f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka
309f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka    static int heightInLandscape(Resources r, int numCells) {
310f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka        // We use this method from Workspace to figure out how many rows/columns Launcher should
311f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka        // have. We ignore the left/right padding on CellLayout because it turns out in our design
312f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka        // the padding extends outside the visible screen size, but it looked fine anyway.
313f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka        int cellHeight = r.getDimensionPixelSize(R.dimen.workspace_cell_height);
3144b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        int minGap = Math.min(r.getDimensionPixelSize(R.dimen.workspace_width_gap),
3154b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                r.getDimensionPixelSize(R.dimen.workspace_height_gap));
316f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka
3174b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        return minGap * (numCells - 1) + cellHeight * numCells;
318f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka    }
319f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka
3202801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    public void enableHardwareLayers() {
321a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.enableHardwareLayers();
3222801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    }
3232801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
3242801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    public void setGridSize(int x, int y) {
3252801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        mCountX = x;
3262801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        mCountY = y;
3272801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        mOccupied = new boolean[mCountX][mCountY];
328482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        mTmpOccupied = new boolean[mCountX][mCountY];
32976fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        requestLayout();
3302801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    }
3312801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
33296864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy    private void invalidateBubbleTextView(BubbleTextView icon) {
33396864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        final int padding = icon.getPressedOrFocusedBackgroundPadding();
3344b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        invalidate(icon.getLeft() + getPaddingLeft() - padding,
3354b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                icon.getTop() + getPaddingTop() - padding,
3364b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                icon.getRight() + getPaddingLeft() + padding,
3374b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                icon.getBottom() + getPaddingTop() + padding);
33896864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy    }
33996864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy
340b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    void setOverScrollAmount(float r, boolean left) {
341b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        if (left && mOverScrollForegroundDrawable != mOverScrollLeft) {
342b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen            mOverScrollForegroundDrawable = mOverScrollLeft;
343b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        } else if (!left && mOverScrollForegroundDrawable != mOverScrollRight) {
344b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen            mOverScrollForegroundDrawable = mOverScrollRight;
345b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        }
346b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen
347b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        mForegroundAlpha = (int) Math.round((r * 255));
348b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        mOverScrollForegroundDrawable.setAlpha(mForegroundAlpha);
349b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        invalidate();
350b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    }
351b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen
35296864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy    void setPressedOrFocusedIcon(BubbleTextView icon) {
35396864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        // We draw the pressed or focused BubbleTextView's background in CellLayout because it
35496864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        // requires an expanded clip rect (due to the glow's blur radius)
35596864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        BubbleTextView oldIcon = mPressedOrFocusedIcon;
35696864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        mPressedOrFocusedIcon = icon;
35796864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        if (oldIcon != null) {
35896864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy            invalidateBubbleTextView(oldIcon);
35996864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        }
36096864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        if (mPressedOrFocusedIcon != null) {
36196864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy            invalidateBubbleTextView(mPressedOrFocusedIcon);
36296864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        }
36396864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy    }
36496864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy
36533945b21544bc98381df17726a3537c292d8c985Michael Jurka    void setIsDragOverlapping(boolean isDragOverlapping) {
36633945b21544bc98381df17726a3537c292d8c985Michael Jurka        if (mIsDragOverlapping != isDragOverlapping) {
36733945b21544bc98381df17726a3537c292d8c985Michael Jurka            mIsDragOverlapping = isDragOverlapping;
36833945b21544bc98381df17726a3537c292d8c985Michael Jurka            invalidate();
36933945b21544bc98381df17726a3537c292d8c985Michael Jurka        }
37033945b21544bc98381df17726a3537c292d8c985Michael Jurka    }
37133945b21544bc98381df17726a3537c292d8c985Michael Jurka
37233945b21544bc98381df17726a3537c292d8c985Michael Jurka    boolean getIsDragOverlapping() {
37333945b21544bc98381df17726a3537c292d8c985Michael Jurka        return mIsDragOverlapping;
37433945b21544bc98381df17726a3537c292d8c985Michael Jurka    }
37533945b21544bc98381df17726a3537c292d8c985Michael Jurka
376ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen    protected void setOverscrollTransformsDirty(boolean dirty) {
377ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen        mScrollingTransformsDirty = dirty;
378ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen    }
379ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen
380ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen    protected void resetOverscrollTransforms() {
381ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen        if (mScrollingTransformsDirty) {
382ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            setOverscrollTransformsDirty(false);
383ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            setTranslationX(0);
384ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            setRotationY(0);
385ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            // It doesn't matter if we pass true or false here, the important thing is that we
386ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            // pass 0, which results in the overscroll drawable not being drawn any more.
387ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            setOverScrollAmount(0, false);
388ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            setPivotX(getMeasuredWidth() / 2);
389ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            setPivotY(getMeasuredHeight() / 2);
390ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen        }
391ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen    }
392ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen
393a6abce8464b57ce91e8f083951ad263370fc2da8Romain Guy    @Override
3941262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy    protected void onDraw(Canvas canvas) {
3953e7c7634531302271270c8cf418abc959d621cbcMichael Jurka        // When we're large, we are either drawn in a "hover" state (ie when dragging an item to
3963e7c7634531302271270c8cf418abc959d621cbcMichael Jurka        // a neighboring page) or with just a normal background (if backgroundAlpha > 0.0f)
3973e7c7634531302271270c8cf418abc959d621cbcMichael Jurka        // When we're small, we are either drawn normally or in the "accepts drops" state (during
3983e7c7634531302271270c8cf418abc959d621cbcMichael Jurka        // a drag). However, we also drag the mini hover background *over* one of those two
3993e7c7634531302271270c8cf418abc959d621cbcMichael Jurka        // backgrounds
400b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung        if (mBackgroundAlpha > 0.0f) {
401f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen            Drawable bg;
40233945b21544bc98381df17726a3537c292d8c985Michael Jurka
40333945b21544bc98381df17726a3537c292d8c985Michael Jurka            if (mIsDragOverlapping) {
40433945b21544bc98381df17726a3537c292d8c985Michael Jurka                // In the mini case, we draw the active_glow bg *over* the active background
405bdf78559f223ac11e01e3311edd5a48a80383e1eMichael Jurka                bg = mActiveGlowBackground;
406f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen            } else {
407bdf78559f223ac11e01e3311edd5a48a80383e1eMichael Jurka                bg = mNormalBackground;
408f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen            }
40933945b21544bc98381df17726a3537c292d8c985Michael Jurka
41033945b21544bc98381df17726a3537c292d8c985Michael Jurka            bg.setAlpha((int) (mBackgroundAlpha * mBackgroundAlphaMultiplier * 255));
41133945b21544bc98381df17726a3537c292d8c985Michael Jurka            bg.setBounds(mBackgroundRect);
41233945b21544bc98381df17726a3537c292d8c985Michael Jurka            bg.draw(canvas);
413a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka        }
41431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
415de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy        if (mCrosshairsVisibility > 0.0f) {
416de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy            final int countX = mCountX;
417de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy            final int countY = mCountY;
418de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy
419de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy            final float MAX_ALPHA = 0.4f;
420de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy            final int MAX_VISIBLE_DISTANCE = 600;
421de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy            final float DISTANCE_MULTIPLIER = 0.002f;
422de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy
423de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy            final Drawable d = mCrosshairsDrawable;
424de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy            final int width = d.getIntrinsicWidth();
425de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy            final int height = d.getIntrinsicHeight();
426de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy
4274b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung            int x = getPaddingLeft() - (mWidthGap / 2) - (width / 2);
428de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy            for (int col = 0; col <= countX; col++) {
4294b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                int y = getPaddingTop() - (mHeightGap / 2) - (height / 2);
430de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                for (int row = 0; row <= countY; row++) {
431de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                    mTmpPointF.set(x - mDragCenter.x, y - mDragCenter.y);
432de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                    float dist = mTmpPointF.length();
433de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                    // Crosshairs further from the drag point are more faint
434de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                    float alpha = Math.min(MAX_ALPHA,
435de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                            DISTANCE_MULTIPLIER * (MAX_VISIBLE_DISTANCE - dist));
436de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                    if (alpha > 0.0f) {
437de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                        d.setBounds(x, y, x + width, y + height);
438de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                        d.setAlpha((int) (alpha * 255 * mCrosshairsVisibility));
439de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                        d.draw(canvas);
440de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                    }
441de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                    y += mCellHeight + mHeightGap;
442de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                }
443de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                x += mCellWidth + mWidthGap;
444de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy            }
4454be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        }
446150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung
4478e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy        final Paint paint = mDragOutlinePaint;
4484be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        for (int i = 0; i < mDragOutlines.length; i++) {
449472b281d5cb4f5660df981a6c912266b9f5703feChet Haase            final float alpha = mDragOutlineAlphas[i];
4504be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            if (alpha > 0) {
451d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                final Rect r = mDragOutlines[i];
4524be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                final Bitmap b = (Bitmap) mDragOutlineAnims[i].getTag();
453472b281d5cb4f5660df981a6c912266b9f5703feChet Haase                paint.setAlpha((int)(alpha + .5f));
454d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                canvas.drawBitmap(b, null, r, paint);
455150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung            }
4566569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        }
45796864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy
45896864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        // We draw the pressed or focused BubbleTextView's background in CellLayout because it
45996864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        // requires an expanded clip rect (due to the glow's blur radius)
46096864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        if (mPressedOrFocusedIcon != null) {
46196864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy            final int padding = mPressedOrFocusedIcon.getPressedOrFocusedBackgroundPadding();
46296864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy            final Bitmap b = mPressedOrFocusedIcon.getPressedOrFocusedBackground();
46396864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy            if (b != null) {
46496864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy                canvas.drawBitmap(b,
4654b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                        mPressedOrFocusedIcon.getLeft() + getPaddingLeft() - padding,
4664b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                        mPressedOrFocusedIcon.getTop() + getPaddingTop() - padding,
46796864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy                        null);
46896864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy            }
46996864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        }
47069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
471482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (DEBUG_VISUALIZE_OCCUPIED) {
472482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            int[] pt = new int[2];
473482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            ColorDrawable cd = new ColorDrawable(Color.RED);
474482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            cd.setBounds(0, 0, 80, 80);
475482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            for (int i = 0; i < mCountX; i++) {
476482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                for (int j = 0; j < mCountY; j++) {
477482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    if (mOccupied[i][j]) {
478482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        cellToPoint(i, j, pt);
479482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        canvas.save();
480482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        canvas.translate(pt[0], pt[1]);
481482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        cd.draw(canvas);
482482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        canvas.restore();
483482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    }
484482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                }
485482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
486482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
487482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
48869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        // The folder outer / inner ring image(s)
48969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        for (int i = 0; i < mFolderOuterRings.size(); i++) {
49069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            FolderRingAnimator fra = mFolderOuterRings.get(i);
49169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
49269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            // Draw outer ring
49369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            Drawable d = FolderRingAnimator.sSharedOuterRingDrawable;
49469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            int width = (int) fra.getOuterRingSize();
49569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            int height = width;
49669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            cellToPoint(fra.mCellX, fra.mCellY, mTempLocation);
49769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
49869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            int centerX = mTempLocation[0] + mCellWidth / 2;
49969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            int centerY = mTempLocation[1] + FolderRingAnimator.sPreviewSize / 2;
50069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
50169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            canvas.save();
50269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            canvas.translate(centerX - width / 2, centerY - height / 2);
50369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            d.setBounds(0, 0, width, height);
50469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            d.draw(canvas);
50569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            canvas.restore();
50669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
50769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            // Draw inner ring
50869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            d = FolderRingAnimator.sSharedInnerRingDrawable;
50969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            width = (int) fra.getInnerRingSize();
51069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            height = width;
51169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            cellToPoint(fra.mCellX, fra.mCellY, mTempLocation);
51269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
51369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            centerX = mTempLocation[0] + mCellWidth / 2;
51469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            centerY = mTempLocation[1] + FolderRingAnimator.sPreviewSize / 2;
51569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            canvas.save();
51669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            canvas.translate(centerX - width / 2, centerY - width / 2);
51769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            d.setBounds(0, 0, width, height);
51869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            d.draw(canvas);
51969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            canvas.restore();
52069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        }
521c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen
522c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        if (mFolderLeaveBehindCell[0] >= 0 && mFolderLeaveBehindCell[1] >= 0) {
523c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            Drawable d = FolderIcon.sSharedFolderLeaveBehind;
524c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            int width = d.getIntrinsicWidth();
525c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            int height = d.getIntrinsicHeight();
526c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen
527c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            cellToPoint(mFolderLeaveBehindCell[0], mFolderLeaveBehindCell[1], mTempLocation);
528c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            int centerX = mTempLocation[0] + mCellWidth / 2;
529c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            int centerY = mTempLocation[1] + FolderRingAnimator.sPreviewSize / 2;
530c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen
531c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            canvas.save();
532c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            canvas.translate(centerX - width / 2, centerY - width / 2);
533c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            d.setBounds(0, 0, width, height);
534c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            d.draw(canvas);
535c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            canvas.restore();
536c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        }
53769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen    }
53869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
539b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    @Override
540b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    protected void dispatchDraw(Canvas canvas) {
541b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        super.dispatchDraw(canvas);
542b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        if (mForegroundAlpha > 0) {
543b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen            mOverScrollForegroundDrawable.setBounds(mForegroundRect);
544b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen            Paint p = ((NinePatchDrawable) mOverScrollForegroundDrawable).getPaint();
545b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen            p.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.ADD));
546b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen            mOverScrollForegroundDrawable.draw(canvas);
547b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen            p.setXfermode(null);
548b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        }
549b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    }
550b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen
55169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen    public void showFolderAccept(FolderRingAnimator fra) {
55269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        mFolderOuterRings.add(fra);
55369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen    }
55469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
55569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen    public void hideFolderAccept(FolderRingAnimator fra) {
55669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        if (mFolderOuterRings.contains(fra)) {
55769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            mFolderOuterRings.remove(fra);
55869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        }
55969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        invalidate();
5606569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    }
5616569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
562c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen    public void setFolderLeaveBehindCell(int x, int y) {
563c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        mFolderLeaveBehindCell[0] = x;
564c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        mFolderLeaveBehindCell[1] = y;
565c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        invalidate();
566c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen    }
567c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen
568c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen    public void clearFolderLeaveBehind() {
569c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        mFolderLeaveBehindCell[0] = -1;
570c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        mFolderLeaveBehindCell[1] = -1;
571c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        invalidate();
572c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen    }
573c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen
5746569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    @Override
575e6235dd225404239b55c459245543f3302326112Michael Jurka    public boolean shouldDelayChildPressedState() {
576e6235dd225404239b55c459245543f3302326112Michael Jurka        return false;
577e6235dd225404239b55c459245543f3302326112Michael Jurka    }
578e6235dd225404239b55c459245543f3302326112Michael Jurka
579e6235dd225404239b55c459245543f3302326112Michael Jurka    @Override
58083f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey    public void cancelLongPress() {
58183f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey        super.cancelLongPress();
58283f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey
58383f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey        // Cancel long press for all children
58483f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey        final int count = getChildCount();
58583f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey        for (int i = 0; i < count; i++) {
58683f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey            final View child = getChildAt(i);
58783f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey            child.cancelLongPress();
58883f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey        }
58983f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey    }
59083f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey
591dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    public void setOnInterceptTouchListener(View.OnTouchListener listener) {
592dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka        mInterceptTouchListener = listener;
593dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    }
594dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka
59531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    int getCountX() {
596d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        return mCountX;
59731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
59831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
59931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    int getCountY() {
600d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        return mCountY;
60131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
60231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
6030dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn    public void setIsHotseat(boolean isHotseat) {
6040dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn        mIsHotseat = isHotseat;
6050dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn    }
6060dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn
607eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung    public float getChildrenScale() {
608eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung        return mIsHotseat ? mHotseatChildScale : mChildScale;
609eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung    }
610eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung
611f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka    public boolean addViewToCellLayout(
612f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka            View child, int index, int childId, LayoutParams params, boolean markCells) {
6130dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn        return addViewToCellLayout(child, index, childId, params, markCells, false);
6140dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn    }
6150dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn
616eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung    private void scaleChild(BubbleTextView bubbleChild, float pivot, float scale) {
617bc239a15464f543a41b960b946aa77258454efafAndrew Flynn        // If we haven't measured the child yet, do it now
618bc239a15464f543a41b960b946aa77258454efafAndrew Flynn        // (this happens if we're being dropped from all-apps
619bc239a15464f543a41b960b946aa77258454efafAndrew Flynn        if (bubbleChild.getLayoutParams() instanceof LayoutParams &&
620bc239a15464f543a41b960b946aa77258454efafAndrew Flynn                (bubbleChild.getMeasuredWidth() | bubbleChild.getMeasuredHeight()) == 0) {
621a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            getShortcutsAndWidgets().measureChild(bubbleChild);
622bc239a15464f543a41b960b946aa77258454efafAndrew Flynn        }
623bc239a15464f543a41b960b946aa77258454efafAndrew Flynn
624bc239a15464f543a41b960b946aa77258454efafAndrew Flynn        bubbleChild.setScaleX(scale);
625bc239a15464f543a41b960b946aa77258454efafAndrew Flynn        bubbleChild.setScaleY(scale);
626bc239a15464f543a41b960b946aa77258454efafAndrew Flynn    }
627bc239a15464f543a41b960b946aa77258454efafAndrew Flynn
628bc239a15464f543a41b960b946aa77258454efafAndrew Flynn    private void resetChild(BubbleTextView bubbleChild) {
629bc239a15464f543a41b960b946aa77258454efafAndrew Flynn        bubbleChild.setScaleX(1f);
630bc239a15464f543a41b960b946aa77258454efafAndrew Flynn        bubbleChild.setScaleY(1f);
631bc239a15464f543a41b960b946aa77258454efafAndrew Flynn
632bc239a15464f543a41b960b946aa77258454efafAndrew Flynn        bubbleChild.setTextColor(getResources().getColor(R.color.workspace_icon_text_color));
633bc239a15464f543a41b960b946aa77258454efafAndrew Flynn    }
634bc239a15464f543a41b960b946aa77258454efafAndrew Flynn
6350dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn    public boolean addViewToCellLayout(View child, int index, int childId, LayoutParams params,
6360dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn            boolean markCells, boolean allApps) {
637aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        final LayoutParams lp = params;
638aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
6390dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn        // Hotseat icons - scale down and remove text
6400dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn        // Don't scale the all apps button
6410dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn        // scale percent set to -1 means do not scale
6420dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn        // Only scale BubbleTextViews
6430dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn        if (child instanceof BubbleTextView) {
6440dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn            BubbleTextView bubbleChild = (BubbleTextView) child;
6450dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn
646bc239a15464f543a41b960b946aa77258454efafAndrew Flynn            // Start the child with 100% scale and visible text
647bc239a15464f543a41b960b946aa77258454efafAndrew Flynn            resetChild(bubbleChild);
648bc239a15464f543a41b960b946aa77258454efafAndrew Flynn
649eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung            if (mIsHotseat && !allApps && mHotseatChildScale >= 0) {
650bc239a15464f543a41b960b946aa77258454efafAndrew Flynn                // Scale/make transparent for a hotseat
651eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                scaleChild(bubbleChild, 0f, mHotseatChildScale);
6520dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn
653bc239a15464f543a41b960b946aa77258454efafAndrew Flynn                bubbleChild.setTextColor(getResources().getColor(android.R.color.transparent));
654eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung            } else if (mChildScale >= 0) {
655bc239a15464f543a41b960b946aa77258454efafAndrew Flynn                // Else possibly still scale it if we need to for smaller icons
656eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                scaleChild(bubbleChild, 0f, mChildScale);
6570dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn            }
6580dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn        }
6590dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn
66031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // Generate an id for each view, this assumes we have at most 256x256 cells
66131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // per workspace screen
662d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        if (lp.cellX >= 0 && lp.cellX <= mCountX - 1 && lp.cellY >= 0 && lp.cellY <= mCountY - 1) {
663aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            // If the horizontal or vertical span is set to -1, it is taken to
664aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            // mean that it spans the extent of the CellLayout
665d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen            if (lp.cellHSpan < 0) lp.cellHSpan = mCountX;
666d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen            if (lp.cellVSpan < 0) lp.cellVSpan = mCountY;
667aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
668aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            child.setId(childId);
66931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
670a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            mShortcutsAndWidgets.addView(child, index, lp);
671dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka
672f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka            if (markCells) markCellsAsOccupiedForView(child);
6730280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
674aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            return true;
675aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        }
676aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        return false;
67731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
6783e7c7634531302271270c8cf418abc959d621cbcMichael Jurka
67931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
6800280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public void removeAllViews() {
6810280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        clearOccupiedCells();
682a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.removeAllViews();
6830280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
6840280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
6850280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    @Override
6860280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public void removeAllViewsInLayout() {
687a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        if (mShortcutsAndWidgets.getChildCount() > 0) {
6887cfc2825c3a1029f962d2fc387ae2eaa85b51798Michael Jurka            clearOccupiedCells();
689a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            mShortcutsAndWidgets.removeAllViewsInLayout();
6907cfc2825c3a1029f962d2fc387ae2eaa85b51798Michael Jurka        }
6910280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
6920280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
693f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka    public void removeViewWithoutMarkingCells(View view) {
694a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.removeView(view);
695f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka    }
696f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka
6970280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    @Override
6980280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public void removeView(View view) {
6990280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        markCellsAsUnoccupiedForView(view);
700a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.removeView(view);
7010280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
7020280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
7030280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    @Override
7040280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public void removeViewAt(int index) {
705a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        markCellsAsUnoccupiedForView(mShortcutsAndWidgets.getChildAt(index));
706a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.removeViewAt(index);
7070280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
7080280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
7090280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    @Override
7100280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public void removeViewInLayout(View view) {
7110280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        markCellsAsUnoccupiedForView(view);
712a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.removeViewInLayout(view);
7130280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
7140280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
7150280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    @Override
7160280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public void removeViews(int start, int count) {
7170280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        for (int i = start; i < start + count; i++) {
718a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            markCellsAsUnoccupiedForView(mShortcutsAndWidgets.getChildAt(i));
7190280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        }
720a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.removeViews(start, count);
7210280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
7220280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
7230280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    @Override
7240280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public void removeViewsInLayout(int start, int count) {
7250280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        for (int i = start; i < start + count; i++) {
726a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            markCellsAsUnoccupiedForView(mShortcutsAndWidgets.getChildAt(i));
7270280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        }
728a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.removeViewsInLayout(start, count);
729abded66084680bb31cc7ea403c88f44f79a3c884Michael Jurka    }
730abded66084680bb31cc7ea403c88f44f79a3c884Michael Jurka
73131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
73231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    protected void onAttachedToWindow() {
73331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        super.onAttachedToWindow();
73431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        mCellInfo.screen = ((ViewGroup) getParent()).indexOfChild(this);
73531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
73631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
737af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka    public void setTagToCellInfoForPoint(int touchX, int touchY) {
73831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        final CellInfo cellInfo = mCellInfo;
739eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung        Rect frame = mRect;
740af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka        final int x = touchX + mScrollX;
741af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka        final int y = touchY + mScrollY;
742a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        final int count = mShortcutsAndWidgets.getChildCount();
74331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
744af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka        boolean found = false;
745af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka        for (int i = count - 1; i >= 0; i--) {
746a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            final View child = mShortcutsAndWidgets.getChildAt(i);
747d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
748af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka
7491b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen            if ((child.getVisibility() == VISIBLE || child.getAnimation() != null) &&
7501b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen                    lp.isLockedToGrid) {
751af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                child.getHitRect(frame);
7520be025d64c1f84138fe430a58875886e66aae767Winson Chung
753eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                float scale = child.getScaleX();
754eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                frame = new Rect(child.getLeft(), child.getTop(), child.getRight(),
755eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                        child.getBottom());
7560be025d64c1f84138fe430a58875886e66aae767Winson Chung                // The child hit rect is relative to the CellLayoutChildren parent, so we need to
7570be025d64c1f84138fe430a58875886e66aae767Winson Chung                // offset that by this CellLayout's padding to test an (x,y) point that is relative
7580be025d64c1f84138fe430a58875886e66aae767Winson Chung                // to this view.
7594b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                frame.offset(mPaddingLeft, mPaddingTop);
760eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                frame.inset((int) (frame.width() * (1f - scale) / 2),
761eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                        (int) (frame.height() * (1f - scale) / 2));
7620be025d64c1f84138fe430a58875886e66aae767Winson Chung
763af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                if (frame.contains(x, y)) {
764af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                    cellInfo.cell = child;
765af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                    cellInfo.cellX = lp.cellX;
766af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                    cellInfo.cellY = lp.cellY;
767af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                    cellInfo.spanX = lp.cellHSpan;
768af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                    cellInfo.spanY = lp.cellVSpan;
769af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                    found = true;
770af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                    break;
77131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                }
77231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            }
773af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka        }
774aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
775d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka        mLastDownOnOccupiedCell = found;
776d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka
777af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka        if (!found) {
7780be025d64c1f84138fe430a58875886e66aae767Winson Chung            final int cellXY[] = mTmpXY;
779af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka            pointToCellExact(x, y, cellXY);
78031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
781af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka            cellInfo.cell = null;
782af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka            cellInfo.cellX = cellXY[0];
783af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka            cellInfo.cellY = cellXY[1];
784af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka            cellInfo.spanX = 1;
785af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka            cellInfo.spanY = 1;
786af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka        }
787af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka        setTag(cellInfo);
788af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka    }
78931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
790af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka    @Override
791af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka    public boolean onInterceptTouchEvent(MotionEvent ev) {
792c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        // First we clear the tag to ensure that on every touch down we start with a fresh slate,
793c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        // even in the case where we return early. Not clearing here was causing bugs whereby on
794c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        // long-press we'd end up picking up an item from a previous drag operation.
795c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        final int action = ev.getAction();
796c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen
797c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        if (action == MotionEvent.ACTION_DOWN) {
798c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen            clearTagCellInfo();
799c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        }
800c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen
801dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka        if (mInterceptTouchListener != null && mInterceptTouchListener.onTouch(this, ev)) {
802dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka            return true;
803dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka        }
80431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
805af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka        if (action == MotionEvent.ACTION_DOWN) {
806af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka            setTagToCellInfoForPoint((int) ev.getX(), (int) ev.getY());
80731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
808eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung
80931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        return false;
81031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
81131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
812c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen    private void clearTagCellInfo() {
813c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        final CellInfo cellInfo = mCellInfo;
814c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        cellInfo.cell = null;
815c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        cellInfo.cellX = -1;
816c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        cellInfo.cellY = -1;
817c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        cellInfo.spanX = 0;
818c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        cellInfo.spanY = 0;
819c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        setTag(cellInfo);
820c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen    }
821c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen
82231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public CellInfo getTag() {
8230280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        return (CellInfo) super.getTag();
82431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
82531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
8266569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    /**
827aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     * Given a point, return the cell that strictly encloses that point
82831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param x X coordinate of the point
82931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param y Y coordinate of the point
83031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param result Array of 2 ints to hold the x and y coordinate of the cell
83131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
83231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    void pointToCellExact(int x, int y, int[] result) {
8334b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int hStartPadding = getPaddingLeft();
8344b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int vStartPadding = getPaddingTop();
83531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
83631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        result[0] = (x - hStartPadding) / (mCellWidth + mWidthGap);
83731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        result[1] = (y - vStartPadding) / (mCellHeight + mHeightGap);
83831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
839d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        final int xAxis = mCountX;
840d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        final int yAxis = mCountY;
84131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
84231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        if (result[0] < 0) result[0] = 0;
84331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        if (result[0] >= xAxis) result[0] = xAxis - 1;
84431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        if (result[1] < 0) result[1] = 0;
84531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        if (result[1] >= yAxis) result[1] = yAxis - 1;
84631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
847aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
84831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
84931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * Given a point, return the cell that most closely encloses that point
85031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param x X coordinate of the point
85131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param y Y coordinate of the point
85231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param result Array of 2 ints to hold the x and y coordinate of the cell
85331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
85431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    void pointToCellRounded(int x, int y, int[] result) {
85531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        pointToCellExact(x + (mCellWidth / 2), y + (mCellHeight / 2), result);
85631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
85731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
85831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
85931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * Given a cell coordinate, return the point that represents the upper left corner of that cell
860aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     *
861aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     * @param cellX X coordinate of the cell
86231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param cellY Y coordinate of the cell
863aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     *
86431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param result Array of 2 ints to hold the x and y coordinate of the point
86531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
86631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    void cellToPoint(int cellX, int cellY, int[] result) {
8674b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int hStartPadding = getPaddingLeft();
8684b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int vStartPadding = getPaddingTop();
86931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
87031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        result[0] = hStartPadding + cellX * (mCellWidth + mWidthGap);
87131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        result[1] = vStartPadding + cellY * (mCellHeight + mHeightGap);
87231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
87331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
874e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen    /**
875482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * Given a cell coordinate, return the point that represents the center of the cell
876e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen     *
877e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen     * @param cellX X coordinate of the cell
878e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen     * @param cellY Y coordinate of the cell
879e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen     *
880e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen     * @param result Array of 2 ints to hold the x and y coordinate of the point
881e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen     */
882e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen    void cellToCenterPoint(int cellX, int cellY, int[] result) {
88347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        regionToCenterPoint(cellX, cellY, 1, 1, result);
88447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    }
88547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
88647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    /**
88747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * Given a cell coordinate and span return the point that represents the center of the regio
88847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     *
88947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param cellX X coordinate of the cell
89047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param cellY Y coordinate of the cell
89147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     *
89247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param result Array of 2 ints to hold the x and y coordinate of the point
89347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     */
89447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    void regionToCenterPoint(int cellX, int cellY, int spanX, int spanY, int[] result) {
8954b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int hStartPadding = getPaddingLeft();
8964b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int vStartPadding = getPaddingTop();
89747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        result[0] = hStartPadding + cellX * (mCellWidth + mWidthGap) +
89847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                (spanX * mCellWidth + (spanX - 1) * mWidthGap) / 2;
89947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        result[1] = vStartPadding + cellY * (mCellHeight + mHeightGap) +
90047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                (spanY * mCellHeight + (spanY - 1) * mHeightGap) / 2;
901e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen    }
902e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen
90319f3792523fe2d55ea791a9286398a6120920690Adam Cohen     /**
90419f3792523fe2d55ea791a9286398a6120920690Adam Cohen     * Given a cell coordinate and span fills out a corresponding pixel rect
90519f3792523fe2d55ea791a9286398a6120920690Adam Cohen     *
90619f3792523fe2d55ea791a9286398a6120920690Adam Cohen     * @param cellX X coordinate of the cell
90719f3792523fe2d55ea791a9286398a6120920690Adam Cohen     * @param cellY Y coordinate of the cell
90819f3792523fe2d55ea791a9286398a6120920690Adam Cohen     * @param result Rect in which to write the result
90919f3792523fe2d55ea791a9286398a6120920690Adam Cohen     */
91019f3792523fe2d55ea791a9286398a6120920690Adam Cohen     void regionToRect(int cellX, int cellY, int spanX, int spanY, Rect result) {
91119f3792523fe2d55ea791a9286398a6120920690Adam Cohen        final int hStartPadding = getPaddingLeft();
91219f3792523fe2d55ea791a9286398a6120920690Adam Cohen        final int vStartPadding = getPaddingTop();
91319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        final int left = hStartPadding + cellX * (mCellWidth + mWidthGap);
91419f3792523fe2d55ea791a9286398a6120920690Adam Cohen        final int top = vStartPadding + cellY * (mCellHeight + mHeightGap);
91519f3792523fe2d55ea791a9286398a6120920690Adam Cohen        result.set(left, top, left + (spanX * mCellWidth + (spanX - 1) * mWidthGap),
91619f3792523fe2d55ea791a9286398a6120920690Adam Cohen                top + (spanY * mCellHeight + (spanY - 1) * mHeightGap));
91719f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
91819f3792523fe2d55ea791a9286398a6120920690Adam Cohen
919482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public float getDistanceFromCell(float x, float y, int[] cell) {
920482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        cellToCenterPoint(cell[0], cell[1], mTmpPoint);
921482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        float distance = (float) Math.sqrt( Math.pow(x - mTmpPoint[0], 2) +
922482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                Math.pow(y - mTmpPoint[1], 2));
923482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return distance;
924482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
925482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
92684f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy    int getCellWidth() {
92784f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy        return mCellWidth;
92884f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy    }
92984f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy
93084f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy    int getCellHeight() {
93184f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy        return mCellHeight;
93284f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy    }
93384f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy
934d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    int getWidthGap() {
935d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        return mWidthGap;
936d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    }
937d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
938d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    int getHeightGap() {
939d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        return mHeightGap;
940d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    }
941d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
9427f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen    Rect getContentRect(Rect r) {
9437f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        if (r == null) {
9447f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            r = new Rect();
9457f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
9467f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        int left = getPaddingLeft();
9477f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        int top = getPaddingTop();
9484b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        int right = left + getWidth() - mPaddingLeft - mPaddingRight;
9494b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        int bottom = top + getHeight() - mPaddingTop - mPaddingBottom;
9507f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        r.set(left, top, right, bottom);
9517f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        return r;
9527f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen    }
9537f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
95431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
95531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
95631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // TODO: currently ignoring padding
957aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
95831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
959aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
960aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
96131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
96231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int heightSpecSize =  MeasureSpec.getSize(heightMeasureSpec);
963aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
96431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        if (widthSpecMode == MeasureSpec.UNSPECIFIED || heightSpecMode == MeasureSpec.UNSPECIFIED) {
96531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            throw new RuntimeException("CellLayout cannot have UNSPECIFIED dimensions");
96631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
96731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
968d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        int numWidthGaps = mCountX - 1;
969d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        int numHeightGaps = mCountY - 1;
970d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen
971234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen        if (mOriginalWidthGap < 0 || mOriginalHeightGap < 0) {
9724b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung            int hSpace = widthSpecSize - mPaddingLeft - mPaddingRight;
9734b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung            int vSpace = heightSpecSize - mPaddingTop - mPaddingBottom;
9744b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung            int hFreeSpace = hSpace - (mCountX * mOriginalCellWidth);
9754b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung            int vFreeSpace = vSpace - (mCountY * mOriginalCellHeight);
9764b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung            mWidthGap = Math.min(mMaxGap, numWidthGaps > 0 ? (hFreeSpace / numWidthGaps) : 0);
9774b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung            mHeightGap = Math.min(mMaxGap,numHeightGaps > 0 ? (vFreeSpace / numHeightGaps) : 0);
978a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            mShortcutsAndWidgets.setCellDimensions(mCellWidth, mCellHeight, mWidthGap, mHeightGap);
979234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen        } else {
980234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen            mWidthGap = mOriginalWidthGap;
981234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen            mHeightGap = mOriginalHeightGap;
982ece7f5b3b55cab646941123e03589241a61678e2Winson Chung        }
9835f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka
9848c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka        // Initial values correspond to widthSpecMode == MeasureSpec.EXACTLY
9858c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka        int newWidth = widthSpecSize;
9868c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka        int newHeight = heightSpecSize;
9878c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka        if (widthSpecMode == MeasureSpec.AT_MOST) {
9884b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung            newWidth = mPaddingLeft + mPaddingRight + (mCountX * mCellWidth) +
9898c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka                ((mCountX - 1) * mWidthGap);
9904b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung            newHeight = mPaddingTop + mPaddingBottom + (mCountY * mCellHeight) +
9918c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka                ((mCountY - 1) * mHeightGap);
9928c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka            setMeasuredDimension(newWidth, newHeight);
9938c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka        }
99431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
9958c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka        int count = getChildCount();
99631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        for (int i = 0; i < count; i++) {
99731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            View child = getChildAt(i);
9984b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung            int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(newWidth - mPaddingLeft -
9994b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                    mPaddingRight, MeasureSpec.EXACTLY);
10004b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung            int childheightMeasureSpec = MeasureSpec.makeMeasureSpec(newHeight - mPaddingTop -
10014b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                    mPaddingBottom, MeasureSpec.EXACTLY);
100231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            child.measure(childWidthMeasureSpec, childheightMeasureSpec);
100331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
10048c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka        setMeasuredDimension(newWidth, newHeight);
100531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
100631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
100731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
100828750fba6a2d141eb9a1e566718c17236030b815Michael Jurka    protected void onLayout(boolean changed, int l, int t, int r, int b) {
100931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int count = getChildCount();
101031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        for (int i = 0; i < count; i++) {
10118c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka            View child = getChildAt(i);
10124b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung            child.layout(mPaddingLeft, mPaddingTop,
10134b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                    r - l - mPaddingRight, b - t - mPaddingBottom);
101431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
101531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
101631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
101731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
1018dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
1019dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka        super.onSizeChanged(w, h, oldw, oldh);
102018014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka        mBackgroundRect.set(0, 0, w, h);
1021b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        mForegroundRect.set(mForegroundPadding, mForegroundPadding,
1022b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen                w - 2 * mForegroundPadding, h - 2 * mForegroundPadding);
1023dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    }
1024dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka
1025dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    @Override
102631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    protected void setChildrenDrawingCacheEnabled(boolean enabled) {
1027a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.setChildrenDrawingCacheEnabled(enabled);
102831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
102931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
103031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
103131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    protected void setChildrenDrawnWithCacheEnabled(boolean enabled) {
1032a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.setChildrenDrawnWithCacheEnabled(enabled);
103331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
103431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
10355f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka    public float getBackgroundAlpha() {
10365f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka        return mBackgroundAlpha;
1037dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    }
1038dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka
10391b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen    public void setBackgroundAlphaMultiplier(float multiplier) {
10401b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen        mBackgroundAlphaMultiplier = multiplier;
10411b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen    }
10421b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen
1043ddb821981e0919bbd3b4c9a2b6aa1811d6c86bb6Adam Cohen    public float getBackgroundAlphaMultiplier() {
1044ddb821981e0919bbd3b4c9a2b6aa1811d6c86bb6Adam Cohen        return mBackgroundAlphaMultiplier;
1045ddb821981e0919bbd3b4c9a2b6aa1811d6c86bb6Adam Cohen    }
1046ddb821981e0919bbd3b4c9a2b6aa1811d6c86bb6Adam Cohen
10475f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka    public void setBackgroundAlpha(float alpha) {
1048afaa05014e0bf3ed1192f9ddec2af4283bc50248Michael Jurka        if (mBackgroundAlpha != alpha) {
1049afaa05014e0bf3ed1192f9ddec2af4283bc50248Michael Jurka            mBackgroundAlpha = alpha;
1050afaa05014e0bf3ed1192f9ddec2af4283bc50248Michael Jurka            invalidate();
1051afaa05014e0bf3ed1192f9ddec2af4283bc50248Michael Jurka        }
1052dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    }
1053dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka
1054a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka    public void setShortcutAndWidgetAlpha(float alpha) {
10550142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka        final int childCount = getChildCount();
10560142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka        for (int i = 0; i < childCount; i++) {
1057dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka            getChildAt(i).setAlpha(alpha);
1058dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka        }
1059dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    }
1060dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka
1061a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka    public ShortcutAndWidgetContainer getShortcutsAndWidgets() {
1062a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        if (getChildCount() > 0) {
1063a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            return (ShortcutAndWidgetContainer) getChildAt(0);
1064a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        }
1065a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        return null;
1066a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka    }
1067a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka
1068440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy    public View getChildAt(int x, int y) {
1069a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        return mShortcutsAndWidgets.getChildAt(x, y);
1070440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy    }
1071440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy
107276fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    public boolean animateChildToPosition(final View child, int cellX, int cellY, int duration,
1073482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            int delay, boolean permanent, boolean adjustOccupied) {
1074a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        ShortcutAndWidgetContainer clc = getShortcutsAndWidgets();
1075482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        boolean[][] occupied = mOccupied;
1076482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (!permanent) {
1077482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            occupied = mTmpOccupied;
1078482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1079482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
108019f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if (clc.indexOfChild(child) != -1) {
1081bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
1082bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            final ItemInfo info = (ItemInfo) child.getTag();
1083bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen
1084bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            // We cancel any existing animations
1085bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            if (mReorderAnimators.containsKey(lp)) {
1086bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                mReorderAnimators.get(lp).cancel();
1087bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                mReorderAnimators.remove(lp);
1088bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            }
1089bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen
1090482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            final int oldX = lp.x;
1091482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            final int oldY = lp.y;
1092482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (adjustOccupied) {
1093482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                occupied[lp.cellX][lp.cellY] = false;
1094482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                occupied[cellX][cellY] = true;
1095482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1096bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            lp.isLockedToGrid = true;
1097482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (permanent) {
1098482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                lp.cellX = info.cellX = cellX;
1099482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                lp.cellY = info.cellY = cellY;
1100482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            } else {
1101482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                lp.tmpCellX = cellX;
1102482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                lp.tmpCellY = cellY;
1103482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1104bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            clc.setupLp(lp);
1105bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            lp.isLockedToGrid = false;
1106482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            final int newX = lp.x;
1107482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            final int newY = lp.y;
1108bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen
110976fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen            lp.x = oldX;
111076fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen            lp.y = oldY;
111176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
1112482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            // Exit early if we're not actually moving the view
1113482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (oldX == newX && oldY == newY) {
1114482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                lp.isLockedToGrid = true;
1115482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                return true;
1116482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1117482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1118482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
1119482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            va.setDuration(duration);
1120482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            mReorderAnimators.put(lp, va);
1121482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1122482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            va.addUpdateListener(new AnimatorUpdateListener() {
1123482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                @Override
1124bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                public void onAnimationUpdate(ValueAnimator animation) {
1125482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    float r = ((Float) animation.getAnimatedValue()).floatValue();
112619f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    lp.x = (int) ((1 - r) * oldX + r * newX);
112719f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    lp.y = (int) ((1 - r) * oldY + r * newY);
11286b8a02d63a5d9cab8209381993e37db6a6afb753Adam Cohen                    child.requestLayout();
1129bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                }
1130bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            });
1131482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            va.addListener(new AnimatorListenerAdapter() {
1132bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                boolean cancelled = false;
1133bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                public void onAnimationEnd(Animator animation) {
1134bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    // If the animation was cancelled, it means that another animation
1135bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    // has interrupted this one, and we don't want to lock the item into
1136bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    // place just yet.
1137bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    if (!cancelled) {
1138bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                        lp.isLockedToGrid = true;
1139482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        child.requestLayout();
1140bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    }
1141bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    if (mReorderAnimators.containsKey(lp)) {
1142bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                        mReorderAnimators.remove(lp);
1143bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    }
1144bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                }
1145bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                public void onAnimationCancel(Animator animation) {
1146bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    cancelled = true;
1147bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                }
1148bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            });
1149482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            va.setStartDelay(delay);
1150482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            va.start();
1151bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            return true;
1152bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        }
1153bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        return false;
1154bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    }
1155bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen
11566569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    /**
11576569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     * Estimate where the top left cell of the dragged item will land if it is dropped.
11586569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     *
11596569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     * @param originX The X value of the top left corner of the item
11606569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     * @param originY The Y value of the top left corner of the item
11616569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     * @param spanX The number of horizontal cells that the item spans
11626569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     * @param spanY The number of vertical cells that the item spans
11636569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     * @param result The estimated drop cell X and Y.
11646569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     */
11656569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    void estimateDropCell(int originX, int originY, int spanX, int spanY, int[] result) {
1166d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        final int countX = mCountX;
1167d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        final int countY = mCountY;
11686569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
1169a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka        // pointToCellRounded takes the top left of a cell but will pad that with
1170a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka        // cellWidth/2 and cellHeight/2 when finding the matching cell
1171a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka        pointToCellRounded(originX, originY, result);
11726569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
11736569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        // If the item isn't fully on this screen, snap to the edges
11746569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        int rightOverhang = result[0] + spanX - countX;
11756569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        if (rightOverhang > 0) {
11766569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy            result[0] -= rightOverhang; // Snap to right
11776569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        }
11786569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        result[0] = Math.max(0, result[0]); // Snap to left
11796569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        int bottomOverhang = result[1] + spanY - countY;
11806569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        if (bottomOverhang > 0) {
11816569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy            result[1] -= bottomOverhang; // Snap to bottom
11826569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        }
11836569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        result[1] = Math.max(0, result[1]); // Snap to top
11846569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    }
11856569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
1186482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    void visualizeDropLocation(View v, Bitmap dragOutline, int originX, int originY, int cellX,
1187482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            int cellY, int spanX, int spanY, boolean resize, Point dragOffset, Rect dragRegion) {
118808ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy        final int oldDragCellX = mDragCell[0];
118908ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy        final int oldDragCellY = mDragCell[1];
1190482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1191b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung        if (v != null && dragOffset == null) {
1192a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung            mDragCenter.set(originX + (v.getWidth() / 2), originY + (v.getHeight() / 2));
1193a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung        } else {
1194a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung            mDragCenter.set(originX, originY);
1195a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung        }
11966569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
11972801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        if (dragOutline == null && v == null) {
11982801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            if (mCrosshairsDrawable != null) {
11992801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen                invalidate();
12002801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            }
12012801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            return;
12022801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        }
12032801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
1204482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (cellX != oldDragCellX || cellY != oldDragCellY) {
1205482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            mDragCell[0] = cellX;
1206482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            mDragCell[1] = cellY;
12076569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy            // Find the top left corner of the rect the object will occupy
1208de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy            final int[] topLeft = mTmpPoint;
1209482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            cellToPoint(cellX, cellY, topLeft);
1210de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy
12114be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            int left = topLeft[0];
12124be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            int top = topLeft[1];
12136569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
1214b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung            if (v != null && dragOffset == null) {
121599e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                // When drawing the drag outline, it did not account for margin offsets
121699e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                // added by the view's parent.
121799e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                MarginLayoutParams lp = (MarginLayoutParams) v.getLayoutParams();
121899e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                left += lp.leftMargin;
121999e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                top += lp.topMargin;
122099e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen
122199e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                // Offsets due to the size difference between the View and the dragOutline.
122299e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                // There is a size difference to account for the outer blur, which may lie
122399e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                // outside the bounds of the view.
1224a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung                top += (v.getHeight() - dragOutline.getHeight()) / 2;
1225ae915cecd36af4973061a1cb0b58c5be1be699a0Adam Cohen                // We center about the x axis
1226ae915cecd36af4973061a1cb0b58c5be1be699a0Adam Cohen                left += ((mCellWidth * spanX) + ((spanX - 1) * mWidthGap)
1227ae915cecd36af4973061a1cb0b58c5be1be699a0Adam Cohen                        - dragOutline.getWidth()) / 2;
12286639687cd67bab1aeef2a75e5c6bc458b20dc082Adam Cohen            } else {
1229b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                if (dragOffset != null && dragRegion != null) {
1230b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                    // Center the drag region *horizontally* in the cell and apply a drag
1231b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                    // outline offset
1232b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                    left += dragOffset.x + ((mCellWidth * spanX) + ((spanX - 1) * mWidthGap)
1233b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                             - dragRegion.width()) / 2;
1234b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                    top += dragOffset.y;
1235b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                } else {
1236b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                    // Center the drag outline in the cell
1237b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                    left += ((mCellWidth * spanX) + ((spanX - 1) * mWidthGap)
1238b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                            - dragOutline.getWidth()) / 2;
1239b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                    top += ((mCellHeight * spanY) + ((spanY - 1) * mHeightGap)
1240b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                            - dragOutline.getHeight()) / 2;
1241b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                }
1242a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung            }
12434be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            final int oldIndex = mDragOutlineCurrent;
124408ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy            mDragOutlineAnims[oldIndex].animateOut();
124508ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy            mDragOutlineCurrent = (oldIndex + 1) % mDragOutlines.length;
1246d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            Rect r = mDragOutlines[mDragOutlineCurrent];
1247d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            r.set(left, top, left + dragOutline.getWidth(), top + dragOutline.getHeight());
1248d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            if (resize) {
1249482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                cellToRect(cellX, cellY, spanX, spanY, r);
1250d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            }
1251150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung
125208ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy            mDragOutlineAnims[mDragOutlineCurrent].setTag(dragOutline);
125308ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy            mDragOutlineAnims[mDragOutlineCurrent].animateIn();
12546569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        }
125549250ad530385fcdd6072ca54697f670ec503b59Patrick Dubroy
125649250ad530385fcdd6072ca54697f670ec503b59Patrick Dubroy        // If we are drawing crosshairs, the entire CellLayout needs to be invalidated
125749250ad530385fcdd6072ca54697f670ec503b59Patrick Dubroy        if (mCrosshairsDrawable != null) {
125849250ad530385fcdd6072ca54697f670ec503b59Patrick Dubroy            invalidate();
125949250ad530385fcdd6072ca54697f670ec503b59Patrick Dubroy        }
12606569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    }
12616569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
1262e0310965022e7a1adb7ad489505d404186608689Adam Cohen    public void clearDragOutlines() {
1263e0310965022e7a1adb7ad489505d404186608689Adam Cohen        final int oldIndex = mDragOutlineCurrent;
1264e0310965022e7a1adb7ad489505d404186608689Adam Cohen        mDragOutlineAnims[oldIndex].animateOut();
1265d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        mDragCell[0] = mDragCell[1] = -1;
1266e0310965022e7a1adb7ad489505d404186608689Adam Cohen    }
1267e0310965022e7a1adb7ad489505d404186608689Adam Cohen
126831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
126970864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey     * Find a vacant area that will fit the given bounds nearest the requested
127070864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey     * cell location. Uses Euclidean distance to score multiple vacant areas.
1271aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     *
127251afc022fa76c79f0d1ece470ddc126c08fea8a4Romain Guy     * @param pixelX The X location at which you want to search for a vacant area.
127351afc022fa76c79f0d1ece470ddc126c08fea8a4Romain Guy     * @param pixelY The Y location at which you want to search for a vacant area.
127470864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey     * @param spanX Horizontal span of the object.
127570864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey     * @param spanY Vertical span of the object.
1276de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy     * @param result Array in which to place the result, or null (in which case a new array will
1277de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy     *        be allocated)
127870864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey     * @return The X, Y cell of a vacant area that can contain this object,
127970864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey     *         nearest the requested location.
128031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
1281d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    int[] findNearestVacantArea(int pixelX, int pixelY, int spanX, int spanY,
1282d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            int[] result) {
1283de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy        return findNearestVacantArea(pixelX, pixelY, spanX, spanY, null, result);
12846a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka    }
1285aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
12866a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka    /**
12876a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     * Find a vacant area that will fit the given bounds nearest the requested
12886a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     * cell location. Uses Euclidean distance to score multiple vacant areas.
12896a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     *
12906a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     * @param pixelX The X location at which you want to search for a vacant area.
12916a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     * @param pixelY The Y location at which you want to search for a vacant area.
1292d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param minSpanX The minimum horizontal span required
1293d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param minSpanY The minimum vertical span required
1294d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param spanX Horizontal span of the object.
1295d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param spanY Vertical span of the object.
1296d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param result Array in which to place the result, or null (in which case a new array will
1297d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *        be allocated)
1298d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @return The X, Y cell of a vacant area that can contain this object,
1299d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *         nearest the requested location.
1300d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     */
1301d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    int[] findNearestVacantArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX,
1302d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            int spanY, int[] result, int[] resultSpan) {
1303d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        return findNearestVacantArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, null,
1304d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                result, resultSpan);
1305d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    }
1306d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen
1307d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    /**
1308d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * Find a vacant area that will fit the given bounds nearest the requested
1309d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * cell location. Uses Euclidean distance to score multiple vacant areas.
1310d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *
1311d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param pixelX The X location at which you want to search for a vacant area.
1312d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param pixelY The Y location at which you want to search for a vacant area.
13136a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     * @param spanX Horizontal span of the object.
13146a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     * @param spanY Vertical span of the object.
1315df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param ignoreOccupied If true, the result can be an occupied cell
1316df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param result Array in which to place the result, or null (in which case a new array will
1317df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     *        be allocated)
13186a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     * @return The X, Y cell of a vacant area that can contain this object,
13196a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     *         nearest the requested location.
13206a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     */
1321df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    int[] findNearestArea(int pixelX, int pixelY, int spanX, int spanY, View ignoreView,
1322df0353815c629fc678824b07a234b89a1ff94208Adam Cohen            boolean ignoreOccupied, int[] result) {
1323d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        return findNearestArea(pixelX, pixelY, spanX, spanY,
1324482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                spanX, spanY, ignoreView, ignoreOccupied, result, null, mOccupied);
1325d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    }
1326d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen
1327d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    private final Stack<Rect> mTempRectStack = new Stack<Rect>();
1328d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    private void lazyInitTempRectStack() {
1329d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        if (mTempRectStack.isEmpty()) {
1330d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            for (int i = 0; i < mCountX * mCountY; i++) {
1331d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                mTempRectStack.push(new Rect());
1332d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            }
1333d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        }
1334d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    }
1335482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1336d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    private void recycleTempRects(Stack<Rect> used) {
1337d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        while (!used.isEmpty()) {
1338d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            mTempRectStack.push(used.pop());
1339d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        }
1340d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    }
1341d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen
1342d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    /**
1343d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * Find a vacant area that will fit the given bounds nearest the requested
1344d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * cell location. Uses Euclidean distance to score multiple vacant areas.
1345d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *
1346d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param pixelX The X location at which you want to search for a vacant area.
1347d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param pixelY The Y location at which you want to search for a vacant area.
1348d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param minSpanX The minimum horizontal span required
1349d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param minSpanY The minimum vertical span required
1350d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param spanX Horizontal span of the object.
1351d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param spanY Vertical span of the object.
1352d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param ignoreOccupied If true, the result can be an occupied cell
1353d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param result Array in which to place the result, or null (in which case a new array will
1354d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *        be allocated)
1355d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @return The X, Y cell of a vacant area that can contain this object,
1356d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *         nearest the requested location.
1357d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     */
1358d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    int[] findNearestArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, int spanY,
1359482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            View ignoreView, boolean ignoreOccupied, int[] result, int[] resultSpan,
1360482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            boolean[][] occupied) {
1361d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        lazyInitTempRectStack();
1362c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka        // mark space take by ignoreView as available (method checks if ignoreView is null)
1363482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsAsUnoccupiedForView(ignoreView, occupied);
1364c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka
1365e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        // For items with a spanX / spanY > 1, the passed in point (pixelX, pixelY) corresponds
1366e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        // to the center of the item, but we are searching based on the top-left cell, so
1367e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        // we translate the point over to correspond to the top-left.
1368e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        pixelX -= (mCellWidth + mWidthGap) * (spanX - 1) / 2f;
1369e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        pixelY -= (mCellHeight + mHeightGap) * (spanY - 1) / 2f;
1370e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen
137170864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey        // Keep track of best-scoring drop area
1372de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy        final int[] bestXY = result != null ? result : new int[2];
137370864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey        double bestDistance = Double.MAX_VALUE;
1374d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        final Rect bestRect = new Rect(-1, -1, -1, -1);
1375d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        final Stack<Rect> validRegions = new Stack<Rect>();
1376aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
1377de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy        final int countX = mCountX;
1378de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy        final int countY = mCountY;
1379de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy
1380d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        if (minSpanX <= 0 || minSpanY <= 0 || spanX <= 0 || spanY <= 0 ||
1381d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                spanX < minSpanX || spanY < minSpanY) {
1382d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            return bestXY;
1383d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        }
1384d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen
1385d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        for (int y = 0; y < countY - (minSpanY - 1); y++) {
1386c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka            inner:
1387d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            for (int x = 0; x < countX - (minSpanX - 1); x++) {
1388d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                int ySize = -1;
1389d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                int xSize = -1;
1390df0353815c629fc678824b07a234b89a1ff94208Adam Cohen                if (ignoreOccupied) {
1391d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    // First, let's see if this thing fits anywhere
1392d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    for (int i = 0; i < minSpanX; i++) {
1393d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        for (int j = 0; j < minSpanY; j++) {
1394df0353815c629fc678824b07a234b89a1ff94208Adam Cohen                            if (occupied[x + i][y + j]) {
1395df0353815c629fc678824b07a234b89a1ff94208Adam Cohen                                continue inner;
1396df0353815c629fc678824b07a234b89a1ff94208Adam Cohen                            }
1397c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                        }
1398c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                    }
1399d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    xSize = minSpanX;
1400d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    ySize = minSpanY;
1401d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen
1402d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    // We know that the item will fit at _some_ acceptable size, now let's see
1403d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    // how big we can make it. We'll alternate between incrementing x and y spans
1404d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    // until we hit a limit.
1405d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    boolean incX = true;
1406d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    boolean hitMaxX = xSize >= spanX;
1407d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    boolean hitMaxY = ySize >= spanY;
1408d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    while (!(hitMaxX && hitMaxY)) {
1409d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        if (incX && !hitMaxX) {
1410d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            for (int j = 0; j < ySize; j++) {
1411d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                if (x + xSize > countX -1 || occupied[x + xSize][y + j]) {
1412d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                    // We can't move out horizontally
1413d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                    hitMaxX = true;
1414d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                }
1415d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            }
1416d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            if (!hitMaxX) {
1417d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                xSize++;
1418d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            }
1419d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        } else if (!hitMaxY) {
1420d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            for (int i = 0; i < xSize; i++) {
1421d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                if (y + ySize > countY - 1 || occupied[x + i][y + ySize]) {
1422d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                    // We can't move out vertically
1423d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                    hitMaxY = true;
1424d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                }
1425d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            }
1426d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            if (!hitMaxY) {
1427d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                ySize++;
1428d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            }
1429d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        }
1430d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        hitMaxX |= xSize >= spanX;
1431d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        hitMaxY |= ySize >= spanY;
1432d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        incX = !incX;
1433d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    }
1434d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    incX = true;
1435d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    hitMaxX = xSize >= spanX;
1436d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    hitMaxY = ySize >= spanY;
1437c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                }
14380be025d64c1f84138fe430a58875886e66aae767Winson Chung                final int[] cellXY = mTmpXY;
1439e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen                cellToCenterPoint(x, y, cellXY);
1440c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka
1441d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                // We verify that the current rect is not a sub-rect of any of our previous
1442d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                // candidates. In this case, the current rect is disqualified in favour of the
1443d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                // containing rect.
1444d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                Rect currentRect = mTempRectStack.pop();
1445d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                currentRect.set(x, y, x + xSize, y + ySize);
1446d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                boolean contained = false;
1447d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                for (Rect r : validRegions) {
1448d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    if (r.contains(currentRect)) {
1449d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        contained = true;
1450d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        break;
1451d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    }
1452d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                }
1453d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                validRegions.push(currentRect);
1454c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                double distance = Math.sqrt(Math.pow(cellXY[0] - pixelX, 2)
1455c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                        + Math.pow(cellXY[1] - pixelY, 2));
1456482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1457d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                if ((distance <= bestDistance && !contained) ||
1458d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        currentRect.contains(bestRect)) {
1459c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                    bestDistance = distance;
1460c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                    bestXY[0] = x;
1461c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                    bestXY[1] = y;
1462d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    if (resultSpan != null) {
1463d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        resultSpan[0] = xSize;
1464d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        resultSpan[1] = ySize;
1465d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    }
1466d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    bestRect.set(currentRect);
1467c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                }
146831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            }
146931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
1470c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka        // re-mark space taken by ignoreView as occupied
1471482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsAsOccupiedForView(ignoreView, occupied);
147231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
1473c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        // Return -1, -1 if no suitable location found
1474c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        if (bestDistance == Double.MAX_VALUE) {
1475c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            bestXY[0] = -1;
1476c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            bestXY[1] = -1;
147770864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey        }
1478d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        recycleTempRects(validRegions);
1479c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        return bestXY;
148031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
1481aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
1482482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     /**
1483482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * Find a vacant area that will fit the given bounds nearest the requested
1484482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * cell location, and will also weigh in a suggested direction vector of the
1485482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * desired location. This method computers distance based on unit grid distances,
1486482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * not pixel distances.
1487482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     *
148847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param cellX The X cell nearest to which you want to search for a vacant area.
148947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param cellY The Y cell nearest which you want to search for a vacant area.
1490482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * @param spanX Horizontal span of the object.
1491482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * @param spanY Vertical span of the object.
149247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param direction The favored direction in which the views should move from x, y
149347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param exactDirectionOnly If this parameter is true, then only solutions where the direction
149447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     *        matches exactly. Otherwise we find the best matching direction.
149547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param occoupied The array which represents which cells in the CellLayout are occupied
149647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param blockOccupied The array which represents which cells in the specified block (cellX,
149747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     *        cellY, spanX, spanY) are occupied. This is used when try to move a group of views.
1498482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * @param result Array in which to place the result, or null (in which case a new array will
1499482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     *        be allocated)
1500482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * @return The X, Y cell of a vacant area that can contain this object,
1501482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     *         nearest the requested location.
1502482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     */
1503482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private int[] findNearestArea(int cellX, int cellY, int spanX, int spanY, int[] direction,
150447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            boolean[][] occupied, boolean blockOccupied[][], int[] result) {
1505482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // Keep track of best-scoring drop area
1506482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        final int[] bestXY = result != null ? result : new int[2];
1507482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        float bestDistance = Float.MAX_VALUE;
1508482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        int bestDirectionScore = Integer.MIN_VALUE;
1509482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1510482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        final int countX = mCountX;
1511482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        final int countY = mCountY;
1512482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1513482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int y = 0; y < countY - (spanY - 1); y++) {
1514482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            inner:
1515482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            for (int x = 0; x < countX - (spanX - 1); x++) {
1516482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                // First, let's see if this thing fits anywhere
1517482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                for (int i = 0; i < spanX; i++) {
1518482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    for (int j = 0; j < spanY; j++) {
151947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        if (occupied[x + i][y + j] && (blockOccupied == null || blockOccupied[i][j])) {
1520482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                            continue inner;
1521482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        }
1522482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    }
1523482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                }
1524482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1525482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                float distance = (float)
1526482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        Math.sqrt((x - cellX) * (x - cellX) + (y - cellY) * (y - cellY));
1527482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                int[] curDirection = mTmpPoint;
152847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                computeDirectionVector(x - cellX, y - cellY, curDirection);
152947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                // The direction score is just the dot product of the two candidate direction
153047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                // and that passed in.
1531482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                int curDirectionScore = direction[0] * curDirection[0] +
1532482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        direction[1] * curDirection[1];
153347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                boolean exactDirectionOnly = false;
153447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                boolean directionMatches = direction[0] == curDirection[0] &&
153547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        direction[0] == curDirection[0];
153647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                if ((directionMatches || !exactDirectionOnly) &&
153747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        Float.compare(distance,  bestDistance) < 0 || (Float.compare(distance,
1538482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        bestDistance) == 0 && curDirectionScore > bestDirectionScore)) {
1539482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    bestDistance = distance;
1540482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    bestDirectionScore = curDirectionScore;
1541482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    bestXY[0] = x;
1542482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    bestXY[1] = y;
1543482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                }
1544482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1545482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1546482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1547482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // Return -1, -1 if no suitable location found
1548482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (bestDistance == Float.MAX_VALUE) {
1549482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            bestXY[0] = -1;
1550482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            bestXY[1] = -1;
1551482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1552482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return bestXY;
1553482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1554482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
155547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    private int[] findNearestAreaInDirection(int cellX, int cellY, int spanX, int spanY,
155647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            int[] direction,boolean[][] occupied,
155747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            boolean blockOccupied[][], int[] result) {
155847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        // Keep track of best-scoring drop area
155947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        final int[] bestXY = result != null ? result : new int[2];
156047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        bestXY[0] = -1;
156147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        bestXY[1] = -1;
156247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        float bestDistance = Float.MAX_VALUE;
156347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
156447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        // We use this to march in a single direction
156547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        if (direction[0] != 0 && direction[1] != 0) {
156647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            return bestXY;
156747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
156847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
156947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        // This will only incrememnet one of x or y based on the assertion above
157047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        int x = cellX + direction[0];
157147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        int y = cellY + direction[1];
157247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        while (x >= 0 && x + spanX <= mCountX && y >= 0 && y + spanY <= mCountY) {
157347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
157447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            boolean fail = false;
157547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            for (int i = 0; i < spanX; i++) {
157647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                for (int j = 0; j < spanY; j++) {
157747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    if (occupied[x + i][y + j] && (blockOccupied == null || blockOccupied[i][j])) {
157847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        fail = true;
157947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    }
158047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                }
158147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            }
158247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            if (!fail) {
158347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                float distance = (float)
158447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        Math.sqrt((x - cellX) * (x - cellX) + (y - cellY) * (y - cellY));
158547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                if (Float.compare(distance,  bestDistance) < 0) {
158647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    bestDistance = distance;
158747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    bestXY[0] = x;
158847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    bestXY[1] = y;
158947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                }
159047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            }
159147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            x += direction[0];
159247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            y += direction[1];
159347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
159447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        return bestXY;
159547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    }
159647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
1597482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private boolean addViewToTempLocation(View v, Rect rectOccupiedByPotentialDrop,
15988baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            int[] direction, ItemConfiguration currentState) {
15998baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        CellAndSpan c = currentState.map.get(v);
1600482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        boolean success = false;
16018baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, false);
1602482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsForRect(rectOccupiedByPotentialDrop, mTmpOccupied, true);
1603482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
16048baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        findNearestArea(c.x, c.y, c.spanX, c.spanY, direction, mTmpOccupied, null, mTempLocation);
1605482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1606482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (mTempLocation[0] >= 0 && mTempLocation[1] >= 0) {
16078baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            c.x = mTempLocation[0];
16088baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            c.y = mTempLocation[1];
1609482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            success = true;
1610482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1611482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
16128baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, true);
1613482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return success;
1614482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1615482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
161647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    // This method looks in the specified direction to see if there is an additional view
161747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    // immediately adjecent in that direction
161847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    private boolean addViewInDirection(ArrayList<View> views, Rect boundingRect, int[] direction,
161919f3792523fe2d55ea791a9286398a6120920690Adam Cohen            boolean[][] occupied, View dragView, ItemConfiguration currentState) {
162047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        boolean found = false;
162147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
1622a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        int childCount = mShortcutsAndWidgets.getChildCount();
162347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        Rect r0 = new Rect(boundingRect);
162447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        Rect r1 = new Rect();
162547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
162647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        int deltaX = 0;
162747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        int deltaY = 0;
162847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        if (direction[1] < 0) {
162947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            r0.set(r0.left, r0.top - 1, r0.right, r0.bottom);
163047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            deltaY = -1;
163147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        } else if (direction[1] > 0) {
163247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            r0.set(r0.left, r0.top, r0.right, r0.bottom + 1);
163347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            deltaY = 1;
163447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        } else if (direction[0] < 0) {
163547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            r0.set(r0.left - 1, r0.top, r0.right, r0.bottom);
163647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            deltaX = -1;
163747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        } else if (direction[0] > 0) {
163847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            r0.set(r0.left, r0.top, r0.right + 1, r0.bottom);
163947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            deltaX = 1;
164047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
164147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
164247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        for (int i = 0; i < childCount; i++) {
1643a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            View child = mShortcutsAndWidgets.getChildAt(i);
164419f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (views.contains(child) || child == dragView) continue;
16458baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = currentState.map.get(child);
164647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
16478baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
16488baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            r1.set(c.x, c.y, c.x + c.spanX, c.y + c.spanY);
164947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            if (Rect.intersects(r0, r1)) {
165047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                if (!lp.canReorder) {
165147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    return false;
165247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                }
165347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                boolean pushed = false;
16548baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                for (int x = c.x; x < c.x + c.spanX; x++) {
16558baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                    for (int y = c.y; y < c.y + c.spanY; y++) {
165647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        boolean inBounds = x - deltaX >= 0 && x -deltaX < mCountX
165747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                                && y - deltaY >= 0 && y - deltaY < mCountY;
165847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        if (inBounds && occupied[x - deltaX][y - deltaY]) {
165947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                            pushed = true;
166047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        }
166147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    }
166247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                }
166347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                if (pushed) {
166447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    views.add(child);
16658baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                    boundingRect.union(c.x, c.y, c.x + c.spanX, c.y + c.spanY);
166647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    found = true;
166747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                }
166847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            }
166947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
167047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        return found;
167147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    }
167247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
16738baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen    private boolean addViewsToTempLocation(ArrayList<View> views, Rect rectOccupiedByPotentialDrop,
167419f3792523fe2d55ea791a9286398a6120920690Adam Cohen            int[] direction, boolean push, View dragView, ItemConfiguration currentState) {
167547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        if (views.size() == 0) return true;
167647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
167747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        boolean success = false;
167847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        Rect boundingRect = null;
16798baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // We construct a rect which represents the entire group of views passed in
168047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        for (View v: views) {
16818baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = currentState.map.get(v);
168247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            if (boundingRect == null) {
16838baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                boundingRect = new Rect(c.x, c.y, c.x + c.spanX, c.y + c.spanY);
168447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            } else {
16858baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                boundingRect.union(c.x, c.y, c.x + c.spanX, c.y + c.spanY);
168647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            }
168747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
168847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
16898baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        @SuppressWarnings("unchecked")
169047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        ArrayList<View> dup = (ArrayList<View>) views.clone();
16918baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // We try and expand the group of views in the direction vector passed, based on
16928baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // whether they are physically adjacent, ie. based on "push mechanics".
169319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        while (push && addViewInDirection(dup, boundingRect, direction, mTmpOccupied, dragView,
16948baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                currentState)) {
169547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
16968baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen
16978baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // Mark the occupied state as false for the group of views we want to move.
169847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        for (View v: dup) {
16998baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = currentState.map.get(v);
17008baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, false);
170147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
170247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
170347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        boolean[][] blockOccupied = new boolean[boundingRect.width()][boundingRect.height()];
170447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        int top = boundingRect.top;
170547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        int left = boundingRect.left;
17068baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // We mark more precisely which parts of the bounding rect are truly occupied, allowing
17078baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // for tetris-style interlocking.
170847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        for (View v: dup) {
17098baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = currentState.map.get(v);
17108baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            markCellsForView(c.x - left, c.y - top, c.spanX, c.spanY, blockOccupied, true);
171147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
171247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
171347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        markCellsForRect(rectOccupiedByPotentialDrop, mTmpOccupied, true);
171447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
17158baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        if (push) {
17168baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            findNearestAreaInDirection(boundingRect.left, boundingRect.top, boundingRect.width(),
17178baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                    boundingRect.height(), direction, mTmpOccupied, blockOccupied, mTempLocation);
17188baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        } else {
17198baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            findNearestArea(boundingRect.left, boundingRect.top, boundingRect.width(),
17208baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                    boundingRect.height(), direction, mTmpOccupied, blockOccupied, mTempLocation);
17218baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        }
172247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
17238baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // If we successfuly found a location by pushing the block of views, we commit it
172447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        if (mTempLocation[0] >= 0 && mTempLocation[1] >= 0) {
17258baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            int deltaX = mTempLocation[0] - boundingRect.left;
17268baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            int deltaY = mTempLocation[1] - boundingRect.top;
172747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            for (View v: dup) {
17288baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                CellAndSpan c = currentState.map.get(v);
17298baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                c.x += deltaX;
17308baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                c.y += deltaY;
173147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            }
173247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            success = true;
173347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
1734482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
17358baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // In either case, we set the occupied array as marked for the location of the views
17368baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        for (View v: dup) {
17378baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = currentState.map.get(v);
17388baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, true);
1739482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1740482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return success;
1741482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1742482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1743482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private void markCellsForRect(Rect r, boolean[][] occupied, boolean value) {
1744482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsForView(r.left, r.top, r.width(), r.height(), occupied, value);
1745482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1746482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1747482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private boolean rearrangementExists(int cellX, int cellY, int spanX, int spanY, int[] direction,
17488baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            View ignoreView, ItemConfiguration solution) {
1749482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
17508baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        mIntersectingViews.clear();
1751482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        mOccupiedRect.set(cellX, cellY, cellX + spanX, cellY + spanY);
1752482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
17538baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // Mark the desired location of the view currently being dragged.
1754482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (ignoreView != null) {
17558baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = solution.map.get(ignoreView);
175619f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (c != null) {
175719f3792523fe2d55ea791a9286398a6120920690Adam Cohen                c.x = cellX;
175819f3792523fe2d55ea791a9286398a6120920690Adam Cohen                c.y = cellY;
175919f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
1760482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1761482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        Rect r0 = new Rect(cellX, cellY, cellX + spanX, cellY + spanY);
1762482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        Rect r1 = new Rect();
17638baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        for (View child: solution.map.keySet()) {
1764482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (child == ignoreView) continue;
17658baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = solution.map.get(child);
1766482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
17678baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            r1.set(c.x, c.y, c.x + c.spanX, c.y + c.spanY);
1768482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (Rect.intersects(r0, r1)) {
1769482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                if (!lp.canReorder) {
1770482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    return false;
1771482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                }
1772482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                mIntersectingViews.add(child);
1773482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1774482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
177547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
17768baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // We try to move the intersecting views as a block using the push mechanic
177719f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if (addViewsToTempLocation(mIntersectingViews, mOccupiedRect, direction, true, ignoreView,
177819f3792523fe2d55ea791a9286398a6120920690Adam Cohen                solution)) {
177947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            return true;
178047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
178147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        // Try the opposite direction
178247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        direction[0] *= -1;
178347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        direction[1] *= -1;
178419f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if (addViewsToTempLocation(mIntersectingViews, mOccupiedRect, direction, true, ignoreView,
178519f3792523fe2d55ea791a9286398a6120920690Adam Cohen                solution)) {
178647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            return true;
178747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
178847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        // Switch the direction back
178947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        direction[0] *= -1;
179047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        direction[1] *= -1;
179147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
17928baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // Next we try moving the views as a block , but without requiring the push mechanic
179319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if (addViewsToTempLocation(mIntersectingViews, mOccupiedRect, direction, false, ignoreView,
179419f3792523fe2d55ea791a9286398a6120920690Adam Cohen                solution)) {
1795482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            return true;
1796482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
179747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
1798482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // Ok, they couldn't move as a block, let's move them individually
1799482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (View v : mIntersectingViews) {
18008baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            if (!addViewToTempLocation(v, mOccupiedRect, direction, solution)) {
1801482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                return false;
1802482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1803482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1804482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return true;
1805482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1806482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1807482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    /*
1808482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * Returns a pair (x, y), where x,y are in {-1, 0, 1} corresponding to vector between
1809482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * the provided point and the provided cell
1810482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     */
181147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    private void computeDirectionVector(float deltaX, float deltaY, int[] result) {
1812482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        double angle = Math.atan(((float) deltaY) / deltaX);
1813482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1814482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        result[0] = 0;
1815482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        result[1] = 0;
1816482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (Math.abs(Math.cos(angle)) > 0.5f) {
1817482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            result[0] = (int) Math.signum(deltaX);
1818482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1819482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (Math.abs(Math.sin(angle)) > 0.5f) {
1820482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            result[1] = (int) Math.signum(deltaY);
1821482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1822482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1823482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
18248baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen    private void copyOccupiedArray(boolean[][] occupied) {
18258baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        for (int i = 0; i < mCountX; i++) {
18268baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            for (int j = 0; j < mCountY; j++) {
18278baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                occupied[i][j] = mOccupied[i][j];
18288baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            }
18298baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        }
18308baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen    }
18318baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen
1832482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    ItemConfiguration simpleSwap(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX,
1833482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            int spanY, int[] direction, View dragView, boolean decX, ItemConfiguration solution) {
18348baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // Copy the current state into the solution. This solution will be manipulated as necessary.
18358baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        copyCurrentStateToSolution(solution, false);
18368baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // Copy the current occupied array into the temporary occupied array. This array will be
18378baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // manipulated as necessary to find a solution.
18388baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        copyOccupiedArray(mTmpOccupied);
1839482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1840482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // We find the nearest cell into which we would place the dragged item, assuming there's
1841482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // nothing in its way.
1842482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        int result[] = new int[2];
1843482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        result = findNearestArea(pixelX, pixelY, spanX, spanY, result);
1844482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1845482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        boolean success = false;
1846482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // First we try the exact nearest position of the item being dragged,
1847482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // we will then want to try to move this around to other neighbouring positions
18488baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        success = rearrangementExists(result[0], result[1], spanX, spanY, direction, dragView,
18498baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                solution);
1850482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1851482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (!success) {
1852482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            // We try shrinking the widget down to size in an alternating pattern, shrink 1 in
1853482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            // x, then 1 in y etc.
1854482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (spanX > minSpanX && (minSpanY == spanY || decX)) {
1855482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                return simpleSwap(pixelX, pixelY, minSpanX, minSpanY, spanX - 1, spanY, direction,
1856482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        dragView, false, solution);
1857482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            } else if (spanY > minSpanY) {
1858482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                return simpleSwap(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY - 1, direction,
1859482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        dragView, true, solution);
1860482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1861482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.isSolution = false;
1862482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        } else {
1863482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.isSolution = true;
1864482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewX = result[0];
1865482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewY = result[1];
1866482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewSpanX = spanX;
1867482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewSpanY = spanY;
1868482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1869482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return solution;
1870482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1871482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1872482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private void copyCurrentStateToSolution(ItemConfiguration solution, boolean temp) {
1873a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        int childCount = mShortcutsAndWidgets.getChildCount();
1874482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < childCount; i++) {
1875a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            View child = mShortcutsAndWidgets.getChildAt(i);
1876482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
18778baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c;
1878482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (temp) {
18798baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                c = new CellAndSpan(lp.tmpCellX, lp.tmpCellY, lp.cellHSpan, lp.cellVSpan);
1880482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            } else {
18818baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                c = new CellAndSpan(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan);
1882482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
18838baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            solution.map.put(child, c);
1884482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1885482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1886482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1887482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private void copySolutionToTempState(ItemConfiguration solution, View dragView) {
1888482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < mCountX; i++) {
1889482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            for (int j = 0; j < mCountY; j++) {
1890482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                mTmpOccupied[i][j] = false;
1891482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1892482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1893482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1894a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        int childCount = mShortcutsAndWidgets.getChildCount();
1895482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < childCount; i++) {
1896a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            View child = mShortcutsAndWidgets.getChildAt(i);
1897482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (child == dragView) continue;
1898482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
18998baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = solution.map.get(child);
19008baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            if (c != null) {
19018baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                lp.tmpCellX = c.x;
19028baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                lp.tmpCellY = c.y;
19038baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                lp.cellHSpan = c.spanX;
19048baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                lp.cellVSpan = c.spanY;
19058baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, true);
1906482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1907482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1908482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsForView(solution.dragViewX, solution.dragViewY, solution.dragViewSpanX,
1909482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                solution.dragViewSpanY, mTmpOccupied, true);
1910482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1911482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1912482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private void animateItemsToSolution(ItemConfiguration solution, View dragView, boolean
1913482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            commitDragView) {
1914482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1915482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        boolean[][] occupied = DESTRUCTIVE_REORDER ? mOccupied : mTmpOccupied;
1916482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < mCountX; i++) {
1917482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            for (int j = 0; j < mCountY; j++) {
1918482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                occupied[i][j] = false;
1919482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1920482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1921482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1922a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        int childCount = mShortcutsAndWidgets.getChildCount();
1923482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < childCount; i++) {
1924a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            View child = mShortcutsAndWidgets.getChildAt(i);
1925482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (child == dragView) continue;
19268baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = solution.map.get(child);
19278baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            if (c != null) {
192819f3792523fe2d55ea791a9286398a6120920690Adam Cohen                animateChildToPosition(child, c.x, c.y, REORDER_ANIMATION_DURATION, 0,
192919f3792523fe2d55ea791a9286398a6120920690Adam Cohen                        DESTRUCTIVE_REORDER, false);
19308baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                markCellsForView(c.x, c.y, c.spanX, c.spanY, occupied, true);
1931482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1932482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1933482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (commitDragView) {
1934482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            markCellsForView(solution.dragViewX, solution.dragViewY, solution.dragViewSpanX,
1935482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    solution.dragViewSpanY, occupied, true);
1936482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1937482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1938482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
193919f3792523fe2d55ea791a9286398a6120920690Adam Cohen    // This method starts or changes the reorder hint animations
194019f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private void beginOrAdjustHintAnimations(ItemConfiguration solution, View dragView, int delay) {
194119f3792523fe2d55ea791a9286398a6120920690Adam Cohen        int childCount = mShortcutsAndWidgets.getChildCount();
194219f3792523fe2d55ea791a9286398a6120920690Adam Cohen        int timeForPriorAnimationToComplete = getMaxCompletionTime();
194319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        for (int i = 0; i < childCount; i++) {
194419f3792523fe2d55ea791a9286398a6120920690Adam Cohen            View child = mShortcutsAndWidgets.getChildAt(i);
194519f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (child == dragView) continue;
194619f3792523fe2d55ea791a9286398a6120920690Adam Cohen            CellAndSpan c = solution.map.get(child);
194719f3792523fe2d55ea791a9286398a6120920690Adam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
194819f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (c != null) {
194919f3792523fe2d55ea791a9286398a6120920690Adam Cohen                ReorderHintAnimation rha = new ReorderHintAnimation(child, lp.cellX, lp.cellY,
195019f3792523fe2d55ea791a9286398a6120920690Adam Cohen                        c.x, c.y, c.spanX, c.spanY);
195119f3792523fe2d55ea791a9286398a6120920690Adam Cohen                rha.animate(timeForPriorAnimationToComplete);
195219f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
195319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
195419f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
195519f3792523fe2d55ea791a9286398a6120920690Adam Cohen
195619f3792523fe2d55ea791a9286398a6120920690Adam Cohen    // Class which represents the reorder hint animations. These animations show that an item is
195719f3792523fe2d55ea791a9286398a6120920690Adam Cohen    // in a temporary state, and hint at where the item will return to.
195819f3792523fe2d55ea791a9286398a6120920690Adam Cohen    class ReorderHintAnimation {
195919f3792523fe2d55ea791a9286398a6120920690Adam Cohen        View child;
196019f3792523fe2d55ea791a9286398a6120920690Adam Cohen        float deltaX;
196119f3792523fe2d55ea791a9286398a6120920690Adam Cohen        float deltaY;
196219f3792523fe2d55ea791a9286398a6120920690Adam Cohen        private static final int DURATION = 140;
196319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        private int repeatCount;
196419f3792523fe2d55ea791a9286398a6120920690Adam Cohen        private boolean cancelOnCycleComplete = false;
196519f3792523fe2d55ea791a9286398a6120920690Adam Cohen        ValueAnimator va;
196619f3792523fe2d55ea791a9286398a6120920690Adam Cohen
196719f3792523fe2d55ea791a9286398a6120920690Adam Cohen        public ReorderHintAnimation(View child, int cellX0, int cellY0, int cellX1, int cellY1,
196819f3792523fe2d55ea791a9286398a6120920690Adam Cohen                int spanX, int spanY) {
196919f3792523fe2d55ea791a9286398a6120920690Adam Cohen            regionToCenterPoint(cellX0, cellY0, spanX, spanY, mTmpPoint);
197019f3792523fe2d55ea791a9286398a6120920690Adam Cohen            final int x0 = mTmpPoint[0];
197119f3792523fe2d55ea791a9286398a6120920690Adam Cohen            final int y0 = mTmpPoint[1];
197219f3792523fe2d55ea791a9286398a6120920690Adam Cohen            regionToCenterPoint(cellX1, cellY1, spanX, spanY, mTmpPoint);
197319f3792523fe2d55ea791a9286398a6120920690Adam Cohen            final int x1 = mTmpPoint[0];
197419f3792523fe2d55ea791a9286398a6120920690Adam Cohen            final int y1 = mTmpPoint[1];
197519f3792523fe2d55ea791a9286398a6120920690Adam Cohen            final int dX = x1 - x0;
197619f3792523fe2d55ea791a9286398a6120920690Adam Cohen            final int dY = y1 - y0;
197719f3792523fe2d55ea791a9286398a6120920690Adam Cohen            deltaX = 0;
197819f3792523fe2d55ea791a9286398a6120920690Adam Cohen            deltaY = 0;
197919f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (dX == dY && dX == 0) {
198019f3792523fe2d55ea791a9286398a6120920690Adam Cohen            } else {
198119f3792523fe2d55ea791a9286398a6120920690Adam Cohen                if (dY == 0) {
198219f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    deltaX = mReorderHintAnimationMagnitude;
198319f3792523fe2d55ea791a9286398a6120920690Adam Cohen                } else if (dX == 0) {
198419f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    deltaY = mReorderHintAnimationMagnitude;
198519f3792523fe2d55ea791a9286398a6120920690Adam Cohen                } else {
198619f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    double angle = Math.atan( (float) (dY) / dX);
198719f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    deltaX = (int) (Math.cos(angle) * mReorderHintAnimationMagnitude);
198819f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    deltaY = (int) (Math.sin(angle) * mReorderHintAnimationMagnitude);
198919f3792523fe2d55ea791a9286398a6120920690Adam Cohen                }
199019f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
199119f3792523fe2d55ea791a9286398a6120920690Adam Cohen            this.child = child;
199219f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
199319f3792523fe2d55ea791a9286398a6120920690Adam Cohen
199419f3792523fe2d55ea791a9286398a6120920690Adam Cohen        void animate(int delay) {
199519f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (mShakeAnimators.containsKey(child)) {
199619f3792523fe2d55ea791a9286398a6120920690Adam Cohen                ReorderHintAnimation oldAnimation = mShakeAnimators.get(child);
199719f3792523fe2d55ea791a9286398a6120920690Adam Cohen                oldAnimation.completeAnimation();
199819f3792523fe2d55ea791a9286398a6120920690Adam Cohen                mShakeAnimators.remove(child);
199919f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
200019f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (deltaX == 0 && deltaY == 0) {
200119f3792523fe2d55ea791a9286398a6120920690Adam Cohen                return;
200219f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
200319f3792523fe2d55ea791a9286398a6120920690Adam Cohen            va = ValueAnimator.ofFloat(0f, 1f);
200419f3792523fe2d55ea791a9286398a6120920690Adam Cohen            va.setRepeatMode(ValueAnimator.REVERSE);
200519f3792523fe2d55ea791a9286398a6120920690Adam Cohen            va.setRepeatCount(ValueAnimator.INFINITE);
200619f3792523fe2d55ea791a9286398a6120920690Adam Cohen            va.setDuration(DURATION);
200719f3792523fe2d55ea791a9286398a6120920690Adam Cohen            va.addUpdateListener(new AnimatorUpdateListener() {
200819f3792523fe2d55ea791a9286398a6120920690Adam Cohen                @Override
200919f3792523fe2d55ea791a9286398a6120920690Adam Cohen                public void onAnimationUpdate(ValueAnimator animation) {
201019f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    float r = ((Float) animation.getAnimatedValue()).floatValue();
201119f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    float x = r * deltaX;
201219f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    float y = r * deltaY;
201319f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    child.setTranslationX(x);
201419f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    child.setTranslationY(y);
201519f3792523fe2d55ea791a9286398a6120920690Adam Cohen                }
201619f3792523fe2d55ea791a9286398a6120920690Adam Cohen            });
201719f3792523fe2d55ea791a9286398a6120920690Adam Cohen            va.addListener(new AnimatorListenerAdapter() {
201819f3792523fe2d55ea791a9286398a6120920690Adam Cohen                public void onAnimationRepeat(Animator animation) {
201919f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    repeatCount++;
202019f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    // We make sure to end only after a full period
202119f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    if (cancelOnCycleComplete && repeatCount % 2 == 0) {
202219f3792523fe2d55ea791a9286398a6120920690Adam Cohen                        va.cancel();
202319f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    }
202419f3792523fe2d55ea791a9286398a6120920690Adam Cohen                }
202519f3792523fe2d55ea791a9286398a6120920690Adam Cohen            });
202619f3792523fe2d55ea791a9286398a6120920690Adam Cohen            va.setStartDelay(Math.max(REORDER_ANIMATION_DURATION, delay));
202719f3792523fe2d55ea791a9286398a6120920690Adam Cohen            mShakeAnimators.put(child, this);
202819f3792523fe2d55ea791a9286398a6120920690Adam Cohen            va.start();
202919f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
203019f3792523fe2d55ea791a9286398a6120920690Adam Cohen
203119f3792523fe2d55ea791a9286398a6120920690Adam Cohen
203219f3792523fe2d55ea791a9286398a6120920690Adam Cohen        private void completeAnimation() {
203319f3792523fe2d55ea791a9286398a6120920690Adam Cohen            cancelOnCycleComplete = true;
203419f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
203519f3792523fe2d55ea791a9286398a6120920690Adam Cohen
203619f3792523fe2d55ea791a9286398a6120920690Adam Cohen        // Returns the time required to complete the current oscillating animation
203719f3792523fe2d55ea791a9286398a6120920690Adam Cohen        private int completionTime() {
203819f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (repeatCount % 2 == 0) {
203919f3792523fe2d55ea791a9286398a6120920690Adam Cohen                return (int) (va.getDuration() - va.getCurrentPlayTime() + DURATION);
204019f3792523fe2d55ea791a9286398a6120920690Adam Cohen            } else {
204119f3792523fe2d55ea791a9286398a6120920690Adam Cohen                return (int) (va.getDuration() - va.getCurrentPlayTime());
204219f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
204319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
204419f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
204519f3792523fe2d55ea791a9286398a6120920690Adam Cohen
204619f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private void completeAndClearReorderHintAnimations() {
204719f3792523fe2d55ea791a9286398a6120920690Adam Cohen        for (ReorderHintAnimation a: mShakeAnimators.values()) {
204819f3792523fe2d55ea791a9286398a6120920690Adam Cohen            a.completeAnimation();
204919f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
205019f3792523fe2d55ea791a9286398a6120920690Adam Cohen        mShakeAnimators.clear();
205119f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
205219f3792523fe2d55ea791a9286398a6120920690Adam Cohen
205319f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private int getMaxCompletionTime() {
205419f3792523fe2d55ea791a9286398a6120920690Adam Cohen        int maxTime = 0;
205519f3792523fe2d55ea791a9286398a6120920690Adam Cohen        for (ReorderHintAnimation a: mShakeAnimators.values()) {
205619f3792523fe2d55ea791a9286398a6120920690Adam Cohen            maxTime = Math.max(maxTime, a.completionTime());
205719f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
205819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        return maxTime;
205919f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
206019f3792523fe2d55ea791a9286398a6120920690Adam Cohen
2061482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private void commitTempPlacement() {
2062482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < mCountX; i++) {
2063482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            for (int j = 0; j < mCountY; j++) {
2064482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                mOccupied[i][j] = mTmpOccupied[i][j];
2065482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
2066482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2067a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        int childCount = mShortcutsAndWidgets.getChildCount();
2068482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < childCount; i++) {
2069a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            LayoutParams lp = (LayoutParams) mShortcutsAndWidgets.getChildAt(i).getLayoutParams();
2070482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            lp.cellX = lp.tmpCellX;
2071482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            lp.cellY = lp.tmpCellY;
2072482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2073482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2074482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2075482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public void setUseTempCoords(boolean useTempCoords) {
2076a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        int childCount = mShortcutsAndWidgets.getChildCount();
2077482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < childCount; i++) {
2078a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            LayoutParams lp = (LayoutParams) mShortcutsAndWidgets.getChildAt(i).getLayoutParams();
2079482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            lp.useTmpCoords = useTempCoords;
2080482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2081482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2082482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2083482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    ItemConfiguration findConfigurationNoShuffle(int pixelX, int pixelY, int minSpanX, int minSpanY,
2084482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            int spanX, int spanY, View dragView, ItemConfiguration solution) {
2085482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        int[] result = new int[2];
2086482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        int[] resultSpan = new int[2];
2087482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        findNearestVacantArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, null, result,
2088482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                resultSpan);
2089482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (result[0] >= 0 && result[1] >= 0) {
2090482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            copyCurrentStateToSolution(solution, false);
2091482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewX = result[0];
2092482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewY = result[1];
2093482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewSpanX = resultSpan[0];
2094482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewSpanY = resultSpan[1];
2095482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.isSolution = true;
2096482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        } else {
2097482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.isSolution = false;
2098482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2099482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return solution;
2100482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2101482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2102482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public void prepareChildForDrag(View child) {
2103482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsAsUnoccupiedForView(child);
2104482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2105482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
210619f3792523fe2d55ea791a9286398a6120920690Adam Cohen    /* This seems like it should be obvious and straight-forward, but when the direction vector
210719f3792523fe2d55ea791a9286398a6120920690Adam Cohen    needs to match with the notion of the dragView pushing other views, we have to employ
210819f3792523fe2d55ea791a9286398a6120920690Adam Cohen    a slightly more subtle notion of the direction vector. The question is what two points is
210919f3792523fe2d55ea791a9286398a6120920690Adam Cohen    the vector between? The center of the dragView and its desired destination? Not quite, as
211019f3792523fe2d55ea791a9286398a6120920690Adam Cohen    this doesn't necessarily coincide with the interaction of the dragView and items occupying
211119f3792523fe2d55ea791a9286398a6120920690Adam Cohen    those cells. Instead we use some heuristics to often lock the vector to up, down, left
211219f3792523fe2d55ea791a9286398a6120920690Adam Cohen    or right, which helps make pushing feel right.
211319f3792523fe2d55ea791a9286398a6120920690Adam Cohen    */
211419f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private void getDirectionVectorForDrop(int dragViewCenterX, int dragViewCenterY, int spanX,
211519f3792523fe2d55ea791a9286398a6120920690Adam Cohen            int spanY, View dragView, int[] resultDirection) {
211619f3792523fe2d55ea791a9286398a6120920690Adam Cohen        int[] targetDestination = new int[2];
211719f3792523fe2d55ea791a9286398a6120920690Adam Cohen
211819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        findNearestArea(dragViewCenterX, dragViewCenterY, spanX, spanY, targetDestination);
211919f3792523fe2d55ea791a9286398a6120920690Adam Cohen        Rect dragRect = new Rect();
212019f3792523fe2d55ea791a9286398a6120920690Adam Cohen        regionToRect(targetDestination[0], targetDestination[1], spanX, spanY, dragRect);
212119f3792523fe2d55ea791a9286398a6120920690Adam Cohen        dragRect.offset(dragViewCenterX - dragRect.centerX(), dragViewCenterY - dragRect.centerY());
212219f3792523fe2d55ea791a9286398a6120920690Adam Cohen
212319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        Rect dropRegionRect = new Rect();
212419f3792523fe2d55ea791a9286398a6120920690Adam Cohen        getViewsIntersectingRegion(targetDestination[0], targetDestination[1], spanX, spanY,
212519f3792523fe2d55ea791a9286398a6120920690Adam Cohen                dragView, dropRegionRect, mIntersectingViews);
212619f3792523fe2d55ea791a9286398a6120920690Adam Cohen
212719f3792523fe2d55ea791a9286398a6120920690Adam Cohen        int dropRegionSpanX = dropRegionRect.width();
212819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        int dropRegionSpanY = dropRegionRect.height();
212919f3792523fe2d55ea791a9286398a6120920690Adam Cohen
213019f3792523fe2d55ea791a9286398a6120920690Adam Cohen        regionToRect(dropRegionRect.left, dropRegionRect.top, dropRegionRect.width(),
213119f3792523fe2d55ea791a9286398a6120920690Adam Cohen                dropRegionRect.height(), dropRegionRect);
213219f3792523fe2d55ea791a9286398a6120920690Adam Cohen
213319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        int deltaX = (dropRegionRect.centerX() - dragViewCenterX) / spanX;
213419f3792523fe2d55ea791a9286398a6120920690Adam Cohen        int deltaY = (dropRegionRect.centerY() - dragViewCenterY) / spanY;
213519f3792523fe2d55ea791a9286398a6120920690Adam Cohen
213619f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if (dropRegionSpanX == mCountX || spanX == mCountX) {
213719f3792523fe2d55ea791a9286398a6120920690Adam Cohen            deltaX = 0;
213819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
213919f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if (dropRegionSpanY == mCountY || spanY == mCountY) {
214019f3792523fe2d55ea791a9286398a6120920690Adam Cohen            deltaY = 0;
214119f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
214219f3792523fe2d55ea791a9286398a6120920690Adam Cohen
214319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if (deltaX == 0 && deltaY == 0) {
214419f3792523fe2d55ea791a9286398a6120920690Adam Cohen            // No idea what to do, give a random direction.
214519f3792523fe2d55ea791a9286398a6120920690Adam Cohen            resultDirection[0] = 1;
214619f3792523fe2d55ea791a9286398a6120920690Adam Cohen            resultDirection[1] = 0;
214719f3792523fe2d55ea791a9286398a6120920690Adam Cohen        } else {
214819f3792523fe2d55ea791a9286398a6120920690Adam Cohen            computeDirectionVector(deltaX, deltaY, resultDirection);
214919f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
215019f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
215119f3792523fe2d55ea791a9286398a6120920690Adam Cohen
215219f3792523fe2d55ea791a9286398a6120920690Adam Cohen    // For a given cell and span, fetch the set of views intersecting the region.
215319f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private void getViewsIntersectingRegion(int cellX, int cellY, int spanX, int spanY,
215419f3792523fe2d55ea791a9286398a6120920690Adam Cohen            View dragView, Rect boundingRect, ArrayList<View> intersectingViews) {
215519f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if (boundingRect != null) {
215619f3792523fe2d55ea791a9286398a6120920690Adam Cohen            boundingRect.set(cellX, cellY, cellX + spanX, cellY + spanY);
215719f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
215819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        intersectingViews.clear();
215919f3792523fe2d55ea791a9286398a6120920690Adam Cohen        Rect r0 = new Rect(cellX, cellY, cellX + spanX, cellY + spanY);
216019f3792523fe2d55ea791a9286398a6120920690Adam Cohen        Rect r1 = new Rect();
216119f3792523fe2d55ea791a9286398a6120920690Adam Cohen        final int count = mShortcutsAndWidgets.getChildCount();
216219f3792523fe2d55ea791a9286398a6120920690Adam Cohen        for (int i = 0; i < count; i++) {
216319f3792523fe2d55ea791a9286398a6120920690Adam Cohen            View child = mShortcutsAndWidgets.getChildAt(i);
216419f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (child == dragView) continue;
216519f3792523fe2d55ea791a9286398a6120920690Adam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
216619f3792523fe2d55ea791a9286398a6120920690Adam Cohen            r1.set(lp.cellX, lp.cellY, lp.cellX + lp.cellHSpan, lp.cellY + lp.cellVSpan);
216719f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (Rect.intersects(r0, r1)) {
216819f3792523fe2d55ea791a9286398a6120920690Adam Cohen                mIntersectingViews.add(child);
216919f3792523fe2d55ea791a9286398a6120920690Adam Cohen                if (boundingRect != null) {
217019f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    boundingRect.union(r1);
217119f3792523fe2d55ea791a9286398a6120920690Adam Cohen                }
217219f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
217319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
217419f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
217519f3792523fe2d55ea791a9286398a6120920690Adam Cohen
217619f3792523fe2d55ea791a9286398a6120920690Adam Cohen    boolean isNearestDropLocationOccupied(int pixelX, int pixelY, int spanX, int spanY,
217719f3792523fe2d55ea791a9286398a6120920690Adam Cohen            View dragView, int[] result) {
217819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        result = findNearestArea(pixelX, pixelY, spanX, spanY, result);
217919f3792523fe2d55ea791a9286398a6120920690Adam Cohen        getViewsIntersectingRegion(result[0], result[1], spanX, spanY, dragView, null,
218019f3792523fe2d55ea791a9286398a6120920690Adam Cohen                mIntersectingViews);
218119f3792523fe2d55ea791a9286398a6120920690Adam Cohen        return !mIntersectingViews.isEmpty();
218219f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
218319f3792523fe2d55ea791a9286398a6120920690Adam Cohen
218419f3792523fe2d55ea791a9286398a6120920690Adam Cohen    void revertTempState() {
218519f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if (!isItemPlacementDirty() || DESTRUCTIVE_REORDER) return;
218619f3792523fe2d55ea791a9286398a6120920690Adam Cohen        final int count = mShortcutsAndWidgets.getChildCount();
218719f3792523fe2d55ea791a9286398a6120920690Adam Cohen        for (int i = 0; i < count; i++) {
218819f3792523fe2d55ea791a9286398a6120920690Adam Cohen            View child = mShortcutsAndWidgets.getChildAt(i);
218919f3792523fe2d55ea791a9286398a6120920690Adam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
219019f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (lp.tmpCellX != lp.cellX || lp.tmpCellY != lp.cellY) {
219119f3792523fe2d55ea791a9286398a6120920690Adam Cohen                lp.tmpCellX = lp.cellX;
219219f3792523fe2d55ea791a9286398a6120920690Adam Cohen                lp.tmpCellY = lp.cellY;
219319f3792523fe2d55ea791a9286398a6120920690Adam Cohen                animateChildToPosition(child, lp.cellX, lp.cellY, REORDER_ANIMATION_DURATION,
219419f3792523fe2d55ea791a9286398a6120920690Adam Cohen                        0, false, false);
219519f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
219619f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
219719f3792523fe2d55ea791a9286398a6120920690Adam Cohen        completeAndClearReorderHintAnimations();
219819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        setItemPlacementDirty(false);
219919f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
220019f3792523fe2d55ea791a9286398a6120920690Adam Cohen
2201482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    int[] createArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, int spanY,
2202482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            View dragView, int[] result, int resultSpan[], int mode) {
2203482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // First we determine if things have moved enough to cause a different layout
220447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        result = findNearestArea(pixelX, pixelY, spanX, spanY, result);
2205482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2206482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (resultSpan == null) {
2207482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            resultSpan = new int[2];
2208482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2209482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
221019f3792523fe2d55ea791a9286398a6120920690Adam Cohen        // When we are checking drop validity or actually dropping, we don't recompute the
221119f3792523fe2d55ea791a9286398a6120920690Adam Cohen        // direction vector, since we want the solution to match the preview, and it's possible
221219f3792523fe2d55ea791a9286398a6120920690Adam Cohen        // that the exact position of the item has changed to result in a new reordering outcome.
221319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if ((mode == MODE_ON_DROP || mode == MODE_ACCEPT_DROP)
221419f3792523fe2d55ea791a9286398a6120920690Adam Cohen               && mPreviousReorderDirection[0] != -1) {
221519f3792523fe2d55ea791a9286398a6120920690Adam Cohen            mDirectionVector[0] = mPreviousReorderDirection[0];
221619f3792523fe2d55ea791a9286398a6120920690Adam Cohen            mDirectionVector[1] = mPreviousReorderDirection[1];
221719f3792523fe2d55ea791a9286398a6120920690Adam Cohen            // We reset this vector after drop
221819f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (mode == MODE_ON_DROP) {
221919f3792523fe2d55ea791a9286398a6120920690Adam Cohen                mPreviousReorderDirection[0] = -1;
222019f3792523fe2d55ea791a9286398a6120920690Adam Cohen                mPreviousReorderDirection[1] = -1;
222119f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
222219f3792523fe2d55ea791a9286398a6120920690Adam Cohen        } else {
222319f3792523fe2d55ea791a9286398a6120920690Adam Cohen            getDirectionVectorForDrop(pixelX, pixelY, spanX, spanY, dragView, mDirectionVector);
222419f3792523fe2d55ea791a9286398a6120920690Adam Cohen            mPreviousReorderDirection[0] = mDirectionVector[0];
222519f3792523fe2d55ea791a9286398a6120920690Adam Cohen            mPreviousReorderDirection[1] = mDirectionVector[1];
222619f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
222719f3792523fe2d55ea791a9286398a6120920690Adam Cohen
2228482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        ItemConfiguration swapSolution = simpleSwap(pixelX, pixelY, minSpanX, minSpanY,
2229482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                 spanX,  spanY, mDirectionVector, dragView,  true,  new ItemConfiguration());
2230482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2231482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // We attempt the approach which doesn't shuffle views at all
2232482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        ItemConfiguration noShuffleSolution = findConfigurationNoShuffle(pixelX, pixelY, minSpanX,
2233482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                minSpanY, spanX, spanY, dragView, new ItemConfiguration());
2234482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2235482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        ItemConfiguration finalSolution = null;
2236482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (swapSolution.isSolution && swapSolution.area() >= noShuffleSolution.area()) {
2237482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            finalSolution = swapSolution;
2238482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        } else if (noShuffleSolution.isSolution) {
2239482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            finalSolution = noShuffleSolution;
2240482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2241482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2242482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        boolean foundSolution = true;
2243482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (!DESTRUCTIVE_REORDER) {
2244482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            setUseTempCoords(true);
2245482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2246482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2247482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (finalSolution != null) {
2248482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            result[0] = finalSolution.dragViewX;
2249482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            result[1] = finalSolution.dragViewY;
2250482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            resultSpan[0] = finalSolution.dragViewSpanX;
2251482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            resultSpan[1] = finalSolution.dragViewSpanY;
2252482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2253482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            // If we're just testing for a possible location (MODE_ACCEPT_DROP), we don't bother
2254482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            // committing anything or animating anything as we just want to determine if a solution
2255482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            // exists
2256482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (mode == MODE_DRAG_OVER || mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL) {
2257482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                if (!DESTRUCTIVE_REORDER) {
2258482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    copySolutionToTempState(finalSolution, dragView);
2259482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                }
2260482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                setItemPlacementDirty(true);
2261482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                animateItemsToSolution(finalSolution, dragView, mode == MODE_ON_DROP);
2262482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
226319f3792523fe2d55ea791a9286398a6120920690Adam Cohen                if (!DESTRUCTIVE_REORDER &&
226419f3792523fe2d55ea791a9286398a6120920690Adam Cohen                        (mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL)) {
2265482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    commitTempPlacement();
226619f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    completeAndClearReorderHintAnimations();
226719f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    setItemPlacementDirty(false);
226819f3792523fe2d55ea791a9286398a6120920690Adam Cohen                } else {
226919f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    beginOrAdjustHintAnimations(finalSolution, dragView,
227019f3792523fe2d55ea791a9286398a6120920690Adam Cohen                            REORDER_ANIMATION_DURATION);
2271482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                }
2272482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
2273482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        } else {
2274482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            foundSolution = false;
2275482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            result[0] = result[1] = resultSpan[0] = resultSpan[1] = -1;
2276482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2277482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2278482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if ((mode == MODE_ON_DROP || !foundSolution) && !DESTRUCTIVE_REORDER) {
2279482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            setUseTempCoords(false);
2280482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2281482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2282a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.requestLayout();
2283482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return result;
2284482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2285482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
228619f3792523fe2d55ea791a9286398a6120920690Adam Cohen    void setItemPlacementDirty(boolean dirty) {
228719f3792523fe2d55ea791a9286398a6120920690Adam Cohen        mItemPlacementDirty = dirty;
2288482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
228919f3792523fe2d55ea791a9286398a6120920690Adam Cohen    boolean isItemPlacementDirty() {
229019f3792523fe2d55ea791a9286398a6120920690Adam Cohen        return mItemPlacementDirty;
2291482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2292482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2293482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private class ItemConfiguration {
22948baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        HashMap<View, CellAndSpan> map = new HashMap<View, CellAndSpan>();
2295482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        boolean isSolution = false;
2296482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        int dragViewX, dragViewY, dragViewSpanX, dragViewSpanY;
2297482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2298482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        int area() {
2299482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            return dragViewSpanX * dragViewSpanY;
2300482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
23018baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen    }
23028baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen
23038baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen    private class CellAndSpan {
23048baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        int x, y;
23058baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        int spanX, spanY;
23068baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen
23078baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        public CellAndSpan(int x, int y, int spanX, int spanY) {
23088baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            this.x = x;
23098baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            this.y = y;
23108baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            this.spanX = spanX;
23118baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            this.spanY = spanY;
2312482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2313482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2314482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2315df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    /**
2316df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * Find a vacant area that will fit the given bounds nearest the requested
2317df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * cell location. Uses Euclidean distance to score multiple vacant areas.
2318df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     *
2319df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param pixelX The X location at which you want to search for a vacant area.
2320df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param pixelY The Y location at which you want to search for a vacant area.
2321df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param spanX Horizontal span of the object.
2322df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param spanY Vertical span of the object.
2323df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param ignoreView Considers space occupied by this view as unoccupied
2324df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param result Previously returned value to possibly recycle.
2325df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @return The X, Y cell of a vacant area that can contain this object,
2326df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     *         nearest the requested location.
2327df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     */
2328df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    int[] findNearestVacantArea(
2329df0353815c629fc678824b07a234b89a1ff94208Adam Cohen            int pixelX, int pixelY, int spanX, int spanY, View ignoreView, int[] result) {
2330df0353815c629fc678824b07a234b89a1ff94208Adam Cohen        return findNearestArea(pixelX, pixelY, spanX, spanY, ignoreView, true, result);
2331df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    }
2332df0353815c629fc678824b07a234b89a1ff94208Adam Cohen
2333df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    /**
2334d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * Find a vacant area that will fit the given bounds nearest the requested
2335d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * cell location. Uses Euclidean distance to score multiple vacant areas.
2336d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *
2337d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param pixelX The X location at which you want to search for a vacant area.
2338d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param pixelY The Y location at which you want to search for a vacant area.
2339d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param minSpanX The minimum horizontal span required
2340d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param minSpanY The minimum vertical span required
2341d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param spanX Horizontal span of the object.
2342d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param spanY Vertical span of the object.
2343d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param ignoreView Considers space occupied by this view as unoccupied
2344d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param result Previously returned value to possibly recycle.
2345d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @return The X, Y cell of a vacant area that can contain this object,
2346d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *         nearest the requested location.
2347d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     */
2348d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    int[] findNearestVacantArea(int pixelX, int pixelY, int minSpanX, int minSpanY,
2349d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            int spanX, int spanY, View ignoreView, int[] result, int[] resultSpan) {
2350482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return findNearestArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, ignoreView, true,
2351482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                result, resultSpan, mOccupied);
2352d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    }
2353d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen
2354d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    /**
2355df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * Find a starting cell position that will fit the given bounds nearest the requested
2356df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * cell location. Uses Euclidean distance to score multiple vacant areas.
2357df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     *
2358df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param pixelX The X location at which you want to search for a vacant area.
2359df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param pixelY The Y location at which you want to search for a vacant area.
2360df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param spanX Horizontal span of the object.
2361df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param spanY Vertical span of the object.
2362df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param ignoreView Considers space occupied by this view as unoccupied
2363df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param result Previously returned value to possibly recycle.
2364df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @return The X, Y cell of a vacant area that can contain this object,
2365df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     *         nearest the requested location.
2366df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     */
2367df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    int[] findNearestArea(
2368df0353815c629fc678824b07a234b89a1ff94208Adam Cohen            int pixelX, int pixelY, int spanX, int spanY, int[] result) {
2369df0353815c629fc678824b07a234b89a1ff94208Adam Cohen        return findNearestArea(pixelX, pixelY, spanX, spanY, null, false, result);
2370df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    }
2371df0353815c629fc678824b07a234b89a1ff94208Adam Cohen
23720280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    boolean existsEmptyCell() {
23730280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        return findCellForSpan(null, 1, 1);
23740280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
23750280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
23760280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    /**
23770280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * Finds the upper-left coordinate of the first rectangle in the grid that can
23780280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * hold a cell of the specified dimensions. If intersectX and intersectY are not -1,
23790280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * then this method will only return coordinates for rectangles that contain the cell
23800280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * (intersectX, intersectY)
23810280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     *
23820280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param cellXY The array that will contain the position of a vacant cell if such a cell
23830280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     *               can be found.
23840280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param spanX The horizontal span of the cell we want to find.
23850280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param spanY The vertical span of the cell we want to find.
23860280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     *
23870280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @return True if a vacant cell of the specified dimension was found, false otherwise.
23880280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     */
23890280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    boolean findCellForSpan(int[] cellXY, int spanX, int spanY) {
2390482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return findCellForSpanThatIntersectsIgnoring(cellXY, spanX, spanY, -1, -1, null, mOccupied);
23910280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
23920280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
23930280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    /**
23940280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * Like above, but ignores any cells occupied by the item "ignoreView"
23950280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     *
23960280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param cellXY The array that will contain the position of a vacant cell if such a cell
23970280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     *               can be found.
23980280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param spanX The horizontal span of the cell we want to find.
23990280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param spanY The vertical span of the cell we want to find.
24000280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param ignoreView The home screen item we should treat as not occupying any space
24010280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @return
24020280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     */
24030280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    boolean findCellForSpanIgnoring(int[] cellXY, int spanX, int spanY, View ignoreView) {
2404482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return findCellForSpanThatIntersectsIgnoring(cellXY, spanX, spanY, -1, -1,
2405482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                ignoreView, mOccupied);
24060280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
24070280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
24080280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    /**
24090280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * Like above, but if intersectX and intersectY are not -1, then this method will try to
24100280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * return coordinates for rectangles that contain the cell [intersectX, intersectY]
24110280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     *
24120280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param spanX The horizontal span of the cell we want to find.
24130280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param spanY The vertical span of the cell we want to find.
24140280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param ignoreView The home screen item we should treat as not occupying any space
24150280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param intersectX The X coordinate of the cell that we should try to overlap
24160280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param intersectX The Y coordinate of the cell that we should try to overlap
24170280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     *
24180280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @return True if a vacant cell of the specified dimension was found, false otherwise.
24190280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     */
24200280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    boolean findCellForSpanThatIntersects(int[] cellXY, int spanX, int spanY,
24210280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            int intersectX, int intersectY) {
24220280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        return findCellForSpanThatIntersectsIgnoring(
2423482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                cellXY, spanX, spanY, intersectX, intersectY, null, mOccupied);
24240280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
24250280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
24260280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    /**
24270280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * The superset of the above two methods
24280280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     */
24290280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    boolean findCellForSpanThatIntersectsIgnoring(int[] cellXY, int spanX, int spanY,
2430482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            int intersectX, int intersectY, View ignoreView, boolean occupied[][]) {
2431c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka        // mark space take by ignoreView as available (method checks if ignoreView is null)
2432482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsAsUnoccupiedForView(ignoreView, occupied);
24330280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
243428750fba6a2d141eb9a1e566718c17236030b815Michael Jurka        boolean foundCell = false;
24350280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        while (true) {
24360280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            int startX = 0;
24370280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            if (intersectX >= 0) {
24380280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                startX = Math.max(startX, intersectX - (spanX - 1));
24390280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            }
24400280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            int endX = mCountX - (spanX - 1);
24410280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            if (intersectX >= 0) {
24420280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                endX = Math.min(endX, intersectX + (spanX - 1) + (spanX == 1 ? 1 : 0));
24430280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            }
24440280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            int startY = 0;
24450280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            if (intersectY >= 0) {
24460280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                startY = Math.max(startY, intersectY - (spanY - 1));
24470280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            }
24480280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            int endY = mCountY - (spanY - 1);
24490280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            if (intersectY >= 0) {
24500280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                endY = Math.min(endY, intersectY + (spanY - 1) + (spanY == 1 ? 1 : 0));
24510280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            }
24520280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
2453bbc60d8e79416e37cbede55c159bf6aaa6c171d5Winson Chung            for (int y = startY; y < endY && !foundCell; y++) {
24540280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                inner:
2455bbc60d8e79416e37cbede55c159bf6aaa6c171d5Winson Chung                for (int x = startX; x < endX; x++) {
24560280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                    for (int i = 0; i < spanX; i++) {
24570280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                        for (int j = 0; j < spanY; j++) {
2458482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                            if (occupied[x + i][y + j]) {
2459bbc60d8e79416e37cbede55c159bf6aaa6c171d5Winson Chung                                // small optimization: we can skip to after the column we just found
24600280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                                // an occupied cell
2461bbc60d8e79416e37cbede55c159bf6aaa6c171d5Winson Chung                                x += i;
24620280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                                continue inner;
24630280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                            }
24640280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                        }
24650280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                    }
24660280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                    if (cellXY != null) {
24670280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                        cellXY[0] = x;
24680280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                        cellXY[1] = y;
24690280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                    }
247028750fba6a2d141eb9a1e566718c17236030b815Michael Jurka                    foundCell = true;
247128750fba6a2d141eb9a1e566718c17236030b815Michael Jurka                    break;
24720280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                }
24730280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            }
24740280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            if (intersectX == -1 && intersectY == -1) {
24750280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                break;
24760280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            } else {
24770280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                // if we failed to find anything, try again but without any requirements of
24780280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                // intersecting
24790280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                intersectX = -1;
24800280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                intersectY = -1;
24810280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                continue;
24820280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            }
24830280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        }
24840280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
2485c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka        // re-mark space taken by ignoreView as occupied
2486482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsAsOccupiedForView(ignoreView, occupied);
248728750fba6a2d141eb9a1e566718c17236030b815Michael Jurka        return foundCell;
24880280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
24890280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
249031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
2491c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung     * A drag event has begun over this layout.
2492c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung     * It may have begun over this layout (in which case onDragChild is called first),
2493c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung     * or it may have begun on another layout.
2494c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung     */
2495c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung    void onDragEnter() {
2496c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung        if (!mDragging) {
2497c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung            // Fade in the drag indicators
2498c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung            if (mCrosshairsAnimator != null) {
2499c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung                mCrosshairsAnimator.animateIn();
2500c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung            }
2501c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung        }
2502c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung        mDragging = true;
2503c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung    }
2504c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung
2505c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung    /**
25060280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * Called when drag has left this CellLayout or has been completed (successfully or not)
25076569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     */
25080280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    void onDragExit() {
25094be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        // This can actually be called when we aren't in a drag, e.g. when adding a new
25104be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        // item to this layout via the customize drawer.
25114be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        // Guard against that case.
25124be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        if (mDragging) {
25134be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            mDragging = false;
25146569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
25154be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            // Fade out the drag indicators
25164be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            if (mCrosshairsAnimator != null) {
25174be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                mCrosshairsAnimator.animateOut();
25184be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            }
25194be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        }
252008ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy
252108ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy        // Invalidate the drag data
2522d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        mDragCell[0] = mDragCell[1] = -1;
252308ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy        mDragOutlineAnims[mDragOutlineCurrent].animateOut();
252408ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy        mDragOutlineCurrent = (mDragOutlineCurrent + 1) % mDragOutlineAnims.length;
252519f3792523fe2d55ea791a9286398a6120920690Adam Cohen        revertTempState();
252633945b21544bc98381df17726a3537c292d8c985Michael Jurka        setIsDragOverlapping(false);
25276569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    }
25286569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
25296569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    /**
2530aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     * Mark a child as having been dropped.
2531de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy     * At the beginning of the drag operation, the child may have been on another
2532ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy     * screen, but it is re-parented before this method is called.
253331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     *
253431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param child The child that is being dropped
253531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
2536716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    void onDropChild(View child) {
2537d94533d04a5f8f5485f106d10af60169857ea899Romain Guy        if (child != null) {
2538d94533d04a5f8f5485f106d10af60169857ea899Romain Guy            LayoutParams lp = (LayoutParams) child.getLayoutParams();
253984f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy            lp.dropped = true;
2540d94533d04a5f8f5485f106d10af60169857ea899Romain Guy            child.requestLayout();
2541d94533d04a5f8f5485f106d10af60169857ea899Romain Guy        }
254231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
254331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
254431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
254531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * Computes a bounding rectangle for a range of cells
2546aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     *
254731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param cellX X coordinate of upper left corner expressed as a cell position
254831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param cellY Y coordinate of upper left corner expressed as a cell position
2549aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     * @param cellHSpan Width in cells
255031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param cellVSpan Height in cells
25516569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     * @param resultRect Rect into which to put the results
255231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
2553d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    public void cellToRect(int cellX, int cellY, int cellHSpan, int cellVSpan, Rect resultRect) {
255431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        final int cellWidth = mCellWidth;
255531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        final int cellHeight = mCellHeight;
255631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        final int widthGap = mWidthGap;
255731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        final int heightGap = mHeightGap;
2558aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
25594b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int hStartPadding = getPaddingLeft();
25604b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int vStartPadding = getPaddingTop();
2561aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
256231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int width = cellHSpan * cellWidth + ((cellHSpan - 1) * widthGap);
256331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int height = cellVSpan * cellHeight + ((cellVSpan - 1) * heightGap);
256431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
256531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int x = hStartPadding + cellX * (cellWidth + widthGap);
256631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int y = vStartPadding + cellY * (cellHeight + heightGap);
2567aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
25686569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        resultRect.set(x, y, x + width, y + height);
256931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
2570aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
257131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
2572aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     * Computes the required horizontal and vertical cell spans to always
257331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * fit the given rectangle.
2574aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     *
257531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param width Width in pixels
257631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param height Height in pixels
25778f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy     * @param result An array of length 2 in which to store the result (may be null).
257831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
25798f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy    public int[] rectToCell(int width, int height, int[] result) {
25809987a5c45e7d01a780d73b269bdce8d8a5309219Michael Jurka        return rectToCell(getResources(), width, height, result);
25819987a5c45e7d01a780d73b269bdce8d8a5309219Michael Jurka    }
25829987a5c45e7d01a780d73b269bdce8d8a5309219Michael Jurka
25839987a5c45e7d01a780d73b269bdce8d8a5309219Michael Jurka    public static int[] rectToCell(Resources resources, int width, int height, int[] result) {
258431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // Always assume we're working with the smallest span to make sure we
258531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // reserve enough space in both orientations.
258679e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato        int actualWidth = resources.getDimensionPixelSize(R.dimen.workspace_cell_width);
258779e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato        int actualHeight = resources.getDimensionPixelSize(R.dimen.workspace_cell_height);
258831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int smallerSize = Math.min(actualWidth, actualHeight);
258979e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato
259031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // Always round up to next largest cell
259154c725cc294cd43ed0650179bfae64a622547660Winson Chung        int spanX = (int) Math.ceil(width / (float) smallerSize);
259254c725cc294cd43ed0650179bfae64a622547660Winson Chung        int spanY = (int) Math.ceil(height / (float) smallerSize);
259379e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato
25948f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy        if (result == null) {
25958f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy            return new int[] { spanX, spanY };
25968f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy        }
25978f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy        result[0] = spanX;
25988f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy        result[1] = spanY;
25998f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy        return result;
260031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
260131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
2602f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka    public int[] cellSpansToSize(int hSpans, int vSpans) {
2603f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka        int[] size = new int[2];
2604f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka        size[0] = hSpans * mCellWidth + (hSpans - 1) * mWidthGap;
2605f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka        size[1] = vSpans * mCellHeight + (vSpans - 1) * mHeightGap;
2606f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka        return size;
2607f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka    }
2608f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka
260931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
2610047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy     * Calculate the grid spans needed to fit given item
2611047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy     */
2612047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy    public void calculateSpans(ItemInfo info) {
2613047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        final int minWidth;
2614047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        final int minHeight;
2615047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy
2616047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        if (info instanceof LauncherAppWidgetInfo) {
2617047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy            minWidth = ((LauncherAppWidgetInfo) info).minWidth;
2618047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy            minHeight = ((LauncherAppWidgetInfo) info).minHeight;
2619047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        } else if (info instanceof PendingAddWidgetInfo) {
2620047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy            minWidth = ((PendingAddWidgetInfo) info).minWidth;
2621047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy            minHeight = ((PendingAddWidgetInfo) info).minHeight;
2622047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        } else {
2623047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy            // It's not a widget, so it must be 1x1
2624047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy            info.spanX = info.spanY = 1;
2625047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy            return;
2626047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        }
2627047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        int[] spans = rectToCell(minWidth, minHeight, null);
2628047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        info.spanX = spans[0];
2629047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        info.spanY = spans[1];
2630047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy    }
2631047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy
2632047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy    /**
263331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * Find the first vacant cell, if there is one.
263431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     *
263531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param vacant Holds the x and y coordinate of the vacant cell
263631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param spanX Horizontal cell span.
263731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param spanY Vertical cell span.
2638aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     *
263931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @return True if a vacant cell was found
264031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
264131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public boolean getVacantCell(int[] vacant, int spanX, int spanY) {
264231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
26430280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        return findVacantCell(vacant, spanX, spanY, mCountX, mCountY, mOccupied);
264431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
264531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
264631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    static boolean findVacantCell(int[] vacant, int spanX, int spanY,
264731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            int xCount, int yCount, boolean[][] occupied) {
264831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
26492801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        for (int y = 0; y < yCount; y++) {
26502801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            for (int x = 0; x < xCount; x++) {
265131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                boolean available = !occupied[x][y];
265231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectout:            for (int i = x; i < x + spanX - 1 && x < xCount; i++) {
265331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                    for (int j = y; j < y + spanY - 1 && y < yCount; j++) {
265431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                        available = available && !occupied[i][j];
265531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                        if (!available) break out;
265631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                    }
265731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                }
265831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
265931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                if (available) {
266031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                    vacant[0] = x;
266131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                    vacant[1] = y;
266231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                    return true;
266331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                }
266431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            }
266531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
266631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
266731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        return false;
266831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
266931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
26700280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    private void clearOccupiedCells() {
26710280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        for (int x = 0; x < mCountX; x++) {
26720280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            for (int y = 0; y < mCountY; y++) {
26730280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                mOccupied[x][y] = false;
267431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            }
267531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
26760280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
267731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
26781b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen    /**
26791b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen     * Given a view, determines how much that view can be expanded in all directions, in terms of
26801b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen     * whether or not there are other items occupying adjacent cells. Used by the
26811b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen     * AppWidgetResizeFrame to determine how the widget can be resized.
26821b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen     */
2683d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    public void getExpandabilityArrayForView(View view, int[] expandability) {
26841b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen        final LayoutParams lp = (LayoutParams) view.getLayoutParams();
2685d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        boolean flag;
2686d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
26871b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen        expandability[AppWidgetResizeFrame.LEFT] = 0;
2688d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        for (int x = lp.cellX - 1; x >= 0; x--) {
2689d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            flag = false;
2690d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            for (int y = lp.cellY; y < lp.cellY + lp.cellVSpan; y++) {
2691d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                if (mOccupied[x][y]) flag = true;
2692d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            }
2693d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            if (flag) break;
26941b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen            expandability[AppWidgetResizeFrame.LEFT]++;
2695d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        }
2696d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
26971b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen        expandability[AppWidgetResizeFrame.TOP] = 0;
2698d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        for (int y = lp.cellY - 1; y >= 0; y--) {
2699d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            flag = false;
2700d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            for (int x = lp.cellX; x < lp.cellX + lp.cellHSpan; x++) {
2701d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                if (mOccupied[x][y]) flag = true;
2702d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            }
2703d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            if (flag) break;
27041b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen            expandability[AppWidgetResizeFrame.TOP]++;
27051b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen        }
2706d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
27071b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen        expandability[AppWidgetResizeFrame.RIGHT] = 0;
2708d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        for (int x = lp.cellX + lp.cellHSpan; x < mCountX; x++) {
2709d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            flag = false;
2710d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            for (int y = lp.cellY; y < lp.cellY + lp.cellVSpan; y++) {
2711d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                if (mOccupied[x][y]) flag = true;
2712d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            }
2713d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            if (flag) break;
27141b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen            expandability[AppWidgetResizeFrame.RIGHT]++;
27151b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen        }
2716d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
27171b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen        expandability[AppWidgetResizeFrame.BOTTOM] = 0;
2718d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        for (int y = lp.cellY + lp.cellVSpan; y < mCountY; y++) {
2719d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            flag = false;
2720d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            for (int x = lp.cellX; x < lp.cellX + lp.cellHSpan; x++) {
2721d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                if (mOccupied[x][y]) flag = true;
2722d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            }
2723d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            if (flag) break;
27241b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen            expandability[AppWidgetResizeFrame.BOTTOM]++;
27251b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen        }
2726d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    }
2727d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
2728d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    public void onMove(View view, int newCellX, int newCellY, int newSpanX, int newSpanY) {
27290280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        markCellsAsUnoccupiedForView(view);
2730482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsForView(newCellX, newCellY, newSpanX, newSpanY, mOccupied, true);
27310280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
273231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
2733d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    public void markCellsAsOccupiedForView(View view) {
2734482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsAsOccupiedForView(view, mOccupied);
2735482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2736482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public void markCellsAsOccupiedForView(View view, boolean[][] occupied) {
2737a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        if (view == null || view.getParent() != mShortcutsAndWidgets) return;
27380280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        LayoutParams lp = (LayoutParams) view.getLayoutParams();
2739482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, occupied, true);
27400280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
27410280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
2742d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    public void markCellsAsUnoccupiedForView(View view) {
2743482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsAsUnoccupiedForView(view, mOccupied);
2744482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2745482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public void markCellsAsUnoccupiedForView(View view, boolean occupied[][]) {
2746a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        if (view == null || view.getParent() != mShortcutsAndWidgets) return;
27470280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        LayoutParams lp = (LayoutParams) view.getLayoutParams();
2748482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, occupied, false);
27490280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
27500280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
2751482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private void markCellsForView(int cellX, int cellY, int spanX, int spanY, boolean[][] occupied,
2752482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            boolean value) {
2753482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (cellX < 0 || cellY < 0) return;
27540280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        for (int x = cellX; x < cellX + spanX && x < mCountX; x++) {
27550280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            for (int y = cellY; y < cellY + spanY && y < mCountY; y++) {
2756482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                occupied[x][y] = value;
275731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            }
275831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
275931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
276031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
27612801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    public int getDesiredWidth() {
27624b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        return mPaddingLeft + mPaddingRight + (mCountX * mCellWidth) +
27632801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen                (Math.max((mCountX - 1), 0) * mWidthGap);
27642801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    }
27652801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
27662801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    public int getDesiredHeight()  {
27674b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        return mPaddingTop + mPaddingBottom + (mCountY * mCellHeight) +
27682801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen                (Math.max((mCountY - 1), 0) * mHeightGap);
27692801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    }
27702801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
277166d72178af91d455700875635473be942bc90e54Michael Jurka    public boolean isOccupied(int x, int y) {
277266d72178af91d455700875635473be942bc90e54Michael Jurka        if (x < mCountX && y < mCountY) {
277366d72178af91d455700875635473be942bc90e54Michael Jurka            return mOccupied[x][y];
277466d72178af91d455700875635473be942bc90e54Michael Jurka        } else {
277566d72178af91d455700875635473be942bc90e54Michael Jurka            throw new RuntimeException("Position exceeds the bound of this CellLayout");
277666d72178af91d455700875635473be942bc90e54Michael Jurka        }
277766d72178af91d455700875635473be942bc90e54Michael Jurka    }
277866d72178af91d455700875635473be942bc90e54Michael Jurka
277931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
278031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
278131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        return new CellLayout.LayoutParams(getContext(), attrs);
278231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
278331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
278431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
278531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
278631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        return p instanceof CellLayout.LayoutParams;
278731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
278831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
278931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
279031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
279131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        return new CellLayout.LayoutParams(p);
279231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
279331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
2794aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung    public static class CellLayoutAnimationController extends LayoutAnimationController {
2795aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        public CellLayoutAnimationController(Animation animation, float delay) {
2796aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            super(animation, delay);
2797aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        }
2798aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
2799aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        @Override
2800aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        protected long getDelayForView(View view) {
2801aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            return (int) (Math.random() * 150);
2802aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        }
2803aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung    }
2804aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
280531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public static class LayoutParams extends ViewGroup.MarginLayoutParams {
280631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        /**
280731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         * Horizontal location of the item in the grid.
280831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         */
280931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        @ViewDebug.ExportedProperty
281031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public int cellX;
281131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
281231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        /**
281331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         * Vertical location of the item in the grid.
281431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         */
281531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        @ViewDebug.ExportedProperty
281631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public int cellY;
281731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
281831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        /**
2819482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         * Temporary horizontal location of the item in the grid during reorder
2820482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         */
2821482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        public int tmpCellX;
2822482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2823482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        /**
2824482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         * Temporary vertical location of the item in the grid during reorder
2825482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         */
2826482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        public int tmpCellY;
2827482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2828482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        /**
2829482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         * Indicates that the temporary coordinates should be used to layout the items
2830482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         */
2831482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        public boolean useTmpCoords;
2832482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2833482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        /**
283431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         * Number of cells spanned horizontally by the item.
283531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         */
283631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        @ViewDebug.ExportedProperty
283731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public int cellHSpan;
283831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
283931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        /**
284031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         * Number of cells spanned vertically by the item.
284131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         */
284231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        @ViewDebug.ExportedProperty
284331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public int cellVSpan;
2844aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
28451b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen        /**
28461b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen         * Indicates whether the item will set its x, y, width and height parameters freely,
28471b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen         * or whether these will be computed based on cellX, cellY, cellHSpan and cellVSpan.
28481b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen         */
2849d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        public boolean isLockedToGrid = true;
2850d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
2851482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        /**
2852482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         * Indicates whether this item can be reordered. Always true except in the case of the
2853482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         * the AllApps button.
2854482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         */
2855482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        public boolean canReorder = true;
2856482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
285731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // X coordinate of the view in the layout.
285831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        @ViewDebug.ExportedProperty
285931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int x;
286031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // Y coordinate of the view in the layout.
286131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        @ViewDebug.ExportedProperty
286231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int y;
286331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
286484f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy        boolean dropped;
2865fcb9e7144e58614f5ae0e9b272fb7ce040848c67Romain Guy
286631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public LayoutParams(Context c, AttributeSet attrs) {
286731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            super(c, attrs);
286831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            cellHSpan = 1;
286931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            cellVSpan = 1;
287031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
287131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
287231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public LayoutParams(ViewGroup.LayoutParams source) {
287331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            super(source);
287431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            cellHSpan = 1;
287531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            cellVSpan = 1;
287631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
2877aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
2878aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        public LayoutParams(LayoutParams source) {
2879aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            super(source);
2880aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            this.cellX = source.cellX;
2881aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            this.cellY = source.cellY;
2882aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            this.cellHSpan = source.cellHSpan;
2883aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            this.cellVSpan = source.cellVSpan;
2884aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        }
2885aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
288631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public LayoutParams(int cellX, int cellY, int cellHSpan, int cellVSpan) {
28878f19cdd62f6e2be05e3890916eabd11317ae1bc2Romain Guy            super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
288831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            this.cellX = cellX;
288931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            this.cellY = cellY;
289031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            this.cellHSpan = cellHSpan;
289131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            this.cellVSpan = cellVSpan;
289231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
289331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
28947f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public void setup(int cellWidth, int cellHeight, int widthGap, int heightGap) {
2895d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            if (isLockedToGrid) {
2896d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                final int myCellHSpan = cellHSpan;
2897d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                final int myCellVSpan = cellVSpan;
2898482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                final int myCellX = useTmpCoords ? tmpCellX : cellX;
2899482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                final int myCellY = useTmpCoords ? tmpCellY : cellY;
29001b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen
2901d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                width = myCellHSpan * cellWidth + ((myCellHSpan - 1) * widthGap) -
2902d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                        leftMargin - rightMargin;
2903d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                height = myCellVSpan * cellHeight + ((myCellVSpan - 1) * heightGap) -
2904d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                        topMargin - bottomMargin;
2905eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                x = (int) (myCellX * (cellWidth + widthGap) + leftMargin);
2906eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                y = (int) (myCellY * (cellHeight + heightGap) + topMargin);
2907d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            }
2908d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        }
2909d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
2910aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        public String toString() {
2911aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            return "(" + this.cellX + ", " + this.cellY + ")";
2912aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        }
29137f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
29147f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public void setWidth(int width) {
29157f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            this.width = width;
29167f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
29177f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
29187f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public int getWidth() {
29197f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            return width;
29207f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
29217f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
29227f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public void setHeight(int height) {
29237f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            this.height = height;
29247f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
29257f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
29267f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public int getHeight() {
29277f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            return height;
29287f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
29297f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
29307f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public void setX(int x) {
29317f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            this.x = x;
29327f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
29337f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
29347f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public int getX() {
29357f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            return x;
29367f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
29377f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
29387f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public void setY(int y) {
29397f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            this.y = y;
29407f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
29417f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
29427f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public int getY() {
29437f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            return y;
29447f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
294531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
294631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
29470280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    // This class stores info for two purposes:
29480280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    // 1. When dragging items (mDragInfo in Workspace), we store the View, its cellX & cellY,
29490280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    //    its spanX, spanY, and the screen it is on
29500280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    // 2. When long clicking on an empty cell in a CellLayout, we save information about the
29510280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    //    cellX and cellY coordinates and which page was clicked. We then set this as a tag on
29520280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    //    the CellLayout that was long clicked
2953e5fb0f27bca7afb996258a7163c76ca7390d7bffMichael Jurka    static final class CellInfo {
295431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        View cell;
2955a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka        int cellX = -1;
2956a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka        int cellY = -1;
295731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int spanX;
295831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int spanY;
295931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int screen;
29603d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        long container;
296131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
296231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        @Override
296331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public String toString() {
2964aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            return "Cell[view=" + (cell == null ? "null" : cell.getClass())
2965aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung                    + ", x=" + cellX + ", y=" + cellY + "]";
296631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
296731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
2968d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka
2969d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka    public boolean lastDownOnOccupiedCell() {
2970d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka        return mLastDownOnOccupiedCell;
2971d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka    }
297231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project}
2973