CellLayout.java revision 6b8a02d63a5d9cab8209381993e37db6a6afb753
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;
2118014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurkaimport android.animation.ObjectAnimator;
22bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohenimport android.animation.PropertyValuesHolder;
2300397b1d9233409d9d6b233b077ae12d09768ce8Chet Haaseimport android.animation.TimeInterpolator;
24de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroyimport android.animation.ValueAnimator;
25de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroyimport android.animation.ValueAnimator.AnimatorUpdateListener;
2631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.content.Context;
2779e56263dbcbe85dc434df372bc6e6730aa13477Joe Onoratoimport android.content.res.Resources;
28aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chungimport android.content.res.TypedArray;
294be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onoratoimport android.graphics.Bitmap;
30aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chungimport android.graphics.Canvas;
310dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynnimport android.graphics.Color;
324be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onoratoimport android.graphics.Paint;
33de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroyimport android.graphics.Point;
34de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroyimport android.graphics.PointF;
35b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohenimport android.graphics.PorterDuff;
36b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohenimport android.graphics.PorterDuffXfermode;
3731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.graphics.Rect;
38482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohenimport android.graphics.drawable.ColorDrawable;
396569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroyimport android.graphics.drawable.Drawable;
40b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohenimport android.graphics.drawable.NinePatchDrawable;
4131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.util.AttributeSet;
424be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onoratoimport android.util.Log;
4331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.MotionEvent;
4431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.View;
4531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.ViewDebug;
4631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.ViewGroup;
47aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chungimport android.view.animation.Animation;
48150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chungimport android.view.animation.DecelerateInterpolator;
49aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chungimport android.view.animation.LayoutAnimationController;
5031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
516639687cd67bab1aeef2a75e5c6bc458b20dc082Adam Cohenimport com.android.launcher.R;
5269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohenimport com.android.launcher2.FolderIcon.FolderRingAnimator;
538e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy
5469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohenimport java.util.ArrayList;
55c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohenimport java.util.Arrays;
56bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohenimport java.util.HashMap;
57d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohenimport java.util.Stack;
58c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen
59bdb5c5342adc550559fd723af461e53248f2fba8Michael Jurkapublic class CellLayout extends ViewGroup {
60aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung    static final String TAG = "CellLayout";
61aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
624b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung    private int mOriginalCellWidth;
634b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung    private int mOriginalCellHeight;
6431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private int mCellWidth;
6531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private int mCellHeight;
66aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
67d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen    private int mCountX;
68d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen    private int mCountY;
6931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
70234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen    private int mOriginalWidthGap;
71234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen    private int mOriginalHeightGap;
7231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private int mWidthGap;
7331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private int mHeightGap;
744b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung    private int mMaxGap;
75ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen    private boolean mScrollingTransformsDirty = false;
7631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
7731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private final Rect mRect = new Rect();
7831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private final CellInfo mCellInfo = new CellInfo();
79aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
80de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy    // These are temporary variables to prevent having to allocate a new object just to
81de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy    // return an (x, y) value from helper functions. Do NOT use them to maintain other state.
820be025d64c1f84138fe430a58875886e66aae767Winson Chung    private final int[] mTmpXY = new int[2];
83de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy    private final int[] mTmpPoint = new int[2];
84de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy    private final PointF mTmpPointF = new PointF();
8569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen    int[] mTempLocation = new int[2];
866569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
8731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    boolean[][] mOccupied;
88482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    boolean[][] mTmpOccupied;
89d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka    private boolean mLastDownOnOccupiedCell = false;
9031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
91dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    private OnTouchListener mInterceptTouchListener;
92dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka
9369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen    private ArrayList<FolderRingAnimator> mFolderOuterRings = new ArrayList<FolderRingAnimator>();
94c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen    private int[] mFolderLeaveBehindCell = {-1, -1};
9569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
96b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    private int mForegroundAlpha = 0;
975f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka    private float mBackgroundAlpha;
981b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen    private float mBackgroundAlphaMultiplier = 1.0f;
99f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen
10033945b21544bc98381df17726a3537c292d8c985Michael Jurka    private Drawable mNormalBackground;
10133945b21544bc98381df17726a3537c292d8c985Michael Jurka    private Drawable mActiveGlowBackground;
102b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    private Drawable mOverScrollForegroundDrawable;
103b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    private Drawable mOverScrollLeft;
104b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    private Drawable mOverScrollRight;
10518014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka    private Rect mBackgroundRect;
106b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    private Rect mForegroundRect;
107b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    private int mForegroundPadding;
10833945b21544bc98381df17726a3537c292d8c985Michael Jurka
10933945b21544bc98381df17726a3537c292d8c985Michael Jurka    // If we're actively dragging something over this screen, mIsDragOverlapping is true
11033945b21544bc98381df17726a3537c292d8c985Michael Jurka    private boolean mIsDragOverlapping = false;
111de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy    private final Point mDragCenter = new Point();
1126569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
113150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung    // These arrays are used to implement the drag visualization on x-large screens.
1144be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato    // They are used as circular arrays, indexed by mDragOutlineCurrent.
115d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    private Rect[] mDragOutlines = new Rect[4];
116472b281d5cb4f5660df981a6c912266b9f5703feChet Haase    private float[] mDragOutlineAlphas = new float[mDragOutlines.length];
1174be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato    private InterruptibleInOutAnimator[] mDragOutlineAnims =
1184be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            new InterruptibleInOutAnimator[mDragOutlines.length];
119150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung
120150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung    // Used as an index into the above 3 arrays; indicates which is the most current value.
1214be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato    private int mDragOutlineCurrent = 0;
1228e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy    private final Paint mDragOutlinePaint = new Paint();
123150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung
12496864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy    private BubbleTextView mPressedOrFocusedIcon;
12596864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy
126de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy    private Drawable mCrosshairsDrawable = null;
12749250ad530385fcdd6072ca54697f670ec503b59Patrick Dubroy    private InterruptibleInOutAnimator mCrosshairsAnimator = null;
128de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy    private float mCrosshairsVisibility = 0.0f;
129de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy
130482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private HashMap<CellLayout.LayoutParams, Animator> mReorderAnimators = new
131482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            HashMap<CellLayout.LayoutParams, Animator>();
132bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen
1336569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    // When a drag operation is in progress, holds the nearest cell to the touch point
1346569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    private final int[] mDragCell = new int[2];
13531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
1364be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato    private boolean mDragging = false;
137482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private boolean mItemLocationsDirty = false;
1384be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato
139ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy    private TimeInterpolator mEaseOutInterpolator;
140a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka    private ShortcutAndWidgetContainer mShortcutsAndWidgets;
141ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy
1420dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn    private boolean mIsHotseat = false;
143eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung    private float mChildScale = 1f;
144eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung    private float mHotseatChildScale = 1f;
1450dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn
146482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public static final int MODE_DRAG_OVER = 0;
147482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public static final int MODE_ON_DROP = 1;
148482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public static final int MODE_ON_DROP_EXTERNAL = 2;
149482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public static final int MODE_ACCEPT_DROP = 3;
150482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private static final boolean DESTRUCTIVE_REORDER = true;
151482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private static final boolean DEBUG_VISUALIZE_OCCUPIED = false;
152482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
153482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private ArrayList<View> mIntersectingViews = new ArrayList<View>();
154482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private Rect mOccupiedRect = new Rect();
155482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private int[] mDirectionVector = new int[2];
156482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
15731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public CellLayout(Context context) {
15831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        this(context, null);
15931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
16031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
16131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public CellLayout(Context context, AttributeSet attrs) {
16231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        this(context, attrs, 0);
16331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
16431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
16531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public CellLayout(Context context, AttributeSet attrs, int defStyle) {
16631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        super(context, attrs, defStyle);
1676569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
1686569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        // A ViewGroup usually does not draw, but CellLayout needs to draw a rectangle to show
1696569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        // the user where a dragged item will land when dropped.
1706569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        setWillNotDraw(false);
171a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka
17231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CellLayout, defStyle, 0);
17331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
1744b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        mOriginalCellWidth =
1754b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung            mCellWidth = a.getDimensionPixelSize(R.styleable.CellLayout_cellWidth, 10);
1764b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        mOriginalCellHeight =
1774b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung            mCellHeight = a.getDimensionPixelSize(R.styleable.CellLayout_cellHeight, 10);
178234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen        mWidthGap = mOriginalWidthGap = a.getDimensionPixelSize(R.styleable.CellLayout_widthGap, 0);
179234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen        mHeightGap = mOriginalHeightGap = a.getDimensionPixelSize(R.styleable.CellLayout_heightGap, 0);
1804b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        mMaxGap = a.getDimensionPixelSize(R.styleable.CellLayout_maxGap, 0);
181d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        mCountX = LauncherModel.getCellCountX();
182d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        mCountY = LauncherModel.getCellCountY();
1830280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        mOccupied = new boolean[mCountX][mCountY];
184482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        mTmpOccupied = new boolean[mCountX][mCountY];
18531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
18631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        a.recycle();
18731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
18831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        setAlwaysDrawnWithCacheEnabled(false);
18931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
190046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        final Resources res = getResources();
191de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy
192967289b6d5fec77f5c381d11ffb2319f3bb5e737Winson Chung        mNormalBackground = res.getDrawable(R.drawable.homescreen_blue_normal_holo);
193dea74b7d12b0fcd50bfdb4274f9867ba76d75238Winson Chung        mActiveGlowBackground = res.getDrawable(R.drawable.homescreen_blue_strong_holo);
194b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung
195b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        mOverScrollLeft = res.getDrawable(R.drawable.overscroll_glow_left);
196b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        mOverScrollRight = res.getDrawable(R.drawable.overscroll_glow_right);
197b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        mForegroundPadding =
198b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen                res.getDimensionPixelSize(R.dimen.workspace_overscroll_drawable_padding);
199b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung
200b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung        mNormalBackground.setFilterBitmap(true);
201b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung        mActiveGlowBackground.setFilterBitmap(true);
202de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy
203eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung        int iconScale = res.getInteger(R.integer.app_icon_scale_percent);
204eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung        if (iconScale >= 0) {
205eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung            mChildScale = iconScale / 100f;
206eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung        }
207eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung        int hotseatIconScale = res.getInteger(R.integer.app_icon_hotseat_scale_percent);
208eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung        if (hotseatIconScale >= 0) {
209eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung            mHotseatChildScale = hotseatIconScale / 100f;
210eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung        }
2110dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn
212046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        // Initialize the data structures used for the drag visualization.
213150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung
214046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        mCrosshairsDrawable = res.getDrawable(R.drawable.gardening_crosshairs);
215ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy        mEaseOutInterpolator = new DecelerateInterpolator(2.5f); // Quint ease out
216de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy
217046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        // Set up the animation for fading the crosshairs in and out
218046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        int animDuration = res.getInteger(R.integer.config_crosshairsFadeInTime);
21949250ad530385fcdd6072ca54697f670ec503b59Patrick Dubroy        mCrosshairsAnimator = new InterruptibleInOutAnimator(animDuration, 0.0f, 1.0f);
220472b281d5cb4f5660df981a6c912266b9f5703feChet Haase        mCrosshairsAnimator.getAnimator().addUpdateListener(new AnimatorUpdateListener() {
221046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy            public void onAnimationUpdate(ValueAnimator animation) {
222046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy                mCrosshairsVisibility = ((Float) animation.getAnimatedValue()).floatValue();
2238e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy                invalidate();
224046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy            }
225046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        });
226ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy        mCrosshairsAnimator.getAnimator().setInterpolator(mEaseOutInterpolator);
227046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy
228b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung        mDragCell[0] = mDragCell[1] = -1;
2294be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        for (int i = 0; i < mDragOutlines.length; i++) {
230d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            mDragOutlines[i] = new Rect(-1, -1, -1, -1);
231046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        }
232046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy
233046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        // When dragging things around the home screens, we show a green outline of
234046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        // where the item will land. The outlines gradually fade out, leaving a trail
235046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        // behind the drag path.
236046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        // Set up all the animations that are used to implement this fading.
237046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        final int duration = res.getInteger(R.integer.config_dragOutlineFadeTime);
238472b281d5cb4f5660df981a6c912266b9f5703feChet Haase        final float fromAlphaValue = 0;
239472b281d5cb4f5660df981a6c912266b9f5703feChet Haase        final float toAlphaValue = (float)res.getInteger(R.integer.config_dragOutlineMaxAlpha);
2404be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato
2418e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy        Arrays.fill(mDragOutlineAlphas, fromAlphaValue);
2424be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato
2434be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        for (int i = 0; i < mDragOutlineAnims.length; i++) {
244046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy            final InterruptibleInOutAnimator anim =
245046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy                new InterruptibleInOutAnimator(duration, fromAlphaValue, toAlphaValue);
246ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy            anim.getAnimator().setInterpolator(mEaseOutInterpolator);
247046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy            final int thisIndex = i;
248472b281d5cb4f5660df981a6c912266b9f5703feChet Haase            anim.getAnimator().addUpdateListener(new AnimatorUpdateListener() {
249de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                public void onAnimationUpdate(ValueAnimator animation) {
2504be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    final Bitmap outline = (Bitmap)anim.getTag();
2514be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato
2524be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    // If an animation is started and then stopped very quickly, we can still
2534be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    // get spurious updates we've cleared the tag. Guard against this.
2544be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    if (outline == null) {
255fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy                        if (false) {
256fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy                            Object val = animation.getAnimatedValue();
257fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy                            Log.d(TAG, "anim " + thisIndex + " update: " + val +
258fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy                                     ", isStopped " + anim.isStopped());
259fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy                        }
2604be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                        // Try to prevent it from continuing to run
2614be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                        animation.cancel();
2624be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    } else {
263472b281d5cb4f5660df981a6c912266b9f5703feChet Haase                        mDragOutlineAlphas[thisIndex] = (Float) animation.getAnimatedValue();
264d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        CellLayout.this.invalidate(mDragOutlines[thisIndex]);
2654be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    }
266de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                }
267de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy            });
2684be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            // The animation holds a reference to the drag outline bitmap as long is it's
2694be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            // running. This way the bitmap can be GCed when the animations are complete.
270472b281d5cb4f5660df981a6c912266b9f5703feChet Haase            anim.getAnimator().addListener(new AnimatorListenerAdapter() {
2713c4c20fbe682cb4b3ef94f09afe0af09171583f3Michael Jurka                @Override
2724be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                public void onAnimationEnd(Animator animation) {
273472b281d5cb4f5660df981a6c912266b9f5703feChet Haase                    if ((Float) ((ValueAnimator) animation).getAnimatedValue() == 0f) {
2744be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                        anim.setTag(null);
2754be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    }
2764be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                }
2774be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            });
2784be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            mDragOutlineAnims[i] = anim;
279de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy        }
280ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy
28118014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka        mBackgroundRect = new Rect();
282b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        mForegroundRect = new Rect();
283bea15195346bab3c52b0156e92f2b71f0811b210Michael Jurka
284a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets = new ShortcutAndWidgetContainer(context);
285a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.setCellDimensions(mCellWidth, mCellHeight, mWidthGap, mHeightGap);
286a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        addView(mShortcutsAndWidgets);
28718014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka    }
28818014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka
289f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka    static int widthInPortrait(Resources r, int numCells) {
290f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka        // We use this method from Workspace to figure out how many rows/columns Launcher should
291f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka        // have. We ignore the left/right padding on CellLayout because it turns out in our design
292f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka        // the padding extends outside the visible screen size, but it looked fine anyway.
293f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka        int cellWidth = r.getDimensionPixelSize(R.dimen.workspace_cell_width);
2944b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        int minGap = Math.min(r.getDimensionPixelSize(R.dimen.workspace_width_gap),
2954b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                r.getDimensionPixelSize(R.dimen.workspace_height_gap));
296f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka
2974b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        return  minGap * (numCells - 1) + cellWidth * numCells;
298f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka    }
299f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka
300f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka    static int heightInLandscape(Resources r, int numCells) {
301f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka        // We use this method from Workspace to figure out how many rows/columns Launcher should
302f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka        // have. We ignore the left/right padding on CellLayout because it turns out in our design
303f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka        // the padding extends outside the visible screen size, but it looked fine anyway.
304f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka        int cellHeight = r.getDimensionPixelSize(R.dimen.workspace_cell_height);
3054b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        int minGap = Math.min(r.getDimensionPixelSize(R.dimen.workspace_width_gap),
3064b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                r.getDimensionPixelSize(R.dimen.workspace_height_gap));
307f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka
3084b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        return minGap * (numCells - 1) + cellHeight * numCells;
309f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka    }
310f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka
3112801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    public void enableHardwareLayers() {
312a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.enableHardwareLayers();
3132801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    }
3142801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
3152801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    public void setGridSize(int x, int y) {
3162801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        mCountX = x;
3172801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        mCountY = y;
3182801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        mOccupied = new boolean[mCountX][mCountY];
319482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        mTmpOccupied = new boolean[mCountX][mCountY];
32076fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        requestLayout();
3212801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    }
3222801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
32396864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy    private void invalidateBubbleTextView(BubbleTextView icon) {
32496864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        final int padding = icon.getPressedOrFocusedBackgroundPadding();
3254b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        invalidate(icon.getLeft() + getPaddingLeft() - padding,
3264b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                icon.getTop() + getPaddingTop() - padding,
3274b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                icon.getRight() + getPaddingLeft() + padding,
3284b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                icon.getBottom() + getPaddingTop() + padding);
32996864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy    }
33096864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy
331b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    void setOverScrollAmount(float r, boolean left) {
332b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        if (left && mOverScrollForegroundDrawable != mOverScrollLeft) {
333b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen            mOverScrollForegroundDrawable = mOverScrollLeft;
334b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        } else if (!left && mOverScrollForegroundDrawable != mOverScrollRight) {
335b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen            mOverScrollForegroundDrawable = mOverScrollRight;
336b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        }
337b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen
338b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        mForegroundAlpha = (int) Math.round((r * 255));
339b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        mOverScrollForegroundDrawable.setAlpha(mForegroundAlpha);
340b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        invalidate();
341b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    }
342b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen
34396864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy    void setPressedOrFocusedIcon(BubbleTextView icon) {
34496864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        // We draw the pressed or focused BubbleTextView's background in CellLayout because it
34596864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        // requires an expanded clip rect (due to the glow's blur radius)
34696864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        BubbleTextView oldIcon = mPressedOrFocusedIcon;
34796864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        mPressedOrFocusedIcon = icon;
34896864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        if (oldIcon != null) {
34996864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy            invalidateBubbleTextView(oldIcon);
35096864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        }
35196864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        if (mPressedOrFocusedIcon != null) {
35296864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy            invalidateBubbleTextView(mPressedOrFocusedIcon);
35396864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        }
35496864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy    }
35596864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy
35633945b21544bc98381df17726a3537c292d8c985Michael Jurka    void setIsDragOverlapping(boolean isDragOverlapping) {
35733945b21544bc98381df17726a3537c292d8c985Michael Jurka        if (mIsDragOverlapping != isDragOverlapping) {
35833945b21544bc98381df17726a3537c292d8c985Michael Jurka            mIsDragOverlapping = isDragOverlapping;
35933945b21544bc98381df17726a3537c292d8c985Michael Jurka            invalidate();
36033945b21544bc98381df17726a3537c292d8c985Michael Jurka        }
36133945b21544bc98381df17726a3537c292d8c985Michael Jurka    }
36233945b21544bc98381df17726a3537c292d8c985Michael Jurka
36333945b21544bc98381df17726a3537c292d8c985Michael Jurka    boolean getIsDragOverlapping() {
36433945b21544bc98381df17726a3537c292d8c985Michael Jurka        return mIsDragOverlapping;
36533945b21544bc98381df17726a3537c292d8c985Michael Jurka    }
36633945b21544bc98381df17726a3537c292d8c985Michael Jurka
367ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen    protected void setOverscrollTransformsDirty(boolean dirty) {
368ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen        mScrollingTransformsDirty = dirty;
369ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen    }
370ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen
371ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen    protected void resetOverscrollTransforms() {
372ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen        if (mScrollingTransformsDirty) {
373ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            setOverscrollTransformsDirty(false);
374ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            setTranslationX(0);
375ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            setRotationY(0);
376ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            // It doesn't matter if we pass true or false here, the important thing is that we
377ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            // pass 0, which results in the overscroll drawable not being drawn any more.
378ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            setOverScrollAmount(0, false);
379ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            setPivotX(getMeasuredWidth() / 2);
380ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            setPivotY(getMeasuredHeight() / 2);
381ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen        }
382ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen    }
383ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen
384a6abce8464b57ce91e8f083951ad263370fc2da8Romain Guy    @Override
3851262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy    protected void onDraw(Canvas canvas) {
3863e7c7634531302271270c8cf418abc959d621cbcMichael Jurka        // When we're large, we are either drawn in a "hover" state (ie when dragging an item to
3873e7c7634531302271270c8cf418abc959d621cbcMichael Jurka        // a neighboring page) or with just a normal background (if backgroundAlpha > 0.0f)
3883e7c7634531302271270c8cf418abc959d621cbcMichael Jurka        // When we're small, we are either drawn normally or in the "accepts drops" state (during
3893e7c7634531302271270c8cf418abc959d621cbcMichael Jurka        // a drag). However, we also drag the mini hover background *over* one of those two
3903e7c7634531302271270c8cf418abc959d621cbcMichael Jurka        // backgrounds
391b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung        if (mBackgroundAlpha > 0.0f) {
392f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen            Drawable bg;
39333945b21544bc98381df17726a3537c292d8c985Michael Jurka
39433945b21544bc98381df17726a3537c292d8c985Michael Jurka            if (mIsDragOverlapping) {
39533945b21544bc98381df17726a3537c292d8c985Michael Jurka                // In the mini case, we draw the active_glow bg *over* the active background
396bdf78559f223ac11e01e3311edd5a48a80383e1eMichael Jurka                bg = mActiveGlowBackground;
397f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen            } else {
398bdf78559f223ac11e01e3311edd5a48a80383e1eMichael Jurka                bg = mNormalBackground;
399f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen            }
40033945b21544bc98381df17726a3537c292d8c985Michael Jurka
40133945b21544bc98381df17726a3537c292d8c985Michael Jurka            bg.setAlpha((int) (mBackgroundAlpha * mBackgroundAlphaMultiplier * 255));
40233945b21544bc98381df17726a3537c292d8c985Michael Jurka            bg.setBounds(mBackgroundRect);
40333945b21544bc98381df17726a3537c292d8c985Michael Jurka            bg.draw(canvas);
404a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka        }
40531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
406de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy        if (mCrosshairsVisibility > 0.0f) {
407de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy            final int countX = mCountX;
408de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy            final int countY = mCountY;
409de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy
410de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy            final float MAX_ALPHA = 0.4f;
411de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy            final int MAX_VISIBLE_DISTANCE = 600;
412de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy            final float DISTANCE_MULTIPLIER = 0.002f;
413de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy
414de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy            final Drawable d = mCrosshairsDrawable;
415de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy            final int width = d.getIntrinsicWidth();
416de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy            final int height = d.getIntrinsicHeight();
417de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy
4184b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung            int x = getPaddingLeft() - (mWidthGap / 2) - (width / 2);
419de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy            for (int col = 0; col <= countX; col++) {
4204b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                int y = getPaddingTop() - (mHeightGap / 2) - (height / 2);
421de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                for (int row = 0; row <= countY; row++) {
422de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                    mTmpPointF.set(x - mDragCenter.x, y - mDragCenter.y);
423de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                    float dist = mTmpPointF.length();
424de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                    // Crosshairs further from the drag point are more faint
425de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                    float alpha = Math.min(MAX_ALPHA,
426de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                            DISTANCE_MULTIPLIER * (MAX_VISIBLE_DISTANCE - dist));
427de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                    if (alpha > 0.0f) {
428de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                        d.setBounds(x, y, x + width, y + height);
429de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                        d.setAlpha((int) (alpha * 255 * mCrosshairsVisibility));
430de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                        d.draw(canvas);
431de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                    }
432de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                    y += mCellHeight + mHeightGap;
433de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                }
434de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                x += mCellWidth + mWidthGap;
435de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy            }
4364be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        }
437150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung
4388e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy        final Paint paint = mDragOutlinePaint;
4394be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        for (int i = 0; i < mDragOutlines.length; i++) {
440472b281d5cb4f5660df981a6c912266b9f5703feChet Haase            final float alpha = mDragOutlineAlphas[i];
4414be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            if (alpha > 0) {
442d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                final Rect r = mDragOutlines[i];
4434be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                final Bitmap b = (Bitmap) mDragOutlineAnims[i].getTag();
444472b281d5cb4f5660df981a6c912266b9f5703feChet Haase                paint.setAlpha((int)(alpha + .5f));
445d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                canvas.drawBitmap(b, null, r, paint);
446150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung            }
4476569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        }
44896864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy
44996864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        // We draw the pressed or focused BubbleTextView's background in CellLayout because it
45096864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        // requires an expanded clip rect (due to the glow's blur radius)
45196864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        if (mPressedOrFocusedIcon != null) {
45296864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy            final int padding = mPressedOrFocusedIcon.getPressedOrFocusedBackgroundPadding();
45396864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy            final Bitmap b = mPressedOrFocusedIcon.getPressedOrFocusedBackground();
45496864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy            if (b != null) {
45596864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy                canvas.drawBitmap(b,
4564b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                        mPressedOrFocusedIcon.getLeft() + getPaddingLeft() - padding,
4574b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                        mPressedOrFocusedIcon.getTop() + getPaddingTop() - padding,
45896864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy                        null);
45996864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy            }
46096864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        }
46169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
462482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (DEBUG_VISUALIZE_OCCUPIED) {
463482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            int[] pt = new int[2];
464482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            ColorDrawable cd = new ColorDrawable(Color.RED);
465482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            cd.setBounds(0, 0, 80, 80);
466482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            for (int i = 0; i < mCountX; i++) {
467482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                for (int j = 0; j < mCountY; j++) {
468482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    if (mOccupied[i][j]) {
469482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        cellToPoint(i, j, pt);
470482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        canvas.save();
471482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        canvas.translate(pt[0], pt[1]);
472482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        cd.draw(canvas);
473482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        canvas.restore();
474482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    }
475482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                }
476482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
477482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
478482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
47969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        // The folder outer / inner ring image(s)
48069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        for (int i = 0; i < mFolderOuterRings.size(); i++) {
48169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            FolderRingAnimator fra = mFolderOuterRings.get(i);
48269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
48369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            // Draw outer ring
48469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            Drawable d = FolderRingAnimator.sSharedOuterRingDrawable;
48569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            int width = (int) fra.getOuterRingSize();
48669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            int height = width;
48769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            cellToPoint(fra.mCellX, fra.mCellY, mTempLocation);
48869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
48969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            int centerX = mTempLocation[0] + mCellWidth / 2;
49069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            int centerY = mTempLocation[1] + FolderRingAnimator.sPreviewSize / 2;
49169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
49269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            canvas.save();
49369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            canvas.translate(centerX - width / 2, centerY - height / 2);
49469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            d.setBounds(0, 0, width, height);
49569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            d.draw(canvas);
49669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            canvas.restore();
49769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
49869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            // Draw inner ring
49969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            d = FolderRingAnimator.sSharedInnerRingDrawable;
50069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            width = (int) fra.getInnerRingSize();
50169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            height = width;
50269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            cellToPoint(fra.mCellX, fra.mCellY, mTempLocation);
50369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
50469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            centerX = mTempLocation[0] + mCellWidth / 2;
50569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            centerY = mTempLocation[1] + FolderRingAnimator.sPreviewSize / 2;
50669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            canvas.save();
50769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            canvas.translate(centerX - width / 2, centerY - width / 2);
50869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            d.setBounds(0, 0, width, height);
50969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            d.draw(canvas);
51069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            canvas.restore();
51169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        }
512c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen
513c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        if (mFolderLeaveBehindCell[0] >= 0 && mFolderLeaveBehindCell[1] >= 0) {
514c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            Drawable d = FolderIcon.sSharedFolderLeaveBehind;
515c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            int width = d.getIntrinsicWidth();
516c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            int height = d.getIntrinsicHeight();
517c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen
518c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            cellToPoint(mFolderLeaveBehindCell[0], mFolderLeaveBehindCell[1], mTempLocation);
519c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            int centerX = mTempLocation[0] + mCellWidth / 2;
520c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            int centerY = mTempLocation[1] + FolderRingAnimator.sPreviewSize / 2;
521c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen
522c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            canvas.save();
523c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            canvas.translate(centerX - width / 2, centerY - width / 2);
524c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            d.setBounds(0, 0, width, height);
525c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            d.draw(canvas);
526c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            canvas.restore();
527c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        }
52869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen    }
52969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
530b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    @Override
531b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    protected void dispatchDraw(Canvas canvas) {
532b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        super.dispatchDraw(canvas);
533b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        if (mForegroundAlpha > 0) {
534b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen            mOverScrollForegroundDrawable.setBounds(mForegroundRect);
535b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen            Paint p = ((NinePatchDrawable) mOverScrollForegroundDrawable).getPaint();
536b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen            p.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.ADD));
537b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen            mOverScrollForegroundDrawable.draw(canvas);
538b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen            p.setXfermode(null);
539b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        }
540b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    }
541b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen
54269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen    public void showFolderAccept(FolderRingAnimator fra) {
54369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        mFolderOuterRings.add(fra);
54469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen    }
54569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
54669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen    public void hideFolderAccept(FolderRingAnimator fra) {
54769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        if (mFolderOuterRings.contains(fra)) {
54869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            mFolderOuterRings.remove(fra);
54969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        }
55069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        invalidate();
5516569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    }
5526569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
553c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen    public void setFolderLeaveBehindCell(int x, int y) {
554c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        mFolderLeaveBehindCell[0] = x;
555c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        mFolderLeaveBehindCell[1] = y;
556c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        invalidate();
557c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen    }
558c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen
559c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen    public void clearFolderLeaveBehind() {
560c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        mFolderLeaveBehindCell[0] = -1;
561c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        mFolderLeaveBehindCell[1] = -1;
562c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        invalidate();
563c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen    }
564c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen
5656569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    @Override
566e6235dd225404239b55c459245543f3302326112Michael Jurka    public boolean shouldDelayChildPressedState() {
567e6235dd225404239b55c459245543f3302326112Michael Jurka        return false;
568e6235dd225404239b55c459245543f3302326112Michael Jurka    }
569e6235dd225404239b55c459245543f3302326112Michael Jurka
570e6235dd225404239b55c459245543f3302326112Michael Jurka    @Override
57183f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey    public void cancelLongPress() {
57283f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey        super.cancelLongPress();
57383f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey
57483f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey        // Cancel long press for all children
57583f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey        final int count = getChildCount();
57683f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey        for (int i = 0; i < count; i++) {
57783f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey            final View child = getChildAt(i);
57883f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey            child.cancelLongPress();
57983f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey        }
58083f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey    }
58183f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey
582dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    public void setOnInterceptTouchListener(View.OnTouchListener listener) {
583dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka        mInterceptTouchListener = listener;
584dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    }
585dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka
58631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    int getCountX() {
587d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        return mCountX;
58831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
58931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
59031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    int getCountY() {
591d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        return mCountY;
59231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
59331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
5940dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn    public void setIsHotseat(boolean isHotseat) {
5950dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn        mIsHotseat = isHotseat;
5960dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn    }
5970dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn
598eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung    public float getChildrenScale() {
599eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung        return mIsHotseat ? mHotseatChildScale : mChildScale;
600eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung    }
601eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung
602f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka    public boolean addViewToCellLayout(
603f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka            View child, int index, int childId, LayoutParams params, boolean markCells) {
6040dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn        return addViewToCellLayout(child, index, childId, params, markCells, false);
6050dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn    }
6060dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn
607eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung    private void scaleChild(BubbleTextView bubbleChild, float pivot, float scale) {
608bc239a15464f543a41b960b946aa77258454efafAndrew Flynn        // If we haven't measured the child yet, do it now
609bc239a15464f543a41b960b946aa77258454efafAndrew Flynn        // (this happens if we're being dropped from all-apps
610bc239a15464f543a41b960b946aa77258454efafAndrew Flynn        if (bubbleChild.getLayoutParams() instanceof LayoutParams &&
611bc239a15464f543a41b960b946aa77258454efafAndrew Flynn                (bubbleChild.getMeasuredWidth() | bubbleChild.getMeasuredHeight()) == 0) {
612a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            getShortcutsAndWidgets().measureChild(bubbleChild);
613bc239a15464f543a41b960b946aa77258454efafAndrew Flynn        }
614bc239a15464f543a41b960b946aa77258454efafAndrew Flynn        int measuredWidth = bubbleChild.getMeasuredWidth();
615bc239a15464f543a41b960b946aa77258454efafAndrew Flynn        int measuredHeight = bubbleChild.getMeasuredHeight();
616bc239a15464f543a41b960b946aa77258454efafAndrew Flynn
617bc239a15464f543a41b960b946aa77258454efafAndrew Flynn        bubbleChild.setScaleX(scale);
618bc239a15464f543a41b960b946aa77258454efafAndrew Flynn        bubbleChild.setScaleY(scale);
619bc239a15464f543a41b960b946aa77258454efafAndrew Flynn    }
620bc239a15464f543a41b960b946aa77258454efafAndrew Flynn
621bc239a15464f543a41b960b946aa77258454efafAndrew Flynn    private void resetChild(BubbleTextView bubbleChild) {
622bc239a15464f543a41b960b946aa77258454efafAndrew Flynn        bubbleChild.setScaleX(1f);
623bc239a15464f543a41b960b946aa77258454efafAndrew Flynn        bubbleChild.setScaleY(1f);
624bc239a15464f543a41b960b946aa77258454efafAndrew Flynn
625bc239a15464f543a41b960b946aa77258454efafAndrew Flynn        bubbleChild.setTextColor(getResources().getColor(R.color.workspace_icon_text_color));
626bc239a15464f543a41b960b946aa77258454efafAndrew Flynn    }
627bc239a15464f543a41b960b946aa77258454efafAndrew Flynn
6280dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn    public boolean addViewToCellLayout(View child, int index, int childId, LayoutParams params,
6290dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn            boolean markCells, boolean allApps) {
630aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        final LayoutParams lp = params;
631aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
6320dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn        // Hotseat icons - scale down and remove text
6330dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn        // Don't scale the all apps button
6340dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn        // scale percent set to -1 means do not scale
6350dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn        // Only scale BubbleTextViews
6360dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn        if (child instanceof BubbleTextView) {
6370dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn            BubbleTextView bubbleChild = (BubbleTextView) child;
6380dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn
639bc239a15464f543a41b960b946aa77258454efafAndrew Flynn            // Start the child with 100% scale and visible text
640bc239a15464f543a41b960b946aa77258454efafAndrew Flynn            resetChild(bubbleChild);
641bc239a15464f543a41b960b946aa77258454efafAndrew Flynn
642eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung            if (mIsHotseat && !allApps && mHotseatChildScale >= 0) {
643bc239a15464f543a41b960b946aa77258454efafAndrew Flynn                // Scale/make transparent for a hotseat
644eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                scaleChild(bubbleChild, 0f, mHotseatChildScale);
6450dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn
646bc239a15464f543a41b960b946aa77258454efafAndrew Flynn                bubbleChild.setTextColor(getResources().getColor(android.R.color.transparent));
647eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung            } else if (mChildScale >= 0) {
648bc239a15464f543a41b960b946aa77258454efafAndrew Flynn                // Else possibly still scale it if we need to for smaller icons
649eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                scaleChild(bubbleChild, 0f, mChildScale);
6500dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn            }
6510dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn        }
6520dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn
65331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // Generate an id for each view, this assumes we have at most 256x256 cells
65431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // per workspace screen
655d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        if (lp.cellX >= 0 && lp.cellX <= mCountX - 1 && lp.cellY >= 0 && lp.cellY <= mCountY - 1) {
656aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            // If the horizontal or vertical span is set to -1, it is taken to
657aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            // mean that it spans the extent of the CellLayout
658d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen            if (lp.cellHSpan < 0) lp.cellHSpan = mCountX;
659d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen            if (lp.cellVSpan < 0) lp.cellVSpan = mCountY;
660aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
661aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            child.setId(childId);
66231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
663a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            mShortcutsAndWidgets.addView(child, index, lp);
664dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka
665f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka            if (markCells) markCellsAsOccupiedForView(child);
6660280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
667aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            return true;
668aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        }
669aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        return false;
67031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
6713e7c7634531302271270c8cf418abc959d621cbcMichael Jurka
67231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
6730280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public void removeAllViews() {
6740280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        clearOccupiedCells();
675a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.removeAllViews();
6760280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
6770280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
6780280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    @Override
6790280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public void removeAllViewsInLayout() {
680a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        if (mShortcutsAndWidgets.getChildCount() > 0) {
6817cfc2825c3a1029f962d2fc387ae2eaa85b51798Michael Jurka            clearOccupiedCells();
682a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            mShortcutsAndWidgets.removeAllViewsInLayout();
6837cfc2825c3a1029f962d2fc387ae2eaa85b51798Michael Jurka        }
6840280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
6850280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
686f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka    public void removeViewWithoutMarkingCells(View view) {
687a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.removeView(view);
688f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka    }
689f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka
6900280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    @Override
6910280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public void removeView(View view) {
6920280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        markCellsAsUnoccupiedForView(view);
693a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.removeView(view);
6940280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
6950280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
6960280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    @Override
6970280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public void removeViewAt(int index) {
698a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        markCellsAsUnoccupiedForView(mShortcutsAndWidgets.getChildAt(index));
699a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.removeViewAt(index);
7000280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
7010280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
7020280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    @Override
7030280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public void removeViewInLayout(View view) {
7040280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        markCellsAsUnoccupiedForView(view);
705a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.removeViewInLayout(view);
7060280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
7070280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
7080280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    @Override
7090280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public void removeViews(int start, int count) {
7100280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        for (int i = start; i < start + count; i++) {
711a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            markCellsAsUnoccupiedForView(mShortcutsAndWidgets.getChildAt(i));
7120280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        }
713a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.removeViews(start, count);
7140280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
7150280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
7160280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    @Override
7170280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public void removeViewsInLayout(int start, int count) {
7180280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        for (int i = start; i < start + count; i++) {
719a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            markCellsAsUnoccupiedForView(mShortcutsAndWidgets.getChildAt(i));
7200280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        }
721a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.removeViewsInLayout(start, count);
722abded66084680bb31cc7ea403c88f44f79a3c884Michael Jurka    }
723abded66084680bb31cc7ea403c88f44f79a3c884Michael Jurka
72431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
72531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    protected void onAttachedToWindow() {
72631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        super.onAttachedToWindow();
72731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        mCellInfo.screen = ((ViewGroup) getParent()).indexOfChild(this);
72831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
72931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
730af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka    public void setTagToCellInfoForPoint(int touchX, int touchY) {
73131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        final CellInfo cellInfo = mCellInfo;
732eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung        Rect frame = mRect;
733af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka        final int x = touchX + mScrollX;
734af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka        final int y = touchY + mScrollY;
735a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        final int count = mShortcutsAndWidgets.getChildCount();
73631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
737af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka        boolean found = false;
738af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka        for (int i = count - 1; i >= 0; i--) {
739a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            final View child = mShortcutsAndWidgets.getChildAt(i);
740d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
741af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka
7421b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen            if ((child.getVisibility() == VISIBLE || child.getAnimation() != null) &&
7431b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen                    lp.isLockedToGrid) {
744af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                child.getHitRect(frame);
7450be025d64c1f84138fe430a58875886e66aae767Winson Chung
746eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                float scale = child.getScaleX();
747eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                frame = new Rect(child.getLeft(), child.getTop(), child.getRight(),
748eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                        child.getBottom());
7490be025d64c1f84138fe430a58875886e66aae767Winson Chung                // The child hit rect is relative to the CellLayoutChildren parent, so we need to
7500be025d64c1f84138fe430a58875886e66aae767Winson Chung                // offset that by this CellLayout's padding to test an (x,y) point that is relative
7510be025d64c1f84138fe430a58875886e66aae767Winson Chung                // to this view.
7524b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                frame.offset(mPaddingLeft, mPaddingTop);
753eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                frame.inset((int) (frame.width() * (1f - scale) / 2),
754eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                        (int) (frame.height() * (1f - scale) / 2));
7550be025d64c1f84138fe430a58875886e66aae767Winson Chung
756af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                if (frame.contains(x, y)) {
757af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                    cellInfo.cell = child;
758af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                    cellInfo.cellX = lp.cellX;
759af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                    cellInfo.cellY = lp.cellY;
760af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                    cellInfo.spanX = lp.cellHSpan;
761af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                    cellInfo.spanY = lp.cellVSpan;
762af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                    found = true;
763af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                    break;
76431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                }
76531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            }
766af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka        }
767aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
768d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka        mLastDownOnOccupiedCell = found;
769d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka
770af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka        if (!found) {
7710be025d64c1f84138fe430a58875886e66aae767Winson Chung            final int cellXY[] = mTmpXY;
772af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka            pointToCellExact(x, y, cellXY);
77331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
774af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka            cellInfo.cell = null;
775af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka            cellInfo.cellX = cellXY[0];
776af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka            cellInfo.cellY = cellXY[1];
777af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka            cellInfo.spanX = 1;
778af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka            cellInfo.spanY = 1;
779af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka        }
780af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka        setTag(cellInfo);
781af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka    }
78231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
783af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka    @Override
784af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka    public boolean onInterceptTouchEvent(MotionEvent ev) {
785c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        // First we clear the tag to ensure that on every touch down we start with a fresh slate,
786c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        // even in the case where we return early. Not clearing here was causing bugs whereby on
787c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        // long-press we'd end up picking up an item from a previous drag operation.
788c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        final int action = ev.getAction();
789c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen
790c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        if (action == MotionEvent.ACTION_DOWN) {
791c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen            clearTagCellInfo();
792c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        }
793c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen
794dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka        if (mInterceptTouchListener != null && mInterceptTouchListener.onTouch(this, ev)) {
795dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka            return true;
796dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka        }
79731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
798af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka        if (action == MotionEvent.ACTION_DOWN) {
799af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka            setTagToCellInfoForPoint((int) ev.getX(), (int) ev.getY());
80031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
801eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung
80231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        return false;
80331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
80431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
805c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen    private void clearTagCellInfo() {
806c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        final CellInfo cellInfo = mCellInfo;
807c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        cellInfo.cell = null;
808c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        cellInfo.cellX = -1;
809c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        cellInfo.cellY = -1;
810c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        cellInfo.spanX = 0;
811c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        cellInfo.spanY = 0;
812c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        setTag(cellInfo);
813c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen    }
814c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen
81531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public CellInfo getTag() {
8160280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        return (CellInfo) super.getTag();
81731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
81831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
8196569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    /**
820aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     * Given a point, return the cell that strictly encloses that point
82131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param x X coordinate of the point
82231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param y Y coordinate of the point
82331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param result Array of 2 ints to hold the x and y coordinate of the cell
82431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
82531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    void pointToCellExact(int x, int y, int[] result) {
8264b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int hStartPadding = getPaddingLeft();
8274b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int vStartPadding = getPaddingTop();
82831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
82931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        result[0] = (x - hStartPadding) / (mCellWidth + mWidthGap);
83031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        result[1] = (y - vStartPadding) / (mCellHeight + mHeightGap);
83131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
832d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        final int xAxis = mCountX;
833d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        final int yAxis = mCountY;
83431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
83531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        if (result[0] < 0) result[0] = 0;
83631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        if (result[0] >= xAxis) result[0] = xAxis - 1;
83731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        if (result[1] < 0) result[1] = 0;
83831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        if (result[1] >= yAxis) result[1] = yAxis - 1;
83931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
840aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
84131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
84231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * Given a point, return the cell that most closely encloses that point
84331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param x X coordinate of the point
84431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param y Y coordinate of the point
84531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param result Array of 2 ints to hold the x and y coordinate of the cell
84631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
84731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    void pointToCellRounded(int x, int y, int[] result) {
84831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        pointToCellExact(x + (mCellWidth / 2), y + (mCellHeight / 2), result);
84931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
85031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
85131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
85231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * Given a cell coordinate, return the point that represents the upper left corner of that cell
853aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     *
854aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     * @param cellX X coordinate of the cell
85531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param cellY Y coordinate of the cell
856aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     *
85731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param result Array of 2 ints to hold the x and y coordinate of the point
85831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
85931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    void cellToPoint(int cellX, int cellY, int[] result) {
8604b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int hStartPadding = getPaddingLeft();
8614b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int vStartPadding = getPaddingTop();
86231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
86331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        result[0] = hStartPadding + cellX * (mCellWidth + mWidthGap);
86431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        result[1] = vStartPadding + cellY * (mCellHeight + mHeightGap);
86531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
86631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
867e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen    /**
868482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * Given a cell coordinate, return the point that represents the center of the cell
869e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen     *
870e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen     * @param cellX X coordinate of the cell
871e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen     * @param cellY Y coordinate of the cell
872e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen     *
873e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen     * @param result Array of 2 ints to hold the x and y coordinate of the point
874e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen     */
875e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen    void cellToCenterPoint(int cellX, int cellY, int[] result) {
87647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        regionToCenterPoint(cellX, cellY, 1, 1, result);
87747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    }
87847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
87947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    /**
88047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * Given a cell coordinate and span return the point that represents the center of the regio
88147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     *
88247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param cellX X coordinate of the cell
88347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param cellY Y coordinate of the cell
88447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     *
88547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param result Array of 2 ints to hold the x and y coordinate of the point
88647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     */
88747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    void regionToCenterPoint(int cellX, int cellY, int spanX, int spanY, int[] result) {
8884b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int hStartPadding = getPaddingLeft();
8894b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int vStartPadding = getPaddingTop();
890e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen
89147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        result[0] = hStartPadding + cellX * (mCellWidth + mWidthGap) +
89247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                (spanX * mCellWidth + (spanX - 1) * mWidthGap) / 2;
89347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        result[1] = vStartPadding + cellY * (mCellHeight + mHeightGap) +
89447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                (spanY * mCellHeight + (spanY - 1) * mHeightGap) / 2;
895e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen    }
896e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen
897482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public float getDistanceFromCell(float x, float y, int[] cell) {
898482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        cellToCenterPoint(cell[0], cell[1], mTmpPoint);
899482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        float distance = (float) Math.sqrt( Math.pow(x - mTmpPoint[0], 2) +
900482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                Math.pow(y - mTmpPoint[1], 2));
901482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return distance;
902482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
903482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
90484f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy    int getCellWidth() {
90584f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy        return mCellWidth;
90684f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy    }
90784f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy
90884f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy    int getCellHeight() {
90984f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy        return mCellHeight;
91084f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy    }
91184f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy
912d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    int getWidthGap() {
913d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        return mWidthGap;
914d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    }
915d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
916d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    int getHeightGap() {
917d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        return mHeightGap;
918d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    }
919d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
9207f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen    Rect getContentRect(Rect r) {
9217f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        if (r == null) {
9227f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            r = new Rect();
9237f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
9247f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        int left = getPaddingLeft();
9257f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        int top = getPaddingTop();
9264b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        int right = left + getWidth() - mPaddingLeft - mPaddingRight;
9274b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        int bottom = top + getHeight() - mPaddingTop - mPaddingBottom;
9287f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        r.set(left, top, right, bottom);
9297f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        return r;
9307f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen    }
9317f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
93231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
93331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
93431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // TODO: currently ignoring padding
935aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
93631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
937aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
938aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
93931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
94031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int heightSpecSize =  MeasureSpec.getSize(heightMeasureSpec);
941aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
94231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        if (widthSpecMode == MeasureSpec.UNSPECIFIED || heightSpecMode == MeasureSpec.UNSPECIFIED) {
94331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            throw new RuntimeException("CellLayout cannot have UNSPECIFIED dimensions");
94431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
94531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
946d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        int numWidthGaps = mCountX - 1;
947d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        int numHeightGaps = mCountY - 1;
948d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen
949234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen        if (mOriginalWidthGap < 0 || mOriginalHeightGap < 0) {
9504b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung            int hSpace = widthSpecSize - mPaddingLeft - mPaddingRight;
9514b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung            int vSpace = heightSpecSize - mPaddingTop - mPaddingBottom;
9524b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung            int hFreeSpace = hSpace - (mCountX * mOriginalCellWidth);
9534b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung            int vFreeSpace = vSpace - (mCountY * mOriginalCellHeight);
9544b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung            mWidthGap = Math.min(mMaxGap, numWidthGaps > 0 ? (hFreeSpace / numWidthGaps) : 0);
9554b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung            mHeightGap = Math.min(mMaxGap,numHeightGaps > 0 ? (vFreeSpace / numHeightGaps) : 0);
956a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            mShortcutsAndWidgets.setCellDimensions(mCellWidth, mCellHeight, mWidthGap, mHeightGap);
957234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen        } else {
958234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen            mWidthGap = mOriginalWidthGap;
959234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen            mHeightGap = mOriginalHeightGap;
960ece7f5b3b55cab646941123e03589241a61678e2Winson Chung        }
9615f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka
9628c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka        // Initial values correspond to widthSpecMode == MeasureSpec.EXACTLY
9638c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka        int newWidth = widthSpecSize;
9648c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka        int newHeight = heightSpecSize;
9658c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka        if (widthSpecMode == MeasureSpec.AT_MOST) {
9664b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung            newWidth = mPaddingLeft + mPaddingRight + (mCountX * mCellWidth) +
9678c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka                ((mCountX - 1) * mWidthGap);
9684b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung            newHeight = mPaddingTop + mPaddingBottom + (mCountY * mCellHeight) +
9698c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka                ((mCountY - 1) * mHeightGap);
9708c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka            setMeasuredDimension(newWidth, newHeight);
9718c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka        }
97231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
9738c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka        int count = getChildCount();
97431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        for (int i = 0; i < count; i++) {
97531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            View child = getChildAt(i);
9764b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung            int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(newWidth - mPaddingLeft -
9774b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                    mPaddingRight, MeasureSpec.EXACTLY);
9784b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung            int childheightMeasureSpec = MeasureSpec.makeMeasureSpec(newHeight - mPaddingTop -
9794b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                    mPaddingBottom, MeasureSpec.EXACTLY);
98031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            child.measure(childWidthMeasureSpec, childheightMeasureSpec);
98131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
9828c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka        setMeasuredDimension(newWidth, newHeight);
98331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
98431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
98531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
98628750fba6a2d141eb9a1e566718c17236030b815Michael Jurka    protected void onLayout(boolean changed, int l, int t, int r, int b) {
98731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int count = getChildCount();
98831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        for (int i = 0; i < count; i++) {
9898c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka            View child = getChildAt(i);
9904b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung            child.layout(mPaddingLeft, mPaddingTop,
9914b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                    r - l - mPaddingRight, b - t - mPaddingBottom);
99231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
99331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
99431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
99531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
996dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
997dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka        super.onSizeChanged(w, h, oldw, oldh);
99818014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka        mBackgroundRect.set(0, 0, w, h);
999b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        mForegroundRect.set(mForegroundPadding, mForegroundPadding,
1000b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen                w - 2 * mForegroundPadding, h - 2 * mForegroundPadding);
1001dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    }
1002dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka
1003dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    @Override
100431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    protected void setChildrenDrawingCacheEnabled(boolean enabled) {
1005a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.setChildrenDrawingCacheEnabled(enabled);
100631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
100731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
100831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
100931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    protected void setChildrenDrawnWithCacheEnabled(boolean enabled) {
1010a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.setChildrenDrawnWithCacheEnabled(enabled);
101131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
101231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
10135f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka    public float getBackgroundAlpha() {
10145f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka        return mBackgroundAlpha;
1015dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    }
1016dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka
10171b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen    public void setBackgroundAlphaMultiplier(float multiplier) {
10181b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen        mBackgroundAlphaMultiplier = multiplier;
10191b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen    }
10201b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen
1021ddb821981e0919bbd3b4c9a2b6aa1811d6c86bb6Adam Cohen    public float getBackgroundAlphaMultiplier() {
1022ddb821981e0919bbd3b4c9a2b6aa1811d6c86bb6Adam Cohen        return mBackgroundAlphaMultiplier;
1023ddb821981e0919bbd3b4c9a2b6aa1811d6c86bb6Adam Cohen    }
1024ddb821981e0919bbd3b4c9a2b6aa1811d6c86bb6Adam Cohen
10255f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka    public void setBackgroundAlpha(float alpha) {
1026afaa05014e0bf3ed1192f9ddec2af4283bc50248Michael Jurka        if (mBackgroundAlpha != alpha) {
1027afaa05014e0bf3ed1192f9ddec2af4283bc50248Michael Jurka            mBackgroundAlpha = alpha;
1028afaa05014e0bf3ed1192f9ddec2af4283bc50248Michael Jurka            invalidate();
1029afaa05014e0bf3ed1192f9ddec2af4283bc50248Michael Jurka        }
1030dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    }
1031dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka
1032a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka    public void setShortcutAndWidgetAlpha(float alpha) {
10330142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka        final int childCount = getChildCount();
10340142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka        for (int i = 0; i < childCount; i++) {
1035dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka            getChildAt(i).setAlpha(alpha);
1036dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka        }
1037dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    }
1038dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka
1039a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka    public ShortcutAndWidgetContainer getShortcutsAndWidgets() {
1040a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        if (getChildCount() > 0) {
1041a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            return (ShortcutAndWidgetContainer) getChildAt(0);
1042a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        }
1043a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        return null;
1044a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka    }
1045a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka
1046440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy    public View getChildAt(int x, int y) {
1047a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        return mShortcutsAndWidgets.getChildAt(x, y);
1048440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy    }
1049440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy
105076fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    public boolean animateChildToPosition(final View child, int cellX, int cellY, int duration,
1051482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            int delay, boolean permanent, boolean adjustOccupied) {
1052a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        ShortcutAndWidgetContainer clc = getShortcutsAndWidgets();
1053482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        boolean[][] occupied = mOccupied;
1054482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (!permanent) {
1055482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            occupied = mTmpOccupied;
1056482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1057482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1058482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (clc.indexOfChild(child) != -1 && !occupied[cellX][cellY]) {
1059bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
1060bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            final ItemInfo info = (ItemInfo) child.getTag();
1061bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen
1062bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            // We cancel any existing animations
1063bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            if (mReorderAnimators.containsKey(lp)) {
1064bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                mReorderAnimators.get(lp).cancel();
1065bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                mReorderAnimators.remove(lp);
1066bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            }
1067bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen
1068482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            final int oldX = lp.x;
1069482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            final int oldY = lp.y;
1070482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (adjustOccupied) {
1071482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                occupied[lp.cellX][lp.cellY] = false;
1072482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                occupied[cellX][cellY] = true;
1073482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1074bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            lp.isLockedToGrid = true;
1075482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (permanent) {
1076482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                lp.cellX = info.cellX = cellX;
1077482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                lp.cellY = info.cellY = cellY;
1078482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            } else {
1079482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                lp.tmpCellX = cellX;
1080482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                lp.tmpCellY = cellY;
1081482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1082bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            clc.setupLp(lp);
1083bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            lp.isLockedToGrid = false;
1084482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            final int newX = lp.x;
1085482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            final int newY = lp.y;
1086bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen
108776fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen            lp.x = oldX;
108876fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen            lp.y = oldY;
108976fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
1090482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            // Exit early if we're not actually moving the view
1091482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (oldX == newX && oldY == newY) {
1092482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                lp.isLockedToGrid = true;
1093482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                return true;
1094482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1095482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1096482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
1097482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            va.setDuration(duration);
1098482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            mReorderAnimators.put(lp, va);
1099482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1100482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            va.addUpdateListener(new AnimatorUpdateListener() {
1101482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                @Override
1102bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                public void onAnimationUpdate(ValueAnimator animation) {
1103482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    float r = ((Float) animation.getAnimatedValue()).floatValue();
11046b8a02d63a5d9cab8209381993e37db6a6afb753Adam Cohen                    lp.x = (int) (r * newX + (1 - r) * oldX);
11056b8a02d63a5d9cab8209381993e37db6a6afb753Adam Cohen                    lp.y = (int) (r * newY + (1 - r) * oldY);
11066b8a02d63a5d9cab8209381993e37db6a6afb753Adam Cohen                    child.requestLayout();
1107bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                }
1108bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            });
1109482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            va.addListener(new AnimatorListenerAdapter() {
1110bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                boolean cancelled = false;
1111bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                public void onAnimationEnd(Animator animation) {
1112bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    // If the animation was cancelled, it means that another animation
1113bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    // has interrupted this one, and we don't want to lock the item into
1114bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    // place just yet.
1115bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    if (!cancelled) {
1116bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                        lp.isLockedToGrid = true;
1117482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        child.requestLayout();
1118bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    }
1119bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    if (mReorderAnimators.containsKey(lp)) {
1120bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                        mReorderAnimators.remove(lp);
1121bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    }
1122bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                }
1123bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                public void onAnimationCancel(Animator animation) {
1124bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    cancelled = true;
1125bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                }
1126bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            });
1127482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            va.setStartDelay(delay);
1128482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            va.start();
1129bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            return true;
1130bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        }
1131bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        return false;
1132bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    }
1133bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen
11346569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    /**
11356569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     * Estimate where the top left cell of the dragged item will land if it is dropped.
11366569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     *
11376569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     * @param originX The X value of the top left corner of the item
11386569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     * @param originY The Y value of the top left corner of the item
11396569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     * @param spanX The number of horizontal cells that the item spans
11406569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     * @param spanY The number of vertical cells that the item spans
11416569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     * @param result The estimated drop cell X and Y.
11426569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     */
11436569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    void estimateDropCell(int originX, int originY, int spanX, int spanY, int[] result) {
1144d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        final int countX = mCountX;
1145d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        final int countY = mCountY;
11466569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
1147a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka        // pointToCellRounded takes the top left of a cell but will pad that with
1148a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka        // cellWidth/2 and cellHeight/2 when finding the matching cell
1149a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka        pointToCellRounded(originX, originY, result);
11506569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
11516569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        // If the item isn't fully on this screen, snap to the edges
11526569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        int rightOverhang = result[0] + spanX - countX;
11536569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        if (rightOverhang > 0) {
11546569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy            result[0] -= rightOverhang; // Snap to right
11556569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        }
11566569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        result[0] = Math.max(0, result[0]); // Snap to left
11576569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        int bottomOverhang = result[1] + spanY - countY;
11586569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        if (bottomOverhang > 0) {
11596569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy            result[1] -= bottomOverhang; // Snap to bottom
11606569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        }
11616569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        result[1] = Math.max(0, result[1]); // Snap to top
11626569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    }
11636569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
1164482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    void visualizeDropLocation(View v, Bitmap dragOutline, int originX, int originY, int cellX,
1165482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            int cellY, int spanX, int spanY, boolean resize, Point dragOffset, Rect dragRegion) {
116608ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy        final int oldDragCellX = mDragCell[0];
116708ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy        final int oldDragCellY = mDragCell[1];
1168482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1169b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung        if (v != null && dragOffset == null) {
1170a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung            mDragCenter.set(originX + (v.getWidth() / 2), originY + (v.getHeight() / 2));
1171a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung        } else {
1172a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung            mDragCenter.set(originX, originY);
1173a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung        }
11746569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
11752801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        if (dragOutline == null && v == null) {
11762801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            if (mCrosshairsDrawable != null) {
11772801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen                invalidate();
11782801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            }
11792801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            return;
11802801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        }
11812801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
1182482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (cellX != oldDragCellX || cellY != oldDragCellY) {
1183482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            mDragCell[0] = cellX;
1184482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            mDragCell[1] = cellY;
11856569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy            // Find the top left corner of the rect the object will occupy
1186de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy            final int[] topLeft = mTmpPoint;
1187482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            cellToPoint(cellX, cellY, topLeft);
1188de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy
11894be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            int left = topLeft[0];
11904be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            int top = topLeft[1];
11916569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
1192b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung            if (v != null && dragOffset == null) {
119399e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                // When drawing the drag outline, it did not account for margin offsets
119499e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                // added by the view's parent.
119599e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                MarginLayoutParams lp = (MarginLayoutParams) v.getLayoutParams();
119699e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                left += lp.leftMargin;
119799e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                top += lp.topMargin;
119899e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen
119999e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                // Offsets due to the size difference between the View and the dragOutline.
120099e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                // There is a size difference to account for the outer blur, which may lie
120199e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                // outside the bounds of the view.
1202a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung                top += (v.getHeight() - dragOutline.getHeight()) / 2;
1203ae915cecd36af4973061a1cb0b58c5be1be699a0Adam Cohen                // We center about the x axis
1204ae915cecd36af4973061a1cb0b58c5be1be699a0Adam Cohen                left += ((mCellWidth * spanX) + ((spanX - 1) * mWidthGap)
1205ae915cecd36af4973061a1cb0b58c5be1be699a0Adam Cohen                        - dragOutline.getWidth()) / 2;
12066639687cd67bab1aeef2a75e5c6bc458b20dc082Adam Cohen            } else {
1207b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                if (dragOffset != null && dragRegion != null) {
1208b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                    // Center the drag region *horizontally* in the cell and apply a drag
1209b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                    // outline offset
1210b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                    left += dragOffset.x + ((mCellWidth * spanX) + ((spanX - 1) * mWidthGap)
1211b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                             - dragRegion.width()) / 2;
1212b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                    top += dragOffset.y;
1213b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                } else {
1214b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                    // Center the drag outline in the cell
1215b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                    left += ((mCellWidth * spanX) + ((spanX - 1) * mWidthGap)
1216b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                            - dragOutline.getWidth()) / 2;
1217b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                    top += ((mCellHeight * spanY) + ((spanY - 1) * mHeightGap)
1218b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                            - dragOutline.getHeight()) / 2;
1219b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                }
1220a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung            }
12214be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            final int oldIndex = mDragOutlineCurrent;
122208ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy            mDragOutlineAnims[oldIndex].animateOut();
122308ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy            mDragOutlineCurrent = (oldIndex + 1) % mDragOutlines.length;
1224d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            Rect r = mDragOutlines[mDragOutlineCurrent];
1225d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            r.set(left, top, left + dragOutline.getWidth(), top + dragOutline.getHeight());
1226d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            if (resize) {
1227482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                cellToRect(cellX, cellY, spanX, spanY, r);
1228d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            }
1229150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung
123008ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy            mDragOutlineAnims[mDragOutlineCurrent].setTag(dragOutline);
123108ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy            mDragOutlineAnims[mDragOutlineCurrent].animateIn();
12326569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        }
123349250ad530385fcdd6072ca54697f670ec503b59Patrick Dubroy
123449250ad530385fcdd6072ca54697f670ec503b59Patrick Dubroy        // If we are drawing crosshairs, the entire CellLayout needs to be invalidated
123549250ad530385fcdd6072ca54697f670ec503b59Patrick Dubroy        if (mCrosshairsDrawable != null) {
123649250ad530385fcdd6072ca54697f670ec503b59Patrick Dubroy            invalidate();
123749250ad530385fcdd6072ca54697f670ec503b59Patrick Dubroy        }
12386569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    }
12396569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
1240e0310965022e7a1adb7ad489505d404186608689Adam Cohen    public void clearDragOutlines() {
1241e0310965022e7a1adb7ad489505d404186608689Adam Cohen        final int oldIndex = mDragOutlineCurrent;
1242e0310965022e7a1adb7ad489505d404186608689Adam Cohen        mDragOutlineAnims[oldIndex].animateOut();
1243d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        mDragCell[0] = mDragCell[1] = -1;
1244e0310965022e7a1adb7ad489505d404186608689Adam Cohen    }
1245e0310965022e7a1adb7ad489505d404186608689Adam Cohen
124631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
124770864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey     * Find a vacant area that will fit the given bounds nearest the requested
124870864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey     * cell location. Uses Euclidean distance to score multiple vacant areas.
1249aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     *
125051afc022fa76c79f0d1ece470ddc126c08fea8a4Romain Guy     * @param pixelX The X location at which you want to search for a vacant area.
125151afc022fa76c79f0d1ece470ddc126c08fea8a4Romain Guy     * @param pixelY The Y location at which you want to search for a vacant area.
125270864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey     * @param spanX Horizontal span of the object.
125370864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey     * @param spanY Vertical span of the object.
1254de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy     * @param result Array in which to place the result, or null (in which case a new array will
1255de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy     *        be allocated)
125670864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey     * @return The X, Y cell of a vacant area that can contain this object,
125770864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey     *         nearest the requested location.
125831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
1259d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    int[] findNearestVacantArea(int pixelX, int pixelY, int spanX, int spanY,
1260d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            int[] result) {
1261de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy        return findNearestVacantArea(pixelX, pixelY, spanX, spanY, null, result);
12626a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka    }
1263aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
12646a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka    /**
12656a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     * Find a vacant area that will fit the given bounds nearest the requested
12666a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     * cell location. Uses Euclidean distance to score multiple vacant areas.
12676a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     *
12686a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     * @param pixelX The X location at which you want to search for a vacant area.
12696a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     * @param pixelY The Y location at which you want to search for a vacant area.
1270d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param minSpanX The minimum horizontal span required
1271d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param minSpanY The minimum vertical span required
1272d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param spanX Horizontal span of the object.
1273d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param spanY Vertical span of the object.
1274d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param result Array in which to place the result, or null (in which case a new array will
1275d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *        be allocated)
1276d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @return The X, Y cell of a vacant area that can contain this object,
1277d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *         nearest the requested location.
1278d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     */
1279d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    int[] findNearestVacantArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX,
1280d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            int spanY, int[] result, int[] resultSpan) {
1281d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        return findNearestVacantArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, null,
1282d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                result, resultSpan);
1283d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    }
1284d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen
1285d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    /**
1286d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * Find a vacant area that will fit the given bounds nearest the requested
1287d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * cell location. Uses Euclidean distance to score multiple vacant areas.
1288d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *
1289d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param pixelX The X location at which you want to search for a vacant area.
1290d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param pixelY The Y location at which you want to search for a vacant area.
12916a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     * @param spanX Horizontal span of the object.
12926a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     * @param spanY Vertical span of the object.
1293df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param ignoreOccupied If true, the result can be an occupied cell
1294df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param result Array in which to place the result, or null (in which case a new array will
1295df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     *        be allocated)
12966a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     * @return The X, Y cell of a vacant area that can contain this object,
12976a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     *         nearest the requested location.
12986a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     */
1299df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    int[] findNearestArea(int pixelX, int pixelY, int spanX, int spanY, View ignoreView,
1300df0353815c629fc678824b07a234b89a1ff94208Adam Cohen            boolean ignoreOccupied, int[] result) {
1301d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        return findNearestArea(pixelX, pixelY, spanX, spanY,
1302482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                spanX, spanY, ignoreView, ignoreOccupied, result, null, mOccupied);
1303d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    }
1304d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen
1305d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    private final Stack<Rect> mTempRectStack = new Stack<Rect>();
1306d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    private void lazyInitTempRectStack() {
1307d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        if (mTempRectStack.isEmpty()) {
1308d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            for (int i = 0; i < mCountX * mCountY; i++) {
1309d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                mTempRectStack.push(new Rect());
1310d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            }
1311d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        }
1312d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    }
1313482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1314d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    private void recycleTempRects(Stack<Rect> used) {
1315d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        while (!used.isEmpty()) {
1316d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            mTempRectStack.push(used.pop());
1317d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        }
1318d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    }
1319d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen
1320d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    /**
1321d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * Find a vacant area that will fit the given bounds nearest the requested
1322d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * cell location. Uses Euclidean distance to score multiple vacant areas.
1323d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *
1324d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param pixelX The X location at which you want to search for a vacant area.
1325d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param pixelY The Y location at which you want to search for a vacant area.
1326d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param minSpanX The minimum horizontal span required
1327d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param minSpanY The minimum vertical span required
1328d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param spanX Horizontal span of the object.
1329d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param spanY Vertical span of the object.
1330d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param ignoreOccupied If true, the result can be an occupied cell
1331d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param result Array in which to place the result, or null (in which case a new array will
1332d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *        be allocated)
1333d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @return The X, Y cell of a vacant area that can contain this object,
1334d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *         nearest the requested location.
1335d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     */
1336d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    int[] findNearestArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, int spanY,
1337482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            View ignoreView, boolean ignoreOccupied, int[] result, int[] resultSpan,
1338482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            boolean[][] occupied) {
1339d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        lazyInitTempRectStack();
1340c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka        // mark space take by ignoreView as available (method checks if ignoreView is null)
1341482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsAsUnoccupiedForView(ignoreView, occupied);
1342c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka
1343e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        // For items with a spanX / spanY > 1, the passed in point (pixelX, pixelY) corresponds
1344e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        // to the center of the item, but we are searching based on the top-left cell, so
1345e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        // we translate the point over to correspond to the top-left.
1346e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        pixelX -= (mCellWidth + mWidthGap) * (spanX - 1) / 2f;
1347e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        pixelY -= (mCellHeight + mHeightGap) * (spanY - 1) / 2f;
1348e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen
134970864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey        // Keep track of best-scoring drop area
1350de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy        final int[] bestXY = result != null ? result : new int[2];
135170864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey        double bestDistance = Double.MAX_VALUE;
1352d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        final Rect bestRect = new Rect(-1, -1, -1, -1);
1353d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        final Stack<Rect> validRegions = new Stack<Rect>();
1354aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
1355de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy        final int countX = mCountX;
1356de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy        final int countY = mCountY;
1357de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy
1358d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        if (minSpanX <= 0 || minSpanY <= 0 || spanX <= 0 || spanY <= 0 ||
1359d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                spanX < minSpanX || spanY < minSpanY) {
1360d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            return bestXY;
1361d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        }
1362d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen
1363d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        for (int y = 0; y < countY - (minSpanY - 1); y++) {
1364c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka            inner:
1365d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            for (int x = 0; x < countX - (minSpanX - 1); x++) {
1366d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                int ySize = -1;
1367d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                int xSize = -1;
1368df0353815c629fc678824b07a234b89a1ff94208Adam Cohen                if (ignoreOccupied) {
1369d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    // First, let's see if this thing fits anywhere
1370d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    for (int i = 0; i < minSpanX; i++) {
1371d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        for (int j = 0; j < minSpanY; j++) {
1372df0353815c629fc678824b07a234b89a1ff94208Adam Cohen                            if (occupied[x + i][y + j]) {
1373df0353815c629fc678824b07a234b89a1ff94208Adam Cohen                                continue inner;
1374df0353815c629fc678824b07a234b89a1ff94208Adam Cohen                            }
1375c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                        }
1376c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                    }
1377d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    xSize = minSpanX;
1378d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    ySize = minSpanY;
1379d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen
1380d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    // We know that the item will fit at _some_ acceptable size, now let's see
1381d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    // how big we can make it. We'll alternate between incrementing x and y spans
1382d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    // until we hit a limit.
1383d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    boolean incX = true;
1384d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    boolean hitMaxX = xSize >= spanX;
1385d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    boolean hitMaxY = ySize >= spanY;
1386d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    while (!(hitMaxX && hitMaxY)) {
1387d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        if (incX && !hitMaxX) {
1388d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            for (int j = 0; j < ySize; j++) {
1389d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                if (x + xSize > countX -1 || occupied[x + xSize][y + j]) {
1390d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                    // We can't move out horizontally
1391d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                    hitMaxX = true;
1392d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                }
1393d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            }
1394d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            if (!hitMaxX) {
1395d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                xSize++;
1396d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            }
1397d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        } else if (!hitMaxY) {
1398d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            for (int i = 0; i < xSize; i++) {
1399d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                if (y + ySize > countY - 1 || occupied[x + i][y + ySize]) {
1400d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                    // We can't move out vertically
1401d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                    hitMaxY = true;
1402d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                }
1403d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            }
1404d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            if (!hitMaxY) {
1405d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                ySize++;
1406d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            }
1407d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        }
1408d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        hitMaxX |= xSize >= spanX;
1409d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        hitMaxY |= ySize >= spanY;
1410d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        incX = !incX;
1411d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    }
1412d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    incX = true;
1413d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    hitMaxX = xSize >= spanX;
1414d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    hitMaxY = ySize >= spanY;
1415c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                }
14160be025d64c1f84138fe430a58875886e66aae767Winson Chung                final int[] cellXY = mTmpXY;
1417e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen                cellToCenterPoint(x, y, cellXY);
1418c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka
1419d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                // We verify that the current rect is not a sub-rect of any of our previous
1420d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                // candidates. In this case, the current rect is disqualified in favour of the
1421d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                // containing rect.
1422d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                Rect currentRect = mTempRectStack.pop();
1423d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                currentRect.set(x, y, x + xSize, y + ySize);
1424d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                boolean contained = false;
1425d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                for (Rect r : validRegions) {
1426d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    if (r.contains(currentRect)) {
1427d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        contained = true;
1428d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        break;
1429d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    }
1430d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                }
1431d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                validRegions.push(currentRect);
1432c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                double distance = Math.sqrt(Math.pow(cellXY[0] - pixelX, 2)
1433c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                        + Math.pow(cellXY[1] - pixelY, 2));
1434482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1435d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                if ((distance <= bestDistance && !contained) ||
1436d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        currentRect.contains(bestRect)) {
1437c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                    bestDistance = distance;
1438c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                    bestXY[0] = x;
1439c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                    bestXY[1] = y;
1440d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    if (resultSpan != null) {
1441d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        resultSpan[0] = xSize;
1442d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        resultSpan[1] = ySize;
1443d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    }
1444d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    bestRect.set(currentRect);
1445c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                }
144631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            }
144731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
1448c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka        // re-mark space taken by ignoreView as occupied
1449482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsAsOccupiedForView(ignoreView, occupied);
145031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
1451c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        // Return -1, -1 if no suitable location found
1452c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        if (bestDistance == Double.MAX_VALUE) {
1453c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            bestXY[0] = -1;
1454c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            bestXY[1] = -1;
145570864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey        }
1456d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        recycleTempRects(validRegions);
1457c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        return bestXY;
145831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
1459aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
1460482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     /**
1461482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * Find a vacant area that will fit the given bounds nearest the requested
1462482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * cell location, and will also weigh in a suggested direction vector of the
1463482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * desired location. This method computers distance based on unit grid distances,
1464482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * not pixel distances.
1465482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     *
146647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param cellX The X cell nearest to which you want to search for a vacant area.
146747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param cellY The Y cell nearest which you want to search for a vacant area.
1468482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * @param spanX Horizontal span of the object.
1469482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * @param spanY Vertical span of the object.
147047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param direction The favored direction in which the views should move from x, y
147147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param exactDirectionOnly If this parameter is true, then only solutions where the direction
147247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     *        matches exactly. Otherwise we find the best matching direction.
147347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param occoupied The array which represents which cells in the CellLayout are occupied
147447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param blockOccupied The array which represents which cells in the specified block (cellX,
147547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     *        cellY, spanX, spanY) are occupied. This is used when try to move a group of views.
1476482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * @param result Array in which to place the result, or null (in which case a new array will
1477482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     *        be allocated)
1478482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * @return The X, Y cell of a vacant area that can contain this object,
1479482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     *         nearest the requested location.
1480482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     */
1481482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private int[] findNearestArea(int cellX, int cellY, int spanX, int spanY, int[] direction,
148247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            boolean[][] occupied, boolean blockOccupied[][], int[] result) {
1483482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // Keep track of best-scoring drop area
1484482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        final int[] bestXY = result != null ? result : new int[2];
1485482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        float bestDistance = Float.MAX_VALUE;
1486482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        int bestDirectionScore = Integer.MIN_VALUE;
1487482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1488482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        final int countX = mCountX;
1489482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        final int countY = mCountY;
1490482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1491482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int y = 0; y < countY - (spanY - 1); y++) {
1492482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            inner:
1493482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            for (int x = 0; x < countX - (spanX - 1); x++) {
1494482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                // First, let's see if this thing fits anywhere
1495482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                for (int i = 0; i < spanX; i++) {
1496482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    for (int j = 0; j < spanY; j++) {
149747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        if (occupied[x + i][y + j] && (blockOccupied == null || blockOccupied[i][j])) {
1498482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                            continue inner;
1499482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        }
1500482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    }
1501482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                }
1502482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1503482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                float distance = (float)
1504482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        Math.sqrt((x - cellX) * (x - cellX) + (y - cellY) * (y - cellY));
1505482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                int[] curDirection = mTmpPoint;
150647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                computeDirectionVector(x - cellX, y - cellY, curDirection);
150747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                // The direction score is just the dot product of the two candidate direction
150847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                // and that passed in.
1509482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                int curDirectionScore = direction[0] * curDirection[0] +
1510482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        direction[1] * curDirection[1];
151147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                boolean exactDirectionOnly = false;
151247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                boolean directionMatches = direction[0] == curDirection[0] &&
151347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        direction[0] == curDirection[0];
151447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                if ((directionMatches || !exactDirectionOnly) &&
151547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        Float.compare(distance,  bestDistance) < 0 || (Float.compare(distance,
1516482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        bestDistance) == 0 && curDirectionScore > bestDirectionScore)) {
1517482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    bestDistance = distance;
1518482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    bestDirectionScore = curDirectionScore;
1519482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    bestXY[0] = x;
1520482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    bestXY[1] = y;
1521482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                }
1522482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1523482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1524482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1525482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // Return -1, -1 if no suitable location found
1526482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (bestDistance == Float.MAX_VALUE) {
1527482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            bestXY[0] = -1;
1528482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            bestXY[1] = -1;
1529482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1530482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return bestXY;
1531482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1532482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
153347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    private int[] findNearestAreaInDirection(int cellX, int cellY, int spanX, int spanY,
153447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            int[] direction,boolean[][] occupied,
153547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            boolean blockOccupied[][], int[] result) {
153647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        // Keep track of best-scoring drop area
153747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        final int[] bestXY = result != null ? result : new int[2];
153847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        bestXY[0] = -1;
153947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        bestXY[1] = -1;
154047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        float bestDistance = Float.MAX_VALUE;
154147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
154247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        // We use this to march in a single direction
154347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        if (direction[0] != 0 && direction[1] != 0) {
154447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            return bestXY;
154547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
154647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
154747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        // This will only incrememnet one of x or y based on the assertion above
154847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        int x = cellX + direction[0];
154947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        int y = cellY + direction[1];
155047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        while (x >= 0 && x + spanX <= mCountX && y >= 0 && y + spanY <= mCountY) {
155147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
155247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            boolean fail = false;
155347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            for (int i = 0; i < spanX; i++) {
155447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                for (int j = 0; j < spanY; j++) {
155547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    if (occupied[x + i][y + j] && (blockOccupied == null || blockOccupied[i][j])) {
155647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        fail = true;
155747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    }
155847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                }
155947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            }
156047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            if (!fail) {
156147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                float distance = (float)
156247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        Math.sqrt((x - cellX) * (x - cellX) + (y - cellY) * (y - cellY));
156347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                if (Float.compare(distance,  bestDistance) < 0) {
156447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    bestDistance = distance;
156547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    bestXY[0] = x;
156647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    bestXY[1] = y;
156747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                }
156847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            }
156947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            x += direction[0];
157047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            y += direction[1];
157147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
157247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        return bestXY;
157347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    }
157447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
1575482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private boolean addViewToTempLocation(View v, Rect rectOccupiedByPotentialDrop,
15768baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            int[] direction, ItemConfiguration currentState) {
15778baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        CellAndSpan c = currentState.map.get(v);
1578482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        boolean success = false;
15798baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, false);
1580482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsForRect(rectOccupiedByPotentialDrop, mTmpOccupied, true);
1581482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
15828baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        findNearestArea(c.x, c.y, c.spanX, c.spanY, direction, mTmpOccupied, null, mTempLocation);
1583482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1584482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (mTempLocation[0] >= 0 && mTempLocation[1] >= 0) {
15858baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            c.x = mTempLocation[0];
15868baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            c.y = mTempLocation[1];
1587482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            success = true;
1588482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1589482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
15908baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, true);
1591482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return success;
1592482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1593482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
159447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    // This method looks in the specified direction to see if there is an additional view
159547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    // immediately adjecent in that direction
159647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    private boolean addViewInDirection(ArrayList<View> views, Rect boundingRect, int[] direction,
15978baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            boolean[][] occupied, ItemConfiguration currentState) {
159847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        boolean found = false;
159947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
1600a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        int childCount = mShortcutsAndWidgets.getChildCount();
160147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        Rect r0 = new Rect(boundingRect);
160247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        Rect r1 = new Rect();
160347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
160447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        int deltaX = 0;
160547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        int deltaY = 0;
160647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        if (direction[1] < 0) {
160747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            r0.set(r0.left, r0.top - 1, r0.right, r0.bottom);
160847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            deltaY = -1;
160947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        } else if (direction[1] > 0) {
161047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            r0.set(r0.left, r0.top, r0.right, r0.bottom + 1);
161147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            deltaY = 1;
161247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        } else if (direction[0] < 0) {
161347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            r0.set(r0.left - 1, r0.top, r0.right, r0.bottom);
161447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            deltaX = -1;
161547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        } else if (direction[0] > 0) {
161647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            r0.set(r0.left, r0.top, r0.right + 1, r0.bottom);
161747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            deltaX = 1;
161847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
161947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
162047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        for (int i = 0; i < childCount; i++) {
1621a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            View child = mShortcutsAndWidgets.getChildAt(i);
162247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            if (views.contains(child)) continue;
16238baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = currentState.map.get(child);
162447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
16258baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
16268baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            r1.set(c.x, c.y, c.x + c.spanX, c.y + c.spanY);
162747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            if (Rect.intersects(r0, r1)) {
162847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                if (!lp.canReorder) {
162947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    return false;
163047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                }
163147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                boolean pushed = false;
16328baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                for (int x = c.x; x < c.x + c.spanX; x++) {
16338baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                    for (int y = c.y; y < c.y + c.spanY; y++) {
163447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        boolean inBounds = x - deltaX >= 0 && x -deltaX < mCountX
163547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                                && y - deltaY >= 0 && y - deltaY < mCountY;
163647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        if (inBounds && occupied[x - deltaX][y - deltaY]) {
163747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                            pushed = true;
163847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        }
163947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    }
164047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                }
164147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                if (pushed) {
164247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    views.add(child);
16438baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                    boundingRect.union(c.x, c.y, c.x + c.spanX, c.y + c.spanY);
164447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    found = true;
164547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                }
164647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            }
164747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
164847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        return found;
164947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    }
165047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
16518baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen    private boolean addViewsToTempLocation(ArrayList<View> views, Rect rectOccupiedByPotentialDrop,
16528baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            int[] direction, boolean push, ItemConfiguration currentState) {
165347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        if (views.size() == 0) return true;
165447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
165547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        boolean success = false;
165647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        Rect boundingRect = null;
16578baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // We construct a rect which represents the entire group of views passed in
165847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        for (View v: views) {
16598baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = currentState.map.get(v);
166047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            if (boundingRect == null) {
16618baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                boundingRect = new Rect(c.x, c.y, c.x + c.spanX, c.y + c.spanY);
166247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            } else {
16638baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                boundingRect.union(c.x, c.y, c.x + c.spanX, c.y + c.spanY);
166447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            }
166547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
166647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
16678baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        @SuppressWarnings("unchecked")
166847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        ArrayList<View> dup = (ArrayList<View>) views.clone();
16698baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // We try and expand the group of views in the direction vector passed, based on
16708baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // whether they are physically adjacent, ie. based on "push mechanics".
16718baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        while (push && addViewInDirection(dup, boundingRect, direction, mTmpOccupied,
16728baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                currentState)) {
167347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
16748baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen
16758baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // Mark the occupied state as false for the group of views we want to move.
167647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        for (View v: dup) {
16778baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = currentState.map.get(v);
16788baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, false);
167947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
168047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
168147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        boolean[][] blockOccupied = new boolean[boundingRect.width()][boundingRect.height()];
168247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        int top = boundingRect.top;
168347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        int left = boundingRect.left;
16848baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // We mark more precisely which parts of the bounding rect are truly occupied, allowing
16858baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // for tetris-style interlocking.
168647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        for (View v: dup) {
16878baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = currentState.map.get(v);
16888baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            markCellsForView(c.x - left, c.y - top, c.spanX, c.spanY, blockOccupied, true);
168947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
169047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
169147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        markCellsForRect(rectOccupiedByPotentialDrop, mTmpOccupied, true);
169247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
16938baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        if (push) {
16948baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            findNearestAreaInDirection(boundingRect.left, boundingRect.top, boundingRect.width(),
16958baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                    boundingRect.height(), direction, mTmpOccupied, blockOccupied, mTempLocation);
16968baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        } else {
16978baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            findNearestArea(boundingRect.left, boundingRect.top, boundingRect.width(),
16988baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                    boundingRect.height(), direction, mTmpOccupied, blockOccupied, mTempLocation);
16998baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        }
170047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
17018baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // If we successfuly found a location by pushing the block of views, we commit it
170247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        if (mTempLocation[0] >= 0 && mTempLocation[1] >= 0) {
17038baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            int deltaX = mTempLocation[0] - boundingRect.left;
17048baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            int deltaY = mTempLocation[1] - boundingRect.top;
170547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            for (View v: dup) {
17068baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                CellAndSpan c = currentState.map.get(v);
17078baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                c.x += deltaX;
17088baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                c.y += deltaY;
170947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            }
171047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            success = true;
171147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
1712482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
17138baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // In either case, we set the occupied array as marked for the location of the views
17148baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        for (View v: dup) {
17158baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = currentState.map.get(v);
17168baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, true);
1717482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1718482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return success;
1719482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1720482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1721482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private void markCellsForRect(Rect r, boolean[][] occupied, boolean value) {
1722482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsForView(r.left, r.top, r.width(), r.height(), occupied, value);
1723482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1724482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1725482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private boolean rearrangementExists(int cellX, int cellY, int spanX, int spanY, int[] direction,
17268baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            View ignoreView, ItemConfiguration solution) {
1727482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
17288baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        mIntersectingViews.clear();
1729482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        mOccupiedRect.set(cellX, cellY, cellX + spanX, cellY + spanY);
1730482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
17318baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // Mark the desired location of the view currently being dragged.
1732482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (ignoreView != null) {
17338baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = solution.map.get(ignoreView);
17348baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            c.x = cellX;
17358baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            c.y = cellY;
1736482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1737482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
17388baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        //int childCount = mChildren.getChildCount();
1739482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        Rect r0 = new Rect(cellX, cellY, cellX + spanX, cellY + spanY);
1740482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        Rect r1 = new Rect();
17418baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        for (View child: solution.map.keySet()) {
1742482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (child == ignoreView) continue;
17438baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = solution.map.get(child);
1744482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
17458baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            r1.set(c.x, c.y, c.x + c.spanX, c.y + c.spanY);
1746482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (Rect.intersects(r0, r1)) {
1747482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                if (!lp.canReorder) {
1748482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    return false;
1749482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                }
1750482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                mIntersectingViews.add(child);
1751482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1752482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
175347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
17548baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // We try to move the intersecting views as a block using the push mechanic
17558baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        if (addViewsToTempLocation(mIntersectingViews, mOccupiedRect, direction, true, solution)) {
175647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            return true;
175747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
175847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        // Try the opposite direction
175947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        direction[0] *= -1;
176047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        direction[1] *= -1;
17618baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        if (addViewsToTempLocation(mIntersectingViews, mOccupiedRect, direction, true, solution)) {
176247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            return true;
176347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
176447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        // Switch the direction back
176547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        direction[0] *= -1;
176647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        direction[1] *= -1;
176747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
17688baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // Next we try moving the views as a block , but without requiring the push mechanic
17698baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        if (addViewsToTempLocation(mIntersectingViews, mOccupiedRect, direction, false, solution)) {
1770482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            return true;
1771482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
177247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
1773482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // Ok, they couldn't move as a block, let's move them individually
1774482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (View v : mIntersectingViews) {
17758baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            if (!addViewToTempLocation(v, mOccupiedRect, direction, solution)) {
1776482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                return false;
1777482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1778482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1779482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return true;
1780482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1781482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1782482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    /*
1783482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * Returns a pair (x, y), where x,y are in {-1, 0, 1} corresponding to vector between
1784482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * the provided point and the provided cell
1785482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     */
178647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    private void computeDirectionVector(float deltaX, float deltaY, int[] result) {
1787482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        double angle = Math.atan(((float) deltaY) / deltaX);
1788482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1789482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        result[0] = 0;
1790482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        result[1] = 0;
1791482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (Math.abs(Math.cos(angle)) > 0.5f) {
1792482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            result[0] = (int) Math.signum(deltaX);
1793482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1794482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (Math.abs(Math.sin(angle)) > 0.5f) {
1795482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            result[1] = (int) Math.signum(deltaY);
1796482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1797482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1798482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
17998baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen    private void copyOccupiedArray(boolean[][] occupied) {
18008baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        for (int i = 0; i < mCountX; i++) {
18018baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            for (int j = 0; j < mCountY; j++) {
18028baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                occupied[i][j] = mOccupied[i][j];
18038baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            }
18048baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        }
18058baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen    }
18068baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen
1807482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    ItemConfiguration simpleSwap(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX,
1808482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            int spanY, int[] direction, View dragView, boolean decX, ItemConfiguration solution) {
18098baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // Copy the current state into the solution. This solution will be manipulated as necessary.
18108baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        copyCurrentStateToSolution(solution, false);
18118baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // Copy the current occupied array into the temporary occupied array. This array will be
18128baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // manipulated as necessary to find a solution.
18138baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        copyOccupiedArray(mTmpOccupied);
1814482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1815482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // We find the nearest cell into which we would place the dragged item, assuming there's
1816482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // nothing in its way.
1817482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        int result[] = new int[2];
1818482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        result = findNearestArea(pixelX, pixelY, spanX, spanY, result);
1819482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1820482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        boolean success = false;
1821482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // First we try the exact nearest position of the item being dragged,
1822482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // we will then want to try to move this around to other neighbouring positions
18238baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        success = rearrangementExists(result[0], result[1], spanX, spanY, direction, dragView,
18248baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                solution);
1825482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1826482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (!success) {
1827482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            // We try shrinking the widget down to size in an alternating pattern, shrink 1 in
1828482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            // x, then 1 in y etc.
1829482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (spanX > minSpanX && (minSpanY == spanY || decX)) {
1830482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                return simpleSwap(pixelX, pixelY, minSpanX, minSpanY, spanX - 1, spanY, direction,
1831482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        dragView, false, solution);
1832482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            } else if (spanY > minSpanY) {
1833482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                return simpleSwap(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY - 1, direction,
1834482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        dragView, true, solution);
1835482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1836482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.isSolution = false;
1837482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        } else {
1838482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.isSolution = true;
1839482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewX = result[0];
1840482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewY = result[1];
1841482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewSpanX = spanX;
1842482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewSpanY = spanY;
1843482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1844482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return solution;
1845482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1846482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1847482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private void copyCurrentStateToSolution(ItemConfiguration solution, boolean temp) {
1848a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        int childCount = mShortcutsAndWidgets.getChildCount();
1849482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < childCount; i++) {
1850a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            View child = mShortcutsAndWidgets.getChildAt(i);
1851482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
18528baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c;
1853482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (temp) {
18548baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                c = new CellAndSpan(lp.tmpCellX, lp.tmpCellY, lp.cellHSpan, lp.cellVSpan);
1855482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            } else {
18568baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                c = new CellAndSpan(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan);
1857482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
18588baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            solution.map.put(child, c);
1859482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1860482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1861482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1862482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private void copySolutionToTempState(ItemConfiguration solution, View dragView) {
1863482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < mCountX; i++) {
1864482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            for (int j = 0; j < mCountY; j++) {
1865482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                mTmpOccupied[i][j] = false;
1866482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1867482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1868482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1869a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        int childCount = mShortcutsAndWidgets.getChildCount();
1870482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < childCount; i++) {
1871a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            View child = mShortcutsAndWidgets.getChildAt(i);
1872482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (child == dragView) continue;
1873482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
18748baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = solution.map.get(child);
18758baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            if (c != null) {
18768baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                lp.tmpCellX = c.x;
18778baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                lp.tmpCellY = c.y;
18788baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                lp.cellHSpan = c.spanX;
18798baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                lp.cellVSpan = c.spanY;
18808baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, true);
1881482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1882482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1883482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsForView(solution.dragViewX, solution.dragViewY, solution.dragViewSpanX,
1884482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                solution.dragViewSpanY, mTmpOccupied, true);
1885482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1886482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1887482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private void animateItemsToSolution(ItemConfiguration solution, View dragView, boolean
1888482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            commitDragView) {
1889482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1890482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        boolean[][] occupied = DESTRUCTIVE_REORDER ? mOccupied : mTmpOccupied;
1891482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < mCountX; i++) {
1892482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            for (int j = 0; j < mCountY; j++) {
1893482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                occupied[i][j] = false;
1894482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1895482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1896482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1897a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        int childCount = mShortcutsAndWidgets.getChildCount();
1898482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < childCount; i++) {
1899a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            View child = mShortcutsAndWidgets.getChildAt(i);
1900482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (child == dragView) continue;
1901482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
19028baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = solution.map.get(child);
19038baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            if (c != null) {
19048baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                if (lp.cellX != c.x || lp.cellY != c.y) {
19058baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                    animateChildToPosition(child, c.x, c.y, 150, 0, DESTRUCTIVE_REORDER, false);
1906482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                }
19078baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                markCellsForView(c.x, c.y, c.spanX, c.spanY, occupied, true);
1908482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1909482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1910482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (commitDragView) {
1911482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            markCellsForView(solution.dragViewX, solution.dragViewY, solution.dragViewSpanX,
1912482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    solution.dragViewSpanY, occupied, true);
1913482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1914482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1915482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1916482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private void commitTempPlacement() {
1917482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < mCountX; i++) {
1918482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            for (int j = 0; j < mCountY; j++) {
1919482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                mOccupied[i][j] = mTmpOccupied[i][j];
1920482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1921482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1922a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        int childCount = mShortcutsAndWidgets.getChildCount();
1923482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < childCount; i++) {
1924a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            LayoutParams lp = (LayoutParams) mShortcutsAndWidgets.getChildAt(i).getLayoutParams();
1925482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            lp.cellX = lp.tmpCellX;
1926482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            lp.cellY = lp.tmpCellY;
1927482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1928482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1929482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1930482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public void setUseTempCoords(boolean useTempCoords) {
1931a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        int childCount = mShortcutsAndWidgets.getChildCount();
1932482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < childCount; i++) {
1933a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            LayoutParams lp = (LayoutParams) mShortcutsAndWidgets.getChildAt(i).getLayoutParams();
1934482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            lp.useTmpCoords = useTempCoords;
1935482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1936482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1937482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1938482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    ItemConfiguration findConfigurationNoShuffle(int pixelX, int pixelY, int minSpanX, int minSpanY,
1939482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            int spanX, int spanY, View dragView, ItemConfiguration solution) {
1940482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        int[] result = new int[2];
1941482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        int[] resultSpan = new int[2];
1942482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        findNearestVacantArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, null, result,
1943482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                resultSpan);
1944482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (result[0] >= 0 && result[1] >= 0) {
1945482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            copyCurrentStateToSolution(solution, false);
1946482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewX = result[0];
1947482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewY = result[1];
1948482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewSpanX = resultSpan[0];
1949482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewSpanY = resultSpan[1];
1950482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.isSolution = true;
1951482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        } else {
1952482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.isSolution = false;
1953482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1954482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return solution;
1955482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1956482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1957482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public void prepareChildForDrag(View child) {
1958482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsAsUnoccupiedForView(child);
1959482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1960482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1961482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    int[] createArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, int spanY,
1962482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            View dragView, int[] result, int resultSpan[], int mode) {
1963482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1964482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // First we determine if things have moved enough to cause a different layout
196547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        result = findNearestArea(pixelX, pixelY, spanX, spanY, result);
1966482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1967482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (resultSpan == null) {
1968482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            resultSpan = new int[2];
1969482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1970482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1971482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // We attempt the first algorithm
197247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        regionToCenterPoint(result[0], result[1], spanX, spanY, mTmpPoint);
197347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        computeDirectionVector((mTmpPoint[0] - pixelX) / spanX, (mTmpPoint[1] - pixelY) / spanY,
197447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                mDirectionVector);
1975482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        ItemConfiguration swapSolution = simpleSwap(pixelX, pixelY, minSpanX, minSpanY,
1976482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                 spanX,  spanY, mDirectionVector, dragView,  true,  new ItemConfiguration());
1977482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1978482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // We attempt the approach which doesn't shuffle views at all
1979482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        ItemConfiguration noShuffleSolution = findConfigurationNoShuffle(pixelX, pixelY, minSpanX,
1980482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                minSpanY, spanX, spanY, dragView, new ItemConfiguration());
1981482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1982482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        ItemConfiguration finalSolution = null;
1983482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (swapSolution.isSolution && swapSolution.area() >= noShuffleSolution.area()) {
1984482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            finalSolution = swapSolution;
1985482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        } else if (noShuffleSolution.isSolution) {
1986482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            finalSolution = noShuffleSolution;
1987482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1988482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1989482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        boolean foundSolution = true;
1990482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (!DESTRUCTIVE_REORDER) {
1991482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            setUseTempCoords(true);
1992482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1993482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1994482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (finalSolution != null) {
1995482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            result[0] = finalSolution.dragViewX;
1996482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            result[1] = finalSolution.dragViewY;
1997482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            resultSpan[0] = finalSolution.dragViewSpanX;
1998482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            resultSpan[1] = finalSolution.dragViewSpanY;
1999482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2000482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            // If we're just testing for a possible location (MODE_ACCEPT_DROP), we don't bother
2001482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            // committing anything or animating anything as we just want to determine if a solution
2002482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            // exists
2003482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (mode == MODE_DRAG_OVER || mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL) {
2004482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                if (!DESTRUCTIVE_REORDER) {
2005482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    copySolutionToTempState(finalSolution, dragView);
2006482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                }
2007482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                setItemPlacementDirty(true);
2008482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                animateItemsToSolution(finalSolution, dragView, mode == MODE_ON_DROP);
2009482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2010482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                if (!DESTRUCTIVE_REORDER && mode == MODE_ON_DROP) {
2011482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    commitTempPlacement();
2012482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                }
2013482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
2014482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        } else {
2015482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            foundSolution = false;
2016482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            result[0] = result[1] = resultSpan[0] = resultSpan[1] = -1;
2017482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2018482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2019482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if ((mode == MODE_ON_DROP || !foundSolution) && !DESTRUCTIVE_REORDER) {
2020482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            setUseTempCoords(false);
2021482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2022482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2023a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.requestLayout();
2024482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return result;
2025482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2026482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2027482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public boolean isItemPlacementDirty() {
2028482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return mItemLocationsDirty;
2029482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2030482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2031482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public void setItemPlacementDirty(boolean dirty) {
2032482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        mItemLocationsDirty = dirty;
2033482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2034482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2035482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private class ItemConfiguration {
20368baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        HashMap<View, CellAndSpan> map = new HashMap<View, CellAndSpan>();
2037482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        boolean isSolution = false;
2038482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        int dragViewX, dragViewY, dragViewSpanX, dragViewSpanY;
2039482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2040482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        int area() {
2041482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            return dragViewSpanX * dragViewSpanY;
2042482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
20438baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen    }
20448baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen
20458baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen    private class CellAndSpan {
20468baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        int x, y;
20478baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        int spanX, spanY;
20488baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen
20498baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        public CellAndSpan(int x, int y, int spanX, int spanY) {
20508baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            this.x = x;
20518baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            this.y = y;
20528baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            this.spanX = spanX;
20538baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            this.spanY = spanY;
2054482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2055482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2056482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2057df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    /**
2058df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * Find a vacant area that will fit the given bounds nearest the requested
2059df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * cell location. Uses Euclidean distance to score multiple vacant areas.
2060df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     *
2061df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param pixelX The X location at which you want to search for a vacant area.
2062df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param pixelY The Y location at which you want to search for a vacant area.
2063df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param spanX Horizontal span of the object.
2064df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param spanY Vertical span of the object.
2065df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param ignoreView Considers space occupied by this view as unoccupied
2066df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param result Previously returned value to possibly recycle.
2067df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @return The X, Y cell of a vacant area that can contain this object,
2068df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     *         nearest the requested location.
2069df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     */
2070df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    int[] findNearestVacantArea(
2071df0353815c629fc678824b07a234b89a1ff94208Adam Cohen            int pixelX, int pixelY, int spanX, int spanY, View ignoreView, int[] result) {
2072df0353815c629fc678824b07a234b89a1ff94208Adam Cohen        return findNearestArea(pixelX, pixelY, spanX, spanY, ignoreView, true, result);
2073df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    }
2074df0353815c629fc678824b07a234b89a1ff94208Adam Cohen
2075df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    /**
2076d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * Find a vacant area that will fit the given bounds nearest the requested
2077d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * cell location. Uses Euclidean distance to score multiple vacant areas.
2078d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *
2079d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param pixelX The X location at which you want to search for a vacant area.
2080d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param pixelY The Y location at which you want to search for a vacant area.
2081d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param minSpanX The minimum horizontal span required
2082d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param minSpanY The minimum vertical span required
2083d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param spanX Horizontal span of the object.
2084d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param spanY Vertical span of the object.
2085d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param ignoreView Considers space occupied by this view as unoccupied
2086d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param result Previously returned value to possibly recycle.
2087d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @return The X, Y cell of a vacant area that can contain this object,
2088d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *         nearest the requested location.
2089d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     */
2090d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    int[] findNearestVacantArea(int pixelX, int pixelY, int minSpanX, int minSpanY,
2091d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            int spanX, int spanY, View ignoreView, int[] result, int[] resultSpan) {
2092482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return findNearestArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, ignoreView, true,
2093482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                result, resultSpan, mOccupied);
2094d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    }
2095d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen
2096d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    /**
2097df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * Find a starting cell position that will fit the given bounds nearest the requested
2098df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * cell location. Uses Euclidean distance to score multiple vacant areas.
2099df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     *
2100df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param pixelX The X location at which you want to search for a vacant area.
2101df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param pixelY The Y location at which you want to search for a vacant area.
2102df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param spanX Horizontal span of the object.
2103df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param spanY Vertical span of the object.
2104df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param ignoreView Considers space occupied by this view as unoccupied
2105df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param result Previously returned value to possibly recycle.
2106df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @return The X, Y cell of a vacant area that can contain this object,
2107df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     *         nearest the requested location.
2108df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     */
2109df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    int[] findNearestArea(
2110df0353815c629fc678824b07a234b89a1ff94208Adam Cohen            int pixelX, int pixelY, int spanX, int spanY, int[] result) {
2111df0353815c629fc678824b07a234b89a1ff94208Adam Cohen        return findNearestArea(pixelX, pixelY, spanX, spanY, null, false, result);
2112df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    }
2113df0353815c629fc678824b07a234b89a1ff94208Adam Cohen
21140280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    boolean existsEmptyCell() {
21150280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        return findCellForSpan(null, 1, 1);
21160280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
21170280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
21180280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    /**
21190280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * Finds the upper-left coordinate of the first rectangle in the grid that can
21200280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * hold a cell of the specified dimensions. If intersectX and intersectY are not -1,
21210280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * then this method will only return coordinates for rectangles that contain the cell
21220280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * (intersectX, intersectY)
21230280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     *
21240280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param cellXY The array that will contain the position of a vacant cell if such a cell
21250280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     *               can be found.
21260280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param spanX The horizontal span of the cell we want to find.
21270280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param spanY The vertical span of the cell we want to find.
21280280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     *
21290280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @return True if a vacant cell of the specified dimension was found, false otherwise.
21300280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     */
21310280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    boolean findCellForSpan(int[] cellXY, int spanX, int spanY) {
2132482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return findCellForSpanThatIntersectsIgnoring(cellXY, spanX, spanY, -1, -1, null, mOccupied);
21330280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
21340280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
21350280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    /**
21360280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * Like above, but ignores any cells occupied by the item "ignoreView"
21370280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     *
21380280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param cellXY The array that will contain the position of a vacant cell if such a cell
21390280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     *               can be found.
21400280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param spanX The horizontal span of the cell we want to find.
21410280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param spanY The vertical span of the cell we want to find.
21420280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param ignoreView The home screen item we should treat as not occupying any space
21430280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @return
21440280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     */
21450280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    boolean findCellForSpanIgnoring(int[] cellXY, int spanX, int spanY, View ignoreView) {
2146482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return findCellForSpanThatIntersectsIgnoring(cellXY, spanX, spanY, -1, -1,
2147482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                ignoreView, mOccupied);
21480280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
21490280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
21500280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    /**
21510280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * Like above, but if intersectX and intersectY are not -1, then this method will try to
21520280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * return coordinates for rectangles that contain the cell [intersectX, intersectY]
21530280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     *
21540280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param spanX The horizontal span of the cell we want to find.
21550280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param spanY The vertical span of the cell we want to find.
21560280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param ignoreView The home screen item we should treat as not occupying any space
21570280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param intersectX The X coordinate of the cell that we should try to overlap
21580280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param intersectX The Y coordinate of the cell that we should try to overlap
21590280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     *
21600280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @return True if a vacant cell of the specified dimension was found, false otherwise.
21610280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     */
21620280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    boolean findCellForSpanThatIntersects(int[] cellXY, int spanX, int spanY,
21630280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            int intersectX, int intersectY) {
21640280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        return findCellForSpanThatIntersectsIgnoring(
2165482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                cellXY, spanX, spanY, intersectX, intersectY, null, mOccupied);
21660280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
21670280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
21680280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    /**
21690280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * The superset of the above two methods
21700280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     */
21710280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    boolean findCellForSpanThatIntersectsIgnoring(int[] cellXY, int spanX, int spanY,
2172482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            int intersectX, int intersectY, View ignoreView, boolean occupied[][]) {
2173c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka        // mark space take by ignoreView as available (method checks if ignoreView is null)
2174482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsAsUnoccupiedForView(ignoreView, occupied);
21750280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
217628750fba6a2d141eb9a1e566718c17236030b815Michael Jurka        boolean foundCell = false;
21770280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        while (true) {
21780280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            int startX = 0;
21790280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            if (intersectX >= 0) {
21800280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                startX = Math.max(startX, intersectX - (spanX - 1));
21810280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            }
21820280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            int endX = mCountX - (spanX - 1);
21830280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            if (intersectX >= 0) {
21840280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                endX = Math.min(endX, intersectX + (spanX - 1) + (spanX == 1 ? 1 : 0));
21850280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            }
21860280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            int startY = 0;
21870280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            if (intersectY >= 0) {
21880280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                startY = Math.max(startY, intersectY - (spanY - 1));
21890280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            }
21900280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            int endY = mCountY - (spanY - 1);
21910280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            if (intersectY >= 0) {
21920280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                endY = Math.min(endY, intersectY + (spanY - 1) + (spanY == 1 ? 1 : 0));
21930280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            }
21940280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
2195bbc60d8e79416e37cbede55c159bf6aaa6c171d5Winson Chung            for (int y = startY; y < endY && !foundCell; y++) {
21960280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                inner:
2197bbc60d8e79416e37cbede55c159bf6aaa6c171d5Winson Chung                for (int x = startX; x < endX; x++) {
21980280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                    for (int i = 0; i < spanX; i++) {
21990280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                        for (int j = 0; j < spanY; j++) {
2200482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                            if (occupied[x + i][y + j]) {
2201bbc60d8e79416e37cbede55c159bf6aaa6c171d5Winson Chung                                // small optimization: we can skip to after the column we just found
22020280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                                // an occupied cell
2203bbc60d8e79416e37cbede55c159bf6aaa6c171d5Winson Chung                                x += i;
22040280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                                continue inner;
22050280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                            }
22060280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                        }
22070280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                    }
22080280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                    if (cellXY != null) {
22090280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                        cellXY[0] = x;
22100280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                        cellXY[1] = y;
22110280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                    }
221228750fba6a2d141eb9a1e566718c17236030b815Michael Jurka                    foundCell = true;
221328750fba6a2d141eb9a1e566718c17236030b815Michael Jurka                    break;
22140280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                }
22150280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            }
22160280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            if (intersectX == -1 && intersectY == -1) {
22170280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                break;
22180280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            } else {
22190280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                // if we failed to find anything, try again but without any requirements of
22200280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                // intersecting
22210280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                intersectX = -1;
22220280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                intersectY = -1;
22230280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                continue;
22240280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            }
22250280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        }
22260280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
2227c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka        // re-mark space taken by ignoreView as occupied
2228482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsAsOccupiedForView(ignoreView, occupied);
222928750fba6a2d141eb9a1e566718c17236030b815Michael Jurka        return foundCell;
22300280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
22310280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
223231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
2233c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung     * A drag event has begun over this layout.
2234c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung     * It may have begun over this layout (in which case onDragChild is called first),
2235c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung     * or it may have begun on another layout.
2236c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung     */
2237c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung    void onDragEnter() {
2238c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung        if (!mDragging) {
2239c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung            // Fade in the drag indicators
2240c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung            if (mCrosshairsAnimator != null) {
2241c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung                mCrosshairsAnimator.animateIn();
2242c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung            }
2243c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung        }
2244c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung        mDragging = true;
2245c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung    }
2246c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung
2247c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung    /**
22480280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * Called when drag has left this CellLayout or has been completed (successfully or not)
22496569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     */
22500280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    void onDragExit() {
22514be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        // This can actually be called when we aren't in a drag, e.g. when adding a new
22524be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        // item to this layout via the customize drawer.
22534be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        // Guard against that case.
22544be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        if (mDragging) {
22554be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            mDragging = false;
22566569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
22574be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            // Fade out the drag indicators
22584be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            if (mCrosshairsAnimator != null) {
22594be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                mCrosshairsAnimator.animateOut();
22604be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            }
22614be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        }
226208ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy
226308ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy        // Invalidate the drag data
2264d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        mDragCell[0] = mDragCell[1] = -1;
226508ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy        mDragOutlineAnims[mDragOutlineCurrent].animateOut();
226608ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy        mDragOutlineCurrent = (mDragOutlineCurrent + 1) % mDragOutlineAnims.length;
226708ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy
226833945b21544bc98381df17726a3537c292d8c985Michael Jurka        setIsDragOverlapping(false);
22696569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    }
22706569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
22716569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    /**
2272aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     * Mark a child as having been dropped.
2273de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy     * At the beginning of the drag operation, the child may have been on another
2274ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy     * screen, but it is re-parented before this method is called.
227531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     *
227631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param child The child that is being dropped
227731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
2278716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    void onDropChild(View child) {
2279d94533d04a5f8f5485f106d10af60169857ea899Romain Guy        if (child != null) {
2280d94533d04a5f8f5485f106d10af60169857ea899Romain Guy            LayoutParams lp = (LayoutParams) child.getLayoutParams();
228184f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy            lp.dropped = true;
2282d94533d04a5f8f5485f106d10af60169857ea899Romain Guy            child.requestLayout();
2283d94533d04a5f8f5485f106d10af60169857ea899Romain Guy        }
228431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
228531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
228631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
228731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * Computes a bounding rectangle for a range of cells
2288aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     *
228931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param cellX X coordinate of upper left corner expressed as a cell position
229031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param cellY Y coordinate of upper left corner expressed as a cell position
2291aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     * @param cellHSpan Width in cells
229231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param cellVSpan Height in cells
22936569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     * @param resultRect Rect into which to put the results
229431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
2295d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    public void cellToRect(int cellX, int cellY, int cellHSpan, int cellVSpan, Rect resultRect) {
229631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        final int cellWidth = mCellWidth;
229731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        final int cellHeight = mCellHeight;
229831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        final int widthGap = mWidthGap;
229931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        final int heightGap = mHeightGap;
2300aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
23014b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int hStartPadding = getPaddingLeft();
23024b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int vStartPadding = getPaddingTop();
2303aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
230431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int width = cellHSpan * cellWidth + ((cellHSpan - 1) * widthGap);
230531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int height = cellVSpan * cellHeight + ((cellVSpan - 1) * heightGap);
230631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
230731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int x = hStartPadding + cellX * (cellWidth + widthGap);
230831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int y = vStartPadding + cellY * (cellHeight + heightGap);
2309aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
23106569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        resultRect.set(x, y, x + width, y + height);
231131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
2312aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
231331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
2314aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     * Computes the required horizontal and vertical cell spans to always
231531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * fit the given rectangle.
2316aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     *
231731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param width Width in pixels
231831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param height Height in pixels
23198f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy     * @param result An array of length 2 in which to store the result (may be null).
232031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
23218f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy    public int[] rectToCell(int width, int height, int[] result) {
23229987a5c45e7d01a780d73b269bdce8d8a5309219Michael Jurka        return rectToCell(getResources(), width, height, result);
23239987a5c45e7d01a780d73b269bdce8d8a5309219Michael Jurka    }
23249987a5c45e7d01a780d73b269bdce8d8a5309219Michael Jurka
23259987a5c45e7d01a780d73b269bdce8d8a5309219Michael Jurka    public static int[] rectToCell(Resources resources, int width, int height, int[] result) {
232631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // Always assume we're working with the smallest span to make sure we
232731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // reserve enough space in both orientations.
232879e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato        int actualWidth = resources.getDimensionPixelSize(R.dimen.workspace_cell_width);
232979e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato        int actualHeight = resources.getDimensionPixelSize(R.dimen.workspace_cell_height);
233031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int smallerSize = Math.min(actualWidth, actualHeight);
233179e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato
233231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // Always round up to next largest cell
233354c725cc294cd43ed0650179bfae64a622547660Winson Chung        int spanX = (int) Math.ceil(width / (float) smallerSize);
233454c725cc294cd43ed0650179bfae64a622547660Winson Chung        int spanY = (int) Math.ceil(height / (float) smallerSize);
233579e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato
23368f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy        if (result == null) {
23378f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy            return new int[] { spanX, spanY };
23388f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy        }
23398f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy        result[0] = spanX;
23408f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy        result[1] = spanY;
23418f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy        return result;
234231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
234331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
2344f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka    public int[] cellSpansToSize(int hSpans, int vSpans) {
2345f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka        int[] size = new int[2];
2346f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka        size[0] = hSpans * mCellWidth + (hSpans - 1) * mWidthGap;
2347f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka        size[1] = vSpans * mCellHeight + (vSpans - 1) * mHeightGap;
2348f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka        return size;
2349f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka    }
2350f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka
235131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
2352047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy     * Calculate the grid spans needed to fit given item
2353047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy     */
2354047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy    public void calculateSpans(ItemInfo info) {
2355047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        final int minWidth;
2356047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        final int minHeight;
2357047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy
2358047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        if (info instanceof LauncherAppWidgetInfo) {
2359047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy            minWidth = ((LauncherAppWidgetInfo) info).minWidth;
2360047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy            minHeight = ((LauncherAppWidgetInfo) info).minHeight;
2361047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        } else if (info instanceof PendingAddWidgetInfo) {
2362047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy            minWidth = ((PendingAddWidgetInfo) info).minWidth;
2363047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy            minHeight = ((PendingAddWidgetInfo) info).minHeight;
2364047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        } else {
2365047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy            // It's not a widget, so it must be 1x1
2366047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy            info.spanX = info.spanY = 1;
2367047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy            return;
2368047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        }
2369047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        int[] spans = rectToCell(minWidth, minHeight, null);
2370047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        info.spanX = spans[0];
2371047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        info.spanY = spans[1];
2372047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy    }
2373047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy
2374047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy    /**
237531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * Find the first vacant cell, if there is one.
237631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     *
237731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param vacant Holds the x and y coordinate of the vacant cell
237831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param spanX Horizontal cell span.
237931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param spanY Vertical cell span.
2380aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     *
238131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @return True if a vacant cell was found
238231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
238331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public boolean getVacantCell(int[] vacant, int spanX, int spanY) {
238431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
23850280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        return findVacantCell(vacant, spanX, spanY, mCountX, mCountY, mOccupied);
238631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
238731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
238831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    static boolean findVacantCell(int[] vacant, int spanX, int spanY,
238931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            int xCount, int yCount, boolean[][] occupied) {
239031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
23912801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        for (int y = 0; y < yCount; y++) {
23922801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            for (int x = 0; x < xCount; x++) {
239331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                boolean available = !occupied[x][y];
239431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectout:            for (int i = x; i < x + spanX - 1 && x < xCount; i++) {
239531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                    for (int j = y; j < y + spanY - 1 && y < yCount; j++) {
239631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                        available = available && !occupied[i][j];
239731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                        if (!available) break out;
239831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                    }
239931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                }
240031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
240131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                if (available) {
240231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                    vacant[0] = x;
240331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                    vacant[1] = y;
240431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                    return true;
240531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                }
240631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            }
240731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
240831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
240931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        return false;
241031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
241131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
24120280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    private void clearOccupiedCells() {
24130280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        for (int x = 0; x < mCountX; x++) {
24140280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            for (int y = 0; y < mCountY; y++) {
24150280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                mOccupied[x][y] = false;
241631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            }
241731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
24180280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
241931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
24201b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen    /**
24211b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen     * Given a view, determines how much that view can be expanded in all directions, in terms of
24221b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen     * whether or not there are other items occupying adjacent cells. Used by the
24231b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen     * AppWidgetResizeFrame to determine how the widget can be resized.
24241b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen     */
2425d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    public void getExpandabilityArrayForView(View view, int[] expandability) {
24261b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen        final LayoutParams lp = (LayoutParams) view.getLayoutParams();
2427d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        boolean flag;
2428d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
24291b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen        expandability[AppWidgetResizeFrame.LEFT] = 0;
2430d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        for (int x = lp.cellX - 1; x >= 0; x--) {
2431d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            flag = false;
2432d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            for (int y = lp.cellY; y < lp.cellY + lp.cellVSpan; y++) {
2433d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                if (mOccupied[x][y]) flag = true;
2434d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            }
2435d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            if (flag) break;
24361b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen            expandability[AppWidgetResizeFrame.LEFT]++;
2437d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        }
2438d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
24391b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen        expandability[AppWidgetResizeFrame.TOP] = 0;
2440d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        for (int y = lp.cellY - 1; y >= 0; y--) {
2441d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            flag = false;
2442d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            for (int x = lp.cellX; x < lp.cellX + lp.cellHSpan; x++) {
2443d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                if (mOccupied[x][y]) flag = true;
2444d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            }
2445d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            if (flag) break;
24461b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen            expandability[AppWidgetResizeFrame.TOP]++;
24471b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen        }
2448d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
24491b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen        expandability[AppWidgetResizeFrame.RIGHT] = 0;
2450d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        for (int x = lp.cellX + lp.cellHSpan; x < mCountX; x++) {
2451d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            flag = false;
2452d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            for (int y = lp.cellY; y < lp.cellY + lp.cellVSpan; y++) {
2453d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                if (mOccupied[x][y]) flag = true;
2454d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            }
2455d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            if (flag) break;
24561b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen            expandability[AppWidgetResizeFrame.RIGHT]++;
24571b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen        }
2458d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
24591b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen        expandability[AppWidgetResizeFrame.BOTTOM] = 0;
2460d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        for (int y = lp.cellY + lp.cellVSpan; y < mCountY; y++) {
2461d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            flag = false;
2462d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            for (int x = lp.cellX; x < lp.cellX + lp.cellHSpan; x++) {
2463d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                if (mOccupied[x][y]) flag = true;
2464d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            }
2465d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            if (flag) break;
24661b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen            expandability[AppWidgetResizeFrame.BOTTOM]++;
24671b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen        }
2468d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    }
2469d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
2470d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    public void onMove(View view, int newCellX, int newCellY, int newSpanX, int newSpanY) {
24710280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        markCellsAsUnoccupiedForView(view);
2472482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsForView(newCellX, newCellY, newSpanX, newSpanY, mOccupied, true);
24730280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
247431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
2475d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    public void markCellsAsOccupiedForView(View view) {
2476482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsAsOccupiedForView(view, mOccupied);
2477482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2478482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public void markCellsAsOccupiedForView(View view, boolean[][] occupied) {
2479a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        if (view == null || view.getParent() != mShortcutsAndWidgets) return;
24800280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        LayoutParams lp = (LayoutParams) view.getLayoutParams();
2481482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, occupied, true);
24820280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
24830280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
2484d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    public void markCellsAsUnoccupiedForView(View view) {
2485482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsAsUnoccupiedForView(view, mOccupied);
2486482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2487482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public void markCellsAsUnoccupiedForView(View view, boolean occupied[][]) {
2488a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        if (view == null || view.getParent() != mShortcutsAndWidgets) return;
24890280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        LayoutParams lp = (LayoutParams) view.getLayoutParams();
2490482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, occupied, false);
24910280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
24920280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
2493482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private void markCellsForView(int cellX, int cellY, int spanX, int spanY, boolean[][] occupied,
2494482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            boolean value) {
2495482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (cellX < 0 || cellY < 0) return;
24960280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        for (int x = cellX; x < cellX + spanX && x < mCountX; x++) {
24970280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            for (int y = cellY; y < cellY + spanY && y < mCountY; y++) {
2498482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                occupied[x][y] = value;
249931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            }
250031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
250131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
250231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
25032801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    public int getDesiredWidth() {
25044b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        return mPaddingLeft + mPaddingRight + (mCountX * mCellWidth) +
25052801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen                (Math.max((mCountX - 1), 0) * mWidthGap);
25062801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    }
25072801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
25082801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    public int getDesiredHeight()  {
25094b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        return mPaddingTop + mPaddingBottom + (mCountY * mCellHeight) +
25102801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen                (Math.max((mCountY - 1), 0) * mHeightGap);
25112801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    }
25122801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
251366d72178af91d455700875635473be942bc90e54Michael Jurka    public boolean isOccupied(int x, int y) {
251466d72178af91d455700875635473be942bc90e54Michael Jurka        if (x < mCountX && y < mCountY) {
251566d72178af91d455700875635473be942bc90e54Michael Jurka            return mOccupied[x][y];
251666d72178af91d455700875635473be942bc90e54Michael Jurka        } else {
251766d72178af91d455700875635473be942bc90e54Michael Jurka            throw new RuntimeException("Position exceeds the bound of this CellLayout");
251866d72178af91d455700875635473be942bc90e54Michael Jurka        }
251966d72178af91d455700875635473be942bc90e54Michael Jurka    }
252066d72178af91d455700875635473be942bc90e54Michael Jurka
252131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
252231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
252331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        return new CellLayout.LayoutParams(getContext(), attrs);
252431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
252531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
252631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
252731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
252831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        return p instanceof CellLayout.LayoutParams;
252931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
253031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
253131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
253231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
253331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        return new CellLayout.LayoutParams(p);
253431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
253531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
2536aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung    public static class CellLayoutAnimationController extends LayoutAnimationController {
2537aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        public CellLayoutAnimationController(Animation animation, float delay) {
2538aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            super(animation, delay);
2539aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        }
2540aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
2541aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        @Override
2542aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        protected long getDelayForView(View view) {
2543aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            return (int) (Math.random() * 150);
2544aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        }
2545aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung    }
2546aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
254731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public static class LayoutParams extends ViewGroup.MarginLayoutParams {
254831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        /**
254931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         * Horizontal location of the item in the grid.
255031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         */
255131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        @ViewDebug.ExportedProperty
255231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public int cellX;
255331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
255431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        /**
255531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         * Vertical location of the item in the grid.
255631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         */
255731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        @ViewDebug.ExportedProperty
255831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public int cellY;
255931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
256031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        /**
2561482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         * Temporary horizontal location of the item in the grid during reorder
2562482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         */
2563482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        public int tmpCellX;
2564482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2565482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        /**
2566482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         * Temporary vertical location of the item in the grid during reorder
2567482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         */
2568482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        public int tmpCellY;
2569482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2570482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        /**
2571482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         * Indicates that the temporary coordinates should be used to layout the items
2572482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         */
2573482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        public boolean useTmpCoords;
2574482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2575482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        /**
257631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         * Number of cells spanned horizontally by the item.
257731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         */
257831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        @ViewDebug.ExportedProperty
257931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public int cellHSpan;
258031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
258131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        /**
258231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         * Number of cells spanned vertically by the item.
258331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         */
258431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        @ViewDebug.ExportedProperty
258531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public int cellVSpan;
2586aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
25871b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen        /**
25881b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen         * Indicates whether the item will set its x, y, width and height parameters freely,
25891b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen         * or whether these will be computed based on cellX, cellY, cellHSpan and cellVSpan.
25901b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen         */
2591d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        public boolean isLockedToGrid = true;
2592d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
2593482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        /**
2594482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         * Indicates whether this item can be reordered. Always true except in the case of the
2595482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         * the AllApps button.
2596482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         */
2597482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        public boolean canReorder = true;
2598482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
259931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // X coordinate of the view in the layout.
260031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        @ViewDebug.ExportedProperty
260131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int x;
260231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // Y coordinate of the view in the layout.
260331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        @ViewDebug.ExportedProperty
260431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int y;
260531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
260684f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy        boolean dropped;
2607fcb9e7144e58614f5ae0e9b272fb7ce040848c67Romain Guy
260831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public LayoutParams(Context c, AttributeSet attrs) {
260931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            super(c, attrs);
261031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            cellHSpan = 1;
261131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            cellVSpan = 1;
261231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
261331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
261431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public LayoutParams(ViewGroup.LayoutParams source) {
261531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            super(source);
261631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            cellHSpan = 1;
261731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            cellVSpan = 1;
261831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
2619aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
2620aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        public LayoutParams(LayoutParams source) {
2621aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            super(source);
2622aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            this.cellX = source.cellX;
2623aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            this.cellY = source.cellY;
2624aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            this.cellHSpan = source.cellHSpan;
2625aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            this.cellVSpan = source.cellVSpan;
2626aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        }
2627aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
262831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public LayoutParams(int cellX, int cellY, int cellHSpan, int cellVSpan) {
26298f19cdd62f6e2be05e3890916eabd11317ae1bc2Romain Guy            super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
263031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            this.cellX = cellX;
263131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            this.cellY = cellY;
263231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            this.cellHSpan = cellHSpan;
263331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            this.cellVSpan = cellVSpan;
263431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
263531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
26367f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public void setup(int cellWidth, int cellHeight, int widthGap, int heightGap) {
2637d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            if (isLockedToGrid) {
2638d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                final int myCellHSpan = cellHSpan;
2639d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                final int myCellVSpan = cellVSpan;
2640482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                final int myCellX = useTmpCoords ? tmpCellX : cellX;
2641482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                final int myCellY = useTmpCoords ? tmpCellY : cellY;
26421b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen
2643d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                width = myCellHSpan * cellWidth + ((myCellHSpan - 1) * widthGap) -
2644d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                        leftMargin - rightMargin;
2645d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                height = myCellVSpan * cellHeight + ((myCellVSpan - 1) * heightGap) -
2646d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                        topMargin - bottomMargin;
2647eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                x = (int) (myCellX * (cellWidth + widthGap) + leftMargin);
2648eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                y = (int) (myCellY * (cellHeight + heightGap) + topMargin);
2649d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            }
2650d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        }
2651d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
2652aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        public String toString() {
2653aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            return "(" + this.cellX + ", " + this.cellY + ")";
2654aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        }
26557f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
26567f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public void setWidth(int width) {
26577f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            this.width = width;
26587f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
26597f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
26607f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public int getWidth() {
26617f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            return width;
26627f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
26637f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
26647f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public void setHeight(int height) {
26657f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            this.height = height;
26667f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
26677f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
26687f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public int getHeight() {
26697f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            return height;
26707f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
26717f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
26727f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public void setX(int x) {
26737f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            this.x = x;
26747f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
26757f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
26767f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public int getX() {
26777f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            return x;
26787f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
26797f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
26807f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public void setY(int y) {
26817f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            this.y = y;
26827f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
26837f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
26847f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public int getY() {
26857f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            return y;
26867f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
268731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
268831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
26890280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    // This class stores info for two purposes:
26900280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    // 1. When dragging items (mDragInfo in Workspace), we store the View, its cellX & cellY,
26910280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    //    its spanX, spanY, and the screen it is on
26920280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    // 2. When long clicking on an empty cell in a CellLayout, we save information about the
26930280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    //    cellX and cellY coordinates and which page was clicked. We then set this as a tag on
26940280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    //    the CellLayout that was long clicked
2695e5fb0f27bca7afb996258a7163c76ca7390d7bffMichael Jurka    static final class CellInfo {
269631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        View cell;
2697a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka        int cellX = -1;
2698a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka        int cellY = -1;
269931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int spanX;
270031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int spanY;
270131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int screen;
27023d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        long container;
270331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
270431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        @Override
270531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public String toString() {
2706aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            return "Cell[view=" + (cell == null ? "null" : cell.getClass())
2707aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung                    + ", x=" + cellX + ", y=" + cellY + "]";
270831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
270931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
2710d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka
2711d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka    public boolean lastDownOnOccupiedCell() {
2712d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka        return mLastDownOnOccupiedCell;
2713d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka    }
271431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project}
2715