CellLayout.java revision 8b805b17158886035b38261eb611d8641701ae43
131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project/*
231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project *
431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * you may not use this file except in compliance with the License.
631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * You may obtain a copy of the License at
731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project *
831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project *
1031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
1131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
1231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * See the License for the specific language governing permissions and
1431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * limitations under the License.
1531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */
1631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
17a5902524d4403885eb4c50360bf3465c6be796efJoe Onoratopackage com.android.launcher2;
1831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
194be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onoratoimport android.animation.Animator;
204be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onoratoimport android.animation.AnimatorListenerAdapter;
2100397b1d9233409d9d6b233b077ae12d09768ce8Chet Haaseimport android.animation.TimeInterpolator;
22de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroyimport android.animation.ValueAnimator;
23de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroyimport android.animation.ValueAnimator.AnimatorUpdateListener;
2431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.content.Context;
2579e56263dbcbe85dc434df372bc6e6730aa13477Joe Onoratoimport android.content.res.Resources;
26aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chungimport android.content.res.TypedArray;
274be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onoratoimport android.graphics.Bitmap;
28aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chungimport android.graphics.Canvas;
290dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynnimport android.graphics.Color;
304be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onoratoimport android.graphics.Paint;
31de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroyimport android.graphics.Point;
32de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroyimport android.graphics.PointF;
33b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohenimport android.graphics.PorterDuff;
34b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohenimport android.graphics.PorterDuffXfermode;
3531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.graphics.Rect;
36482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohenimport android.graphics.drawable.ColorDrawable;
376569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroyimport android.graphics.drawable.Drawable;
38b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohenimport android.graphics.drawable.NinePatchDrawable;
3931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.util.AttributeSet;
404be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onoratoimport android.util.Log;
4131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.MotionEvent;
4231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.View;
4331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.ViewDebug;
4431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.ViewGroup;
45aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chungimport android.view.animation.Animation;
46150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chungimport android.view.animation.DecelerateInterpolator;
47aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chungimport android.view.animation.LayoutAnimationController;
4831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
496639687cd67bab1aeef2a75e5c6bc458b20dc082Adam Cohenimport com.android.launcher.R;
5069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohenimport com.android.launcher2.FolderIcon.FolderRingAnimator;
518e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy
5269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohenimport java.util.ArrayList;
53c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohenimport java.util.Arrays;
54bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohenimport java.util.HashMap;
55d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohenimport java.util.Stack;
56c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen
57bdb5c5342adc550559fd723af461e53248f2fba8Michael Jurkapublic class CellLayout extends ViewGroup {
58aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung    static final String TAG = "CellLayout";
59aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
602acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen    private Launcher mLauncher;
614b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung    private int mOriginalCellWidth;
624b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung    private int mOriginalCellHeight;
6331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private int mCellWidth;
6431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private int mCellHeight;
65aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
66d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen    private int mCountX;
67d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen    private int mCountY;
6831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
69234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen    private int mOriginalWidthGap;
70234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen    private int mOriginalHeightGap;
7131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private int mWidthGap;
7231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private int mHeightGap;
734b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung    private int mMaxGap;
74ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen    private boolean mScrollingTransformsDirty = false;
7531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
7631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private final Rect mRect = new Rect();
7731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private final CellInfo mCellInfo = new CellInfo();
78aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
79de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy    // These are temporary variables to prevent having to allocate a new object just to
80de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy    // return an (x, y) value from helper functions. Do NOT use them to maintain other state.
810be025d64c1f84138fe430a58875886e66aae767Winson Chung    private final int[] mTmpXY = new int[2];
82de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy    private final int[] mTmpPoint = new int[2];
83de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy    private final PointF mTmpPointF = new PointF();
8469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen    int[] mTempLocation = new int[2];
856569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
8631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    boolean[][] mOccupied;
87482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    boolean[][] mTmpOccupied;
88d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka    private boolean mLastDownOnOccupiedCell = false;
8931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
90dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    private OnTouchListener mInterceptTouchListener;
91dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka
9269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen    private ArrayList<FolderRingAnimator> mFolderOuterRings = new ArrayList<FolderRingAnimator>();
93c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen    private int[] mFolderLeaveBehindCell = {-1, -1};
9469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
95b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    private int mForegroundAlpha = 0;
965f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka    private float mBackgroundAlpha;
971b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen    private float mBackgroundAlphaMultiplier = 1.0f;
98f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen
9933945b21544bc98381df17726a3537c292d8c985Michael Jurka    private Drawable mNormalBackground;
10033945b21544bc98381df17726a3537c292d8c985Michael Jurka    private Drawable mActiveGlowBackground;
101b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    private Drawable mOverScrollForegroundDrawable;
102b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    private Drawable mOverScrollLeft;
103b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    private Drawable mOverScrollRight;
10418014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka    private Rect mBackgroundRect;
105b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    private Rect mForegroundRect;
106b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    private int mForegroundPadding;
10733945b21544bc98381df17726a3537c292d8c985Michael Jurka
10833945b21544bc98381df17726a3537c292d8c985Michael Jurka    // If we're actively dragging something over this screen, mIsDragOverlapping is true
10933945b21544bc98381df17726a3537c292d8c985Michael Jurka    private boolean mIsDragOverlapping = false;
110de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy    private final Point mDragCenter = new Point();
1116569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
112150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung    // These arrays are used to implement the drag visualization on x-large screens.
1134be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato    // They are used as circular arrays, indexed by mDragOutlineCurrent.
114d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    private Rect[] mDragOutlines = new Rect[4];
115472b281d5cb4f5660df981a6c912266b9f5703feChet Haase    private float[] mDragOutlineAlphas = new float[mDragOutlines.length];
1164be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato    private InterruptibleInOutAnimator[] mDragOutlineAnims =
1174be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            new InterruptibleInOutAnimator[mDragOutlines.length];
118150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung
119150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung    // Used as an index into the above 3 arrays; indicates which is the most current value.
1204be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato    private int mDragOutlineCurrent = 0;
1218e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy    private final Paint mDragOutlinePaint = new Paint();
122150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung
12396864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy    private BubbleTextView mPressedOrFocusedIcon;
12496864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy
125de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy    private Drawable mCrosshairsDrawable = null;
12649250ad530385fcdd6072ca54697f670ec503b59Patrick Dubroy    private InterruptibleInOutAnimator mCrosshairsAnimator = null;
127de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy    private float mCrosshairsVisibility = 0.0f;
128de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy
129482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private HashMap<CellLayout.LayoutParams, Animator> mReorderAnimators = new
130482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            HashMap<CellLayout.LayoutParams, Animator>();
13119f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private HashMap<View, ReorderHintAnimation>
13219f3792523fe2d55ea791a9286398a6120920690Adam Cohen            mShakeAnimators = new HashMap<View, ReorderHintAnimation>();
13319f3792523fe2d55ea791a9286398a6120920690Adam Cohen
13419f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private boolean mItemPlacementDirty = false;
135bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen
1366569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    // When a drag operation is in progress, holds the nearest cell to the touch point
1376569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    private final int[] mDragCell = new int[2];
13831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
1394be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato    private boolean mDragging = false;
1404be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato
141ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy    private TimeInterpolator mEaseOutInterpolator;
142a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka    private ShortcutAndWidgetContainer mShortcutsAndWidgets;
143ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy
1440dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn    private boolean mIsHotseat = false;
145eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung    private float mChildScale = 1f;
146eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung    private float mHotseatChildScale = 1f;
1470dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn
148482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public static final int MODE_DRAG_OVER = 0;
149482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public static final int MODE_ON_DROP = 1;
150482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public static final int MODE_ON_DROP_EXTERNAL = 2;
151482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public static final int MODE_ACCEPT_DROP = 3;
15219f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private static final boolean DESTRUCTIVE_REORDER = false;
153482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private static final boolean DEBUG_VISUALIZE_OCCUPIED = false;
154482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
15519f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private static final float REORDER_HINT_MAGNITUDE = 0.27f;
15619f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private static final int REORDER_ANIMATION_DURATION = 150;
15719f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private float mReorderHintAnimationMagnitude;
15819f3792523fe2d55ea791a9286398a6120920690Adam Cohen
159482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private ArrayList<View> mIntersectingViews = new ArrayList<View>();
160482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private Rect mOccupiedRect = new Rect();
161482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private int[] mDirectionVector = new int[2];
16219f3792523fe2d55ea791a9286398a6120920690Adam Cohen    int[] mPreviousReorderDirection = new int[2];
163b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen    private static final int INVALID_DIRECTION = -100;
164c6cc61d45836e4081920883cc4d448ccb0bb8417Adam Cohen    private DropTarget.DragEnforcer mDragEnforcer;
165482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
16631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public CellLayout(Context context) {
16731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        this(context, null);
16831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
16931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
17031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public CellLayout(Context context, AttributeSet attrs) {
17131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        this(context, attrs, 0);
17231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
17331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
17431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public CellLayout(Context context, AttributeSet attrs, int defStyle) {
17531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        super(context, attrs, defStyle);
1768b805b17158886035b38261eb611d8641701ae43Michael Jurka        mDragEnforcer = new DropTarget.DragEnforcer(context);
1776569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
1786569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        // A ViewGroup usually does not draw, but CellLayout needs to draw a rectangle to show
1796569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        // the user where a dragged item will land when dropped.
1806569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        setWillNotDraw(false);
1812acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen        mLauncher = (Launcher) context;
182a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka
18331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CellLayout, defStyle, 0);
18431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
1854b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        mOriginalCellWidth =
1864b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung            mCellWidth = a.getDimensionPixelSize(R.styleable.CellLayout_cellWidth, 10);
1874b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        mOriginalCellHeight =
1884b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung            mCellHeight = a.getDimensionPixelSize(R.styleable.CellLayout_cellHeight, 10);
189234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen        mWidthGap = mOriginalWidthGap = a.getDimensionPixelSize(R.styleable.CellLayout_widthGap, 0);
190234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen        mHeightGap = mOriginalHeightGap = a.getDimensionPixelSize(R.styleable.CellLayout_heightGap, 0);
1914b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        mMaxGap = a.getDimensionPixelSize(R.styleable.CellLayout_maxGap, 0);
192d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        mCountX = LauncherModel.getCellCountX();
193d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        mCountY = LauncherModel.getCellCountY();
1940280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        mOccupied = new boolean[mCountX][mCountY];
195482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        mTmpOccupied = new boolean[mCountX][mCountY];
1965b53f29f809a0dad4a1e0717ba610ce737ee0f43Adam Cohen        mPreviousReorderDirection[0] = INVALID_DIRECTION;
1975b53f29f809a0dad4a1e0717ba610ce737ee0f43Adam Cohen        mPreviousReorderDirection[1] = INVALID_DIRECTION;
19831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
19931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        a.recycle();
20031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
20131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        setAlwaysDrawnWithCacheEnabled(false);
20231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
203046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        final Resources res = getResources();
204de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy
205967289b6d5fec77f5c381d11ffb2319f3bb5e737Winson Chung        mNormalBackground = res.getDrawable(R.drawable.homescreen_blue_normal_holo);
206dea74b7d12b0fcd50bfdb4274f9867ba76d75238Winson Chung        mActiveGlowBackground = res.getDrawable(R.drawable.homescreen_blue_strong_holo);
207b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung
208b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        mOverScrollLeft = res.getDrawable(R.drawable.overscroll_glow_left);
209b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        mOverScrollRight = res.getDrawable(R.drawable.overscroll_glow_right);
210b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        mForegroundPadding =
211b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen                res.getDimensionPixelSize(R.dimen.workspace_overscroll_drawable_padding);
212b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung
21319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        mReorderHintAnimationMagnitude = (REORDER_HINT_MAGNITUDE *
21419f3792523fe2d55ea791a9286398a6120920690Adam Cohen                res.getDimensionPixelSize(R.dimen.app_icon_size));
21519f3792523fe2d55ea791a9286398a6120920690Adam Cohen
216b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung        mNormalBackground.setFilterBitmap(true);
217b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung        mActiveGlowBackground.setFilterBitmap(true);
218de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy
219eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung        int iconScale = res.getInteger(R.integer.app_icon_scale_percent);
220eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung        if (iconScale >= 0) {
221eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung            mChildScale = iconScale / 100f;
222eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung        }
223eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung        int hotseatIconScale = res.getInteger(R.integer.app_icon_hotseat_scale_percent);
224eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung        if (hotseatIconScale >= 0) {
225eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung            mHotseatChildScale = hotseatIconScale / 100f;
226eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung        }
2270dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn
228046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        // Initialize the data structures used for the drag visualization.
229150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung
230046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        mCrosshairsDrawable = res.getDrawable(R.drawable.gardening_crosshairs);
231ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy        mEaseOutInterpolator = new DecelerateInterpolator(2.5f); // Quint ease out
232de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy
233046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        // Set up the animation for fading the crosshairs in and out
234046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        int animDuration = res.getInteger(R.integer.config_crosshairsFadeInTime);
23549250ad530385fcdd6072ca54697f670ec503b59Patrick Dubroy        mCrosshairsAnimator = new InterruptibleInOutAnimator(animDuration, 0.0f, 1.0f);
236472b281d5cb4f5660df981a6c912266b9f5703feChet Haase        mCrosshairsAnimator.getAnimator().addUpdateListener(new AnimatorUpdateListener() {
237046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy            public void onAnimationUpdate(ValueAnimator animation) {
238046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy                mCrosshairsVisibility = ((Float) animation.getAnimatedValue()).floatValue();
2398e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy                invalidate();
240046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy            }
241046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        });
242ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy        mCrosshairsAnimator.getAnimator().setInterpolator(mEaseOutInterpolator);
243046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy
244b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung        mDragCell[0] = mDragCell[1] = -1;
2454be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        for (int i = 0; i < mDragOutlines.length; i++) {
246d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            mDragOutlines[i] = new Rect(-1, -1, -1, -1);
247046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        }
248046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy
249046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        // When dragging things around the home screens, we show a green outline of
250046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        // where the item will land. The outlines gradually fade out, leaving a trail
251046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        // behind the drag path.
252046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        // Set up all the animations that are used to implement this fading.
253046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        final int duration = res.getInteger(R.integer.config_dragOutlineFadeTime);
254472b281d5cb4f5660df981a6c912266b9f5703feChet Haase        final float fromAlphaValue = 0;
255472b281d5cb4f5660df981a6c912266b9f5703feChet Haase        final float toAlphaValue = (float)res.getInteger(R.integer.config_dragOutlineMaxAlpha);
2564be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato
2578e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy        Arrays.fill(mDragOutlineAlphas, fromAlphaValue);
2584be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato
2594be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        for (int i = 0; i < mDragOutlineAnims.length; i++) {
260046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy            final InterruptibleInOutAnimator anim =
261046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy                new InterruptibleInOutAnimator(duration, fromAlphaValue, toAlphaValue);
262ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy            anim.getAnimator().setInterpolator(mEaseOutInterpolator);
263046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy            final int thisIndex = i;
264472b281d5cb4f5660df981a6c912266b9f5703feChet Haase            anim.getAnimator().addUpdateListener(new AnimatorUpdateListener() {
265de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                public void onAnimationUpdate(ValueAnimator animation) {
2664be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    final Bitmap outline = (Bitmap)anim.getTag();
2674be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato
2684be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    // If an animation is started and then stopped very quickly, we can still
2694be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    // get spurious updates we've cleared the tag. Guard against this.
2704be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    if (outline == null) {
2713a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka                        @SuppressWarnings("all") // suppress dead code warning
2723a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka                        final boolean debug = false;
2733a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka                        if (debug) {
274fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy                            Object val = animation.getAnimatedValue();
275fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy                            Log.d(TAG, "anim " + thisIndex + " update: " + val +
276fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy                                     ", isStopped " + anim.isStopped());
277fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy                        }
2784be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                        // Try to prevent it from continuing to run
2794be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                        animation.cancel();
2804be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    } else {
281472b281d5cb4f5660df981a6c912266b9f5703feChet Haase                        mDragOutlineAlphas[thisIndex] = (Float) animation.getAnimatedValue();
282d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        CellLayout.this.invalidate(mDragOutlines[thisIndex]);
2834be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    }
284de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                }
285de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy            });
2864be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            // The animation holds a reference to the drag outline bitmap as long is it's
2874be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            // running. This way the bitmap can be GCed when the animations are complete.
288472b281d5cb4f5660df981a6c912266b9f5703feChet Haase            anim.getAnimator().addListener(new AnimatorListenerAdapter() {
2893c4c20fbe682cb4b3ef94f09afe0af09171583f3Michael Jurka                @Override
2904be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                public void onAnimationEnd(Animator animation) {
291472b281d5cb4f5660df981a6c912266b9f5703feChet Haase                    if ((Float) ((ValueAnimator) animation).getAnimatedValue() == 0f) {
2924be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                        anim.setTag(null);
2934be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    }
2944be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                }
2954be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            });
2964be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            mDragOutlineAnims[i] = anim;
297de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy        }
298ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy
29918014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka        mBackgroundRect = new Rect();
300b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        mForegroundRect = new Rect();
301bea15195346bab3c52b0156e92f2b71f0811b210Michael Jurka
302a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets = new ShortcutAndWidgetContainer(context);
303a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.setCellDimensions(mCellWidth, mCellHeight, mWidthGap, mHeightGap);
304a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        addView(mShortcutsAndWidgets);
30518014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka    }
30618014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka
307f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka    static int widthInPortrait(Resources r, int numCells) {
308f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka        // We use this method from Workspace to figure out how many rows/columns Launcher should
309f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka        // have. We ignore the left/right padding on CellLayout because it turns out in our design
310f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka        // the padding extends outside the visible screen size, but it looked fine anyway.
311f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka        int cellWidth = r.getDimensionPixelSize(R.dimen.workspace_cell_width);
3124b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        int minGap = Math.min(r.getDimensionPixelSize(R.dimen.workspace_width_gap),
3134b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                r.getDimensionPixelSize(R.dimen.workspace_height_gap));
314f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka
3154b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        return  minGap * (numCells - 1) + cellWidth * numCells;
316f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka    }
317f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka
318f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka    static int heightInLandscape(Resources r, int numCells) {
319f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka        // We use this method from Workspace to figure out how many rows/columns Launcher should
320f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka        // have. We ignore the left/right padding on CellLayout because it turns out in our design
321f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka        // the padding extends outside the visible screen size, but it looked fine anyway.
322f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka        int cellHeight = r.getDimensionPixelSize(R.dimen.workspace_cell_height);
3234b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        int minGap = Math.min(r.getDimensionPixelSize(R.dimen.workspace_width_gap),
3244b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                r.getDimensionPixelSize(R.dimen.workspace_height_gap));
325f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka
3264b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        return minGap * (numCells - 1) + cellHeight * numCells;
327f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka    }
328f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka
3292801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    public void enableHardwareLayers() {
330a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.enableHardwareLayers();
3312801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    }
3322801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
3332801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    public void setGridSize(int x, int y) {
3342801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        mCountX = x;
3352801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        mCountY = y;
3362801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        mOccupied = new boolean[mCountX][mCountY];
337482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        mTmpOccupied = new boolean[mCountX][mCountY];
3387fbec10b36818f100b631f3d73fe1ad5360975aaAdam Cohen        mTempRectStack.clear();
33976fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        requestLayout();
3402801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    }
3412801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
34296864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy    private void invalidateBubbleTextView(BubbleTextView icon) {
34396864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        final int padding = icon.getPressedOrFocusedBackgroundPadding();
3444b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        invalidate(icon.getLeft() + getPaddingLeft() - padding,
3454b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                icon.getTop() + getPaddingTop() - padding,
3464b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                icon.getRight() + getPaddingLeft() + padding,
3474b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                icon.getBottom() + getPaddingTop() + padding);
34896864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy    }
34996864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy
350b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    void setOverScrollAmount(float r, boolean left) {
351b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        if (left && mOverScrollForegroundDrawable != mOverScrollLeft) {
352b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen            mOverScrollForegroundDrawable = mOverScrollLeft;
353b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        } else if (!left && mOverScrollForegroundDrawable != mOverScrollRight) {
354b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen            mOverScrollForegroundDrawable = mOverScrollRight;
355b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        }
356b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen
357b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        mForegroundAlpha = (int) Math.round((r * 255));
358b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        mOverScrollForegroundDrawable.setAlpha(mForegroundAlpha);
359b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        invalidate();
360b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    }
361b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen
36296864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy    void setPressedOrFocusedIcon(BubbleTextView icon) {
36396864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        // We draw the pressed or focused BubbleTextView's background in CellLayout because it
36496864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        // requires an expanded clip rect (due to the glow's blur radius)
36596864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        BubbleTextView oldIcon = mPressedOrFocusedIcon;
36696864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        mPressedOrFocusedIcon = icon;
36796864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        if (oldIcon != null) {
36896864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy            invalidateBubbleTextView(oldIcon);
36996864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        }
37096864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        if (mPressedOrFocusedIcon != null) {
37196864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy            invalidateBubbleTextView(mPressedOrFocusedIcon);
37296864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        }
37396864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy    }
37496864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy
37533945b21544bc98381df17726a3537c292d8c985Michael Jurka    void setIsDragOverlapping(boolean isDragOverlapping) {
37633945b21544bc98381df17726a3537c292d8c985Michael Jurka        if (mIsDragOverlapping != isDragOverlapping) {
37733945b21544bc98381df17726a3537c292d8c985Michael Jurka            mIsDragOverlapping = isDragOverlapping;
37833945b21544bc98381df17726a3537c292d8c985Michael Jurka            invalidate();
37933945b21544bc98381df17726a3537c292d8c985Michael Jurka        }
38033945b21544bc98381df17726a3537c292d8c985Michael Jurka    }
38133945b21544bc98381df17726a3537c292d8c985Michael Jurka
38233945b21544bc98381df17726a3537c292d8c985Michael Jurka    boolean getIsDragOverlapping() {
38333945b21544bc98381df17726a3537c292d8c985Michael Jurka        return mIsDragOverlapping;
38433945b21544bc98381df17726a3537c292d8c985Michael Jurka    }
38533945b21544bc98381df17726a3537c292d8c985Michael Jurka
386ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen    protected void setOverscrollTransformsDirty(boolean dirty) {
387ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen        mScrollingTransformsDirty = dirty;
388ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen    }
389ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen
390ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen    protected void resetOverscrollTransforms() {
391ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen        if (mScrollingTransformsDirty) {
392ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            setOverscrollTransformsDirty(false);
393ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            setTranslationX(0);
394ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            setRotationY(0);
395ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            // It doesn't matter if we pass true or false here, the important thing is that we
396ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            // pass 0, which results in the overscroll drawable not being drawn any more.
397ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            setOverScrollAmount(0, false);
398ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            setPivotX(getMeasuredWidth() / 2);
399ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            setPivotY(getMeasuredHeight() / 2);
400ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen        }
401ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen    }
402ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen
403a6abce8464b57ce91e8f083951ad263370fc2da8Romain Guy    @Override
4041262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy    protected void onDraw(Canvas canvas) {
4053e7c7634531302271270c8cf418abc959d621cbcMichael Jurka        // When we're large, we are either drawn in a "hover" state (ie when dragging an item to
4063e7c7634531302271270c8cf418abc959d621cbcMichael Jurka        // a neighboring page) or with just a normal background (if backgroundAlpha > 0.0f)
4073e7c7634531302271270c8cf418abc959d621cbcMichael Jurka        // When we're small, we are either drawn normally or in the "accepts drops" state (during
4083e7c7634531302271270c8cf418abc959d621cbcMichael Jurka        // a drag). However, we also drag the mini hover background *over* one of those two
4093e7c7634531302271270c8cf418abc959d621cbcMichael Jurka        // backgrounds
410b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung        if (mBackgroundAlpha > 0.0f) {
411f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen            Drawable bg;
41233945b21544bc98381df17726a3537c292d8c985Michael Jurka
41333945b21544bc98381df17726a3537c292d8c985Michael Jurka            if (mIsDragOverlapping) {
41433945b21544bc98381df17726a3537c292d8c985Michael Jurka                // In the mini case, we draw the active_glow bg *over* the active background
415bdf78559f223ac11e01e3311edd5a48a80383e1eMichael Jurka                bg = mActiveGlowBackground;
416f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen            } else {
417bdf78559f223ac11e01e3311edd5a48a80383e1eMichael Jurka                bg = mNormalBackground;
418f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen            }
41933945b21544bc98381df17726a3537c292d8c985Michael Jurka
42033945b21544bc98381df17726a3537c292d8c985Michael Jurka            bg.setAlpha((int) (mBackgroundAlpha * mBackgroundAlphaMultiplier * 255));
42133945b21544bc98381df17726a3537c292d8c985Michael Jurka            bg.setBounds(mBackgroundRect);
42233945b21544bc98381df17726a3537c292d8c985Michael Jurka            bg.draw(canvas);
423a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka        }
42431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
425de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy        if (mCrosshairsVisibility > 0.0f) {
426de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy            final int countX = mCountX;
427de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy            final int countY = mCountY;
428de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy
429de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy            final float MAX_ALPHA = 0.4f;
430de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy            final int MAX_VISIBLE_DISTANCE = 600;
431de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy            final float DISTANCE_MULTIPLIER = 0.002f;
432de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy
433de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy            final Drawable d = mCrosshairsDrawable;
434de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy            final int width = d.getIntrinsicWidth();
435de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy            final int height = d.getIntrinsicHeight();
436de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy
4374b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung            int x = getPaddingLeft() - (mWidthGap / 2) - (width / 2);
438de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy            for (int col = 0; col <= countX; col++) {
4394b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                int y = getPaddingTop() - (mHeightGap / 2) - (height / 2);
440de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                for (int row = 0; row <= countY; row++) {
441de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                    mTmpPointF.set(x - mDragCenter.x, y - mDragCenter.y);
442de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                    float dist = mTmpPointF.length();
443de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                    // Crosshairs further from the drag point are more faint
444de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                    float alpha = Math.min(MAX_ALPHA,
445de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                            DISTANCE_MULTIPLIER * (MAX_VISIBLE_DISTANCE - dist));
446de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                    if (alpha > 0.0f) {
447de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                        d.setBounds(x, y, x + width, y + height);
448de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                        d.setAlpha((int) (alpha * 255 * mCrosshairsVisibility));
449de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                        d.draw(canvas);
450de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                    }
451de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                    y += mCellHeight + mHeightGap;
452de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                }
453de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                x += mCellWidth + mWidthGap;
454de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy            }
4554be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        }
456150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung
4578e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy        final Paint paint = mDragOutlinePaint;
4584be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        for (int i = 0; i < mDragOutlines.length; i++) {
459472b281d5cb4f5660df981a6c912266b9f5703feChet Haase            final float alpha = mDragOutlineAlphas[i];
4604be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            if (alpha > 0) {
461d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                final Rect r = mDragOutlines[i];
4624be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                final Bitmap b = (Bitmap) mDragOutlineAnims[i].getTag();
463472b281d5cb4f5660df981a6c912266b9f5703feChet Haase                paint.setAlpha((int)(alpha + .5f));
464d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                canvas.drawBitmap(b, null, r, paint);
465150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung            }
4666569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        }
46796864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy
46896864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        // We draw the pressed or focused BubbleTextView's background in CellLayout because it
46996864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        // requires an expanded clip rect (due to the glow's blur radius)
47096864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        if (mPressedOrFocusedIcon != null) {
47196864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy            final int padding = mPressedOrFocusedIcon.getPressedOrFocusedBackgroundPadding();
47296864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy            final Bitmap b = mPressedOrFocusedIcon.getPressedOrFocusedBackground();
47396864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy            if (b != null) {
47496864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy                canvas.drawBitmap(b,
4754b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                        mPressedOrFocusedIcon.getLeft() + getPaddingLeft() - padding,
4764b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                        mPressedOrFocusedIcon.getTop() + getPaddingTop() - padding,
47796864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy                        null);
47896864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy            }
47996864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        }
48069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
481482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (DEBUG_VISUALIZE_OCCUPIED) {
482482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            int[] pt = new int[2];
483482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            ColorDrawable cd = new ColorDrawable(Color.RED);
484482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            cd.setBounds(0, 0, 80, 80);
485482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            for (int i = 0; i < mCountX; i++) {
486482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                for (int j = 0; j < mCountY; j++) {
487482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    if (mOccupied[i][j]) {
488482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        cellToPoint(i, j, pt);
489482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        canvas.save();
490482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        canvas.translate(pt[0], pt[1]);
491482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        cd.draw(canvas);
492482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        canvas.restore();
493482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    }
494482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                }
495482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
496482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
497482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
49869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        // The folder outer / inner ring image(s)
49969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        for (int i = 0; i < mFolderOuterRings.size(); i++) {
50069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            FolderRingAnimator fra = mFolderOuterRings.get(i);
50169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
50269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            // Draw outer ring
50369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            Drawable d = FolderRingAnimator.sSharedOuterRingDrawable;
50469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            int width = (int) fra.getOuterRingSize();
50569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            int height = width;
50669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            cellToPoint(fra.mCellX, fra.mCellY, mTempLocation);
50769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
50869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            int centerX = mTempLocation[0] + mCellWidth / 2;
50969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            int centerY = mTempLocation[1] + FolderRingAnimator.sPreviewSize / 2;
51069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
51169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            canvas.save();
51269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            canvas.translate(centerX - width / 2, centerY - height / 2);
51369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            d.setBounds(0, 0, width, height);
51469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            d.draw(canvas);
51569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            canvas.restore();
51669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
51769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            // Draw inner ring
51869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            d = FolderRingAnimator.sSharedInnerRingDrawable;
51969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            width = (int) fra.getInnerRingSize();
52069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            height = width;
52169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            cellToPoint(fra.mCellX, fra.mCellY, mTempLocation);
52269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
52369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            centerX = mTempLocation[0] + mCellWidth / 2;
52469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            centerY = mTempLocation[1] + FolderRingAnimator.sPreviewSize / 2;
52569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            canvas.save();
52669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            canvas.translate(centerX - width / 2, centerY - width / 2);
52769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            d.setBounds(0, 0, width, height);
52869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            d.draw(canvas);
52969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            canvas.restore();
53069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        }
531c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen
532c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        if (mFolderLeaveBehindCell[0] >= 0 && mFolderLeaveBehindCell[1] >= 0) {
533c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            Drawable d = FolderIcon.sSharedFolderLeaveBehind;
534c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            int width = d.getIntrinsicWidth();
535c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            int height = d.getIntrinsicHeight();
536c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen
537c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            cellToPoint(mFolderLeaveBehindCell[0], mFolderLeaveBehindCell[1], mTempLocation);
538c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            int centerX = mTempLocation[0] + mCellWidth / 2;
539c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            int centerY = mTempLocation[1] + FolderRingAnimator.sPreviewSize / 2;
540c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen
541c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            canvas.save();
542c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            canvas.translate(centerX - width / 2, centerY - width / 2);
543c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            d.setBounds(0, 0, width, height);
544c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            d.draw(canvas);
545c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            canvas.restore();
546c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        }
54769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen    }
54869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
549b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    @Override
550b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    protected void dispatchDraw(Canvas canvas) {
551b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        super.dispatchDraw(canvas);
552b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        if (mForegroundAlpha > 0) {
553b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen            mOverScrollForegroundDrawable.setBounds(mForegroundRect);
554b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen            Paint p = ((NinePatchDrawable) mOverScrollForegroundDrawable).getPaint();
555b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen            p.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.ADD));
556b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen            mOverScrollForegroundDrawable.draw(canvas);
557b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen            p.setXfermode(null);
558b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        }
559b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    }
560b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen
56169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen    public void showFolderAccept(FolderRingAnimator fra) {
56269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        mFolderOuterRings.add(fra);
56369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen    }
56469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
56569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen    public void hideFolderAccept(FolderRingAnimator fra) {
56669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        if (mFolderOuterRings.contains(fra)) {
56769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            mFolderOuterRings.remove(fra);
56869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        }
56969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        invalidate();
5706569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    }
5716569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
572c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen    public void setFolderLeaveBehindCell(int x, int y) {
573c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        mFolderLeaveBehindCell[0] = x;
574c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        mFolderLeaveBehindCell[1] = y;
575c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        invalidate();
576c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen    }
577c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen
578c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen    public void clearFolderLeaveBehind() {
579c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        mFolderLeaveBehindCell[0] = -1;
580c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        mFolderLeaveBehindCell[1] = -1;
581c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        invalidate();
582c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen    }
583c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen
5846569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    @Override
585e6235dd225404239b55c459245543f3302326112Michael Jurka    public boolean shouldDelayChildPressedState() {
586e6235dd225404239b55c459245543f3302326112Michael Jurka        return false;
587e6235dd225404239b55c459245543f3302326112Michael Jurka    }
588e6235dd225404239b55c459245543f3302326112Michael Jurka
589e6235dd225404239b55c459245543f3302326112Michael Jurka    @Override
59083f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey    public void cancelLongPress() {
59183f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey        super.cancelLongPress();
59283f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey
59383f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey        // Cancel long press for all children
59483f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey        final int count = getChildCount();
59583f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey        for (int i = 0; i < count; i++) {
59683f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey            final View child = getChildAt(i);
59783f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey            child.cancelLongPress();
59883f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey        }
59983f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey    }
60083f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey
601dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    public void setOnInterceptTouchListener(View.OnTouchListener listener) {
602dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka        mInterceptTouchListener = listener;
603dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    }
604dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka
60531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    int getCountX() {
606d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        return mCountX;
60731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
60831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
60931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    int getCountY() {
610d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        return mCountY;
61131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
61231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
6130dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn    public void setIsHotseat(boolean isHotseat) {
6140dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn        mIsHotseat = isHotseat;
6150dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn    }
6160dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn
617eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung    public float getChildrenScale() {
618eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung        return mIsHotseat ? mHotseatChildScale : mChildScale;
619eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung    }
620eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung
621f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka    public boolean addViewToCellLayout(
622f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka            View child, int index, int childId, LayoutParams params, boolean markCells) {
6230dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn        return addViewToCellLayout(child, index, childId, params, markCells, false);
6240dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn    }
6250dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn
626eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung    private void scaleChild(BubbleTextView bubbleChild, float pivot, float scale) {
627bc239a15464f543a41b960b946aa77258454efafAndrew Flynn        // If we haven't measured the child yet, do it now
628bc239a15464f543a41b960b946aa77258454efafAndrew Flynn        // (this happens if we're being dropped from all-apps
629bc239a15464f543a41b960b946aa77258454efafAndrew Flynn        if (bubbleChild.getLayoutParams() instanceof LayoutParams &&
630bc239a15464f543a41b960b946aa77258454efafAndrew Flynn                (bubbleChild.getMeasuredWidth() | bubbleChild.getMeasuredHeight()) == 0) {
631a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            getShortcutsAndWidgets().measureChild(bubbleChild);
632bc239a15464f543a41b960b946aa77258454efafAndrew Flynn        }
633bc239a15464f543a41b960b946aa77258454efafAndrew Flynn
634bc239a15464f543a41b960b946aa77258454efafAndrew Flynn        bubbleChild.setScaleX(scale);
635bc239a15464f543a41b960b946aa77258454efafAndrew Flynn        bubbleChild.setScaleY(scale);
636bc239a15464f543a41b960b946aa77258454efafAndrew Flynn    }
637bc239a15464f543a41b960b946aa77258454efafAndrew Flynn
638bc239a15464f543a41b960b946aa77258454efafAndrew Flynn    private void resetChild(BubbleTextView bubbleChild) {
639bc239a15464f543a41b960b946aa77258454efafAndrew Flynn        bubbleChild.setScaleX(1f);
640bc239a15464f543a41b960b946aa77258454efafAndrew Flynn        bubbleChild.setScaleY(1f);
641bc239a15464f543a41b960b946aa77258454efafAndrew Flynn
642bc239a15464f543a41b960b946aa77258454efafAndrew Flynn        bubbleChild.setTextColor(getResources().getColor(R.color.workspace_icon_text_color));
643bc239a15464f543a41b960b946aa77258454efafAndrew Flynn    }
644bc239a15464f543a41b960b946aa77258454efafAndrew Flynn
6450dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn    public boolean addViewToCellLayout(View child, int index, int childId, LayoutParams params,
6460dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn            boolean markCells, boolean allApps) {
647aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        final LayoutParams lp = params;
648aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
6490dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn        // Hotseat icons - scale down and remove text
6500dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn        // Don't scale the all apps button
6510dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn        // scale percent set to -1 means do not scale
6520dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn        // Only scale BubbleTextViews
6530dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn        if (child instanceof BubbleTextView) {
6540dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn            BubbleTextView bubbleChild = (BubbleTextView) child;
6550dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn
656bc239a15464f543a41b960b946aa77258454efafAndrew Flynn            // Start the child with 100% scale and visible text
657bc239a15464f543a41b960b946aa77258454efafAndrew Flynn            resetChild(bubbleChild);
658bc239a15464f543a41b960b946aa77258454efafAndrew Flynn
659eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung            if (mIsHotseat && !allApps && mHotseatChildScale >= 0) {
660bc239a15464f543a41b960b946aa77258454efafAndrew Flynn                // Scale/make transparent for a hotseat
661eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                scaleChild(bubbleChild, 0f, mHotseatChildScale);
6620dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn
663bc239a15464f543a41b960b946aa77258454efafAndrew Flynn                bubbleChild.setTextColor(getResources().getColor(android.R.color.transparent));
664eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung            } else if (mChildScale >= 0) {
665bc239a15464f543a41b960b946aa77258454efafAndrew Flynn                // Else possibly still scale it if we need to for smaller icons
666eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                scaleChild(bubbleChild, 0f, mChildScale);
6670dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn            }
6680dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn        }
6690dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn
67031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // Generate an id for each view, this assumes we have at most 256x256 cells
67131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // per workspace screen
672d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        if (lp.cellX >= 0 && lp.cellX <= mCountX - 1 && lp.cellY >= 0 && lp.cellY <= mCountY - 1) {
673aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            // If the horizontal or vertical span is set to -1, it is taken to
674aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            // mean that it spans the extent of the CellLayout
675d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen            if (lp.cellHSpan < 0) lp.cellHSpan = mCountX;
676d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen            if (lp.cellVSpan < 0) lp.cellVSpan = mCountY;
677aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
678aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            child.setId(childId);
67931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
680a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            mShortcutsAndWidgets.addView(child, index, lp);
681dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka
682f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka            if (markCells) markCellsAsOccupiedForView(child);
6830280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
684aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            return true;
685aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        }
686aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        return false;
68731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
6883e7c7634531302271270c8cf418abc959d621cbcMichael Jurka
68931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
6900280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public void removeAllViews() {
6910280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        clearOccupiedCells();
692a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.removeAllViews();
6930280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
6940280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
6950280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    @Override
6960280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public void removeAllViewsInLayout() {
697a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        if (mShortcutsAndWidgets.getChildCount() > 0) {
6987cfc2825c3a1029f962d2fc387ae2eaa85b51798Michael Jurka            clearOccupiedCells();
699a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            mShortcutsAndWidgets.removeAllViewsInLayout();
7007cfc2825c3a1029f962d2fc387ae2eaa85b51798Michael Jurka        }
7010280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
7020280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
703f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka    public void removeViewWithoutMarkingCells(View view) {
704a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.removeView(view);
705f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka    }
706f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka
7070280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    @Override
7080280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public void removeView(View view) {
7090280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        markCellsAsUnoccupiedForView(view);
710a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.removeView(view);
7110280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
7120280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
7130280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    @Override
7140280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public void removeViewAt(int index) {
715a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        markCellsAsUnoccupiedForView(mShortcutsAndWidgets.getChildAt(index));
716a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.removeViewAt(index);
7170280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
7180280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
7190280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    @Override
7200280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public void removeViewInLayout(View view) {
7210280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        markCellsAsUnoccupiedForView(view);
722a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.removeViewInLayout(view);
7230280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
7240280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
7250280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    @Override
7260280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public void removeViews(int start, int count) {
7270280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        for (int i = start; i < start + count; i++) {
728a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            markCellsAsUnoccupiedForView(mShortcutsAndWidgets.getChildAt(i));
7290280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        }
730a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.removeViews(start, count);
7310280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
7320280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
7330280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    @Override
7340280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public void removeViewsInLayout(int start, int count) {
7350280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        for (int i = start; i < start + count; i++) {
736a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            markCellsAsUnoccupiedForView(mShortcutsAndWidgets.getChildAt(i));
7370280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        }
738a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.removeViewsInLayout(start, count);
739abded66084680bb31cc7ea403c88f44f79a3c884Michael Jurka    }
740abded66084680bb31cc7ea403c88f44f79a3c884Michael Jurka
74131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
74231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    protected void onAttachedToWindow() {
74331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        super.onAttachedToWindow();
74431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        mCellInfo.screen = ((ViewGroup) getParent()).indexOfChild(this);
74531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
74631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
747af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka    public void setTagToCellInfoForPoint(int touchX, int touchY) {
74831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        final CellInfo cellInfo = mCellInfo;
749eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung        Rect frame = mRect;
7508b805b17158886035b38261eb611d8641701ae43Michael Jurka        final int x = touchX + getScrollX();
7518b805b17158886035b38261eb611d8641701ae43Michael Jurka        final int y = touchY + getScrollY();
752a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        final int count = mShortcutsAndWidgets.getChildCount();
75331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
754af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka        boolean found = false;
755af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka        for (int i = count - 1; i >= 0; i--) {
756a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            final View child = mShortcutsAndWidgets.getChildAt(i);
757d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
758af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka
7591b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen            if ((child.getVisibility() == VISIBLE || child.getAnimation() != null) &&
7601b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen                    lp.isLockedToGrid) {
761af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                child.getHitRect(frame);
7620be025d64c1f84138fe430a58875886e66aae767Winson Chung
763eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                float scale = child.getScaleX();
764eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                frame = new Rect(child.getLeft(), child.getTop(), child.getRight(),
765eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                        child.getBottom());
7660be025d64c1f84138fe430a58875886e66aae767Winson Chung                // The child hit rect is relative to the CellLayoutChildren parent, so we need to
7670be025d64c1f84138fe430a58875886e66aae767Winson Chung                // offset that by this CellLayout's padding to test an (x,y) point that is relative
7680be025d64c1f84138fe430a58875886e66aae767Winson Chung                // to this view.
7698b805b17158886035b38261eb611d8641701ae43Michael Jurka                frame.offset(getPaddingLeft(), getPaddingTop());
770eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                frame.inset((int) (frame.width() * (1f - scale) / 2),
771eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                        (int) (frame.height() * (1f - scale) / 2));
7720be025d64c1f84138fe430a58875886e66aae767Winson Chung
773af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                if (frame.contains(x, y)) {
774af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                    cellInfo.cell = child;
775af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                    cellInfo.cellX = lp.cellX;
776af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                    cellInfo.cellY = lp.cellY;
777af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                    cellInfo.spanX = lp.cellHSpan;
778af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                    cellInfo.spanY = lp.cellVSpan;
779af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                    found = true;
780af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                    break;
78131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                }
78231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            }
783af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka        }
784aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
785d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka        mLastDownOnOccupiedCell = found;
786d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka
787af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka        if (!found) {
7880be025d64c1f84138fe430a58875886e66aae767Winson Chung            final int cellXY[] = mTmpXY;
789af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka            pointToCellExact(x, y, cellXY);
79031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
791af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka            cellInfo.cell = null;
792af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka            cellInfo.cellX = cellXY[0];
793af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka            cellInfo.cellY = cellXY[1];
794af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka            cellInfo.spanX = 1;
795af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka            cellInfo.spanY = 1;
796af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka        }
797af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka        setTag(cellInfo);
798af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka    }
79931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
800af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka    @Override
801af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka    public boolean onInterceptTouchEvent(MotionEvent ev) {
802c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        // First we clear the tag to ensure that on every touch down we start with a fresh slate,
803c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        // even in the case where we return early. Not clearing here was causing bugs whereby on
804c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        // long-press we'd end up picking up an item from a previous drag operation.
805c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        final int action = ev.getAction();
806c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen
807c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        if (action == MotionEvent.ACTION_DOWN) {
808c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen            clearTagCellInfo();
809c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        }
810c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen
811dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka        if (mInterceptTouchListener != null && mInterceptTouchListener.onTouch(this, ev)) {
812dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka            return true;
813dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka        }
81431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
815af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka        if (action == MotionEvent.ACTION_DOWN) {
816af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka            setTagToCellInfoForPoint((int) ev.getX(), (int) ev.getY());
81731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
818eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung
81931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        return false;
82031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
82131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
822c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen    private void clearTagCellInfo() {
823c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        final CellInfo cellInfo = mCellInfo;
824c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        cellInfo.cell = null;
825c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        cellInfo.cellX = -1;
826c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        cellInfo.cellY = -1;
827c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        cellInfo.spanX = 0;
828c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        cellInfo.spanY = 0;
829c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        setTag(cellInfo);
830c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen    }
831c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen
83231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public CellInfo getTag() {
8330280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        return (CellInfo) super.getTag();
83431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
83531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
8366569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    /**
837aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     * Given a point, return the cell that strictly encloses that point
83831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param x X coordinate of the point
83931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param y Y coordinate of the point
84031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param result Array of 2 ints to hold the x and y coordinate of the cell
84131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
84231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    void pointToCellExact(int x, int y, int[] result) {
8434b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int hStartPadding = getPaddingLeft();
8444b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int vStartPadding = getPaddingTop();
84531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
84631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        result[0] = (x - hStartPadding) / (mCellWidth + mWidthGap);
84731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        result[1] = (y - vStartPadding) / (mCellHeight + mHeightGap);
84831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
849d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        final int xAxis = mCountX;
850d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        final int yAxis = mCountY;
85131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
85231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        if (result[0] < 0) result[0] = 0;
85331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        if (result[0] >= xAxis) result[0] = xAxis - 1;
85431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        if (result[1] < 0) result[1] = 0;
85531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        if (result[1] >= yAxis) result[1] = yAxis - 1;
85631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
857aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
85831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
85931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * Given a point, return the cell that most closely encloses that point
86031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param x X coordinate of the point
86131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param y Y coordinate of the point
86231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param result Array of 2 ints to hold the x and y coordinate of the cell
86331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
86431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    void pointToCellRounded(int x, int y, int[] result) {
86531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        pointToCellExact(x + (mCellWidth / 2), y + (mCellHeight / 2), result);
86631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
86731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
86831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
86931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * Given a cell coordinate, return the point that represents the upper left corner of that cell
870aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     *
871aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     * @param cellX X coordinate of the cell
87231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param cellY Y coordinate of the cell
873aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     *
87431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param result Array of 2 ints to hold the x and y coordinate of the point
87531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
87631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    void cellToPoint(int cellX, int cellY, int[] result) {
8774b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int hStartPadding = getPaddingLeft();
8784b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int vStartPadding = getPaddingTop();
87931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
88031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        result[0] = hStartPadding + cellX * (mCellWidth + mWidthGap);
88131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        result[1] = vStartPadding + cellY * (mCellHeight + mHeightGap);
88231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
88331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
884e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen    /**
885482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * Given a cell coordinate, return the point that represents the center of the cell
886e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen     *
887e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen     * @param cellX X coordinate of the cell
888e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen     * @param cellY Y coordinate of the cell
889e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen     *
890e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen     * @param result Array of 2 ints to hold the x and y coordinate of the point
891e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen     */
892e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen    void cellToCenterPoint(int cellX, int cellY, int[] result) {
89347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        regionToCenterPoint(cellX, cellY, 1, 1, result);
89447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    }
89547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
89647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    /**
89747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * Given a cell coordinate and span return the point that represents the center of the regio
89847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     *
89947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param cellX X coordinate of the cell
90047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param cellY Y coordinate of the cell
90147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     *
90247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param result Array of 2 ints to hold the x and y coordinate of the point
90347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     */
90447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    void regionToCenterPoint(int cellX, int cellY, int spanX, int spanY, int[] result) {
9054b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int hStartPadding = getPaddingLeft();
9064b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int vStartPadding = getPaddingTop();
90747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        result[0] = hStartPadding + cellX * (mCellWidth + mWidthGap) +
90847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                (spanX * mCellWidth + (spanX - 1) * mWidthGap) / 2;
90947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        result[1] = vStartPadding + cellY * (mCellHeight + mHeightGap) +
91047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                (spanY * mCellHeight + (spanY - 1) * mHeightGap) / 2;
911e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen    }
912e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen
91319f3792523fe2d55ea791a9286398a6120920690Adam Cohen     /**
91419f3792523fe2d55ea791a9286398a6120920690Adam Cohen     * Given a cell coordinate and span fills out a corresponding pixel rect
91519f3792523fe2d55ea791a9286398a6120920690Adam Cohen     *
91619f3792523fe2d55ea791a9286398a6120920690Adam Cohen     * @param cellX X coordinate of the cell
91719f3792523fe2d55ea791a9286398a6120920690Adam Cohen     * @param cellY Y coordinate of the cell
91819f3792523fe2d55ea791a9286398a6120920690Adam Cohen     * @param result Rect in which to write the result
91919f3792523fe2d55ea791a9286398a6120920690Adam Cohen     */
92019f3792523fe2d55ea791a9286398a6120920690Adam Cohen     void regionToRect(int cellX, int cellY, int spanX, int spanY, Rect result) {
92119f3792523fe2d55ea791a9286398a6120920690Adam Cohen        final int hStartPadding = getPaddingLeft();
92219f3792523fe2d55ea791a9286398a6120920690Adam Cohen        final int vStartPadding = getPaddingTop();
92319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        final int left = hStartPadding + cellX * (mCellWidth + mWidthGap);
92419f3792523fe2d55ea791a9286398a6120920690Adam Cohen        final int top = vStartPadding + cellY * (mCellHeight + mHeightGap);
92519f3792523fe2d55ea791a9286398a6120920690Adam Cohen        result.set(left, top, left + (spanX * mCellWidth + (spanX - 1) * mWidthGap),
92619f3792523fe2d55ea791a9286398a6120920690Adam Cohen                top + (spanY * mCellHeight + (spanY - 1) * mHeightGap));
92719f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
92819f3792523fe2d55ea791a9286398a6120920690Adam Cohen
929482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public float getDistanceFromCell(float x, float y, int[] cell) {
930482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        cellToCenterPoint(cell[0], cell[1], mTmpPoint);
931482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        float distance = (float) Math.sqrt( Math.pow(x - mTmpPoint[0], 2) +
932482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                Math.pow(y - mTmpPoint[1], 2));
933482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return distance;
934482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
935482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
93684f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy    int getCellWidth() {
93784f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy        return mCellWidth;
93884f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy    }
93984f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy
94084f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy    int getCellHeight() {
94184f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy        return mCellHeight;
94284f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy    }
94384f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy
944d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    int getWidthGap() {
945d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        return mWidthGap;
946d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    }
947d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
948d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    int getHeightGap() {
949d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        return mHeightGap;
950d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    }
951d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
9527f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen    Rect getContentRect(Rect r) {
9537f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        if (r == null) {
9547f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            r = new Rect();
9557f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
9567f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        int left = getPaddingLeft();
9577f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        int top = getPaddingTop();
9588b805b17158886035b38261eb611d8641701ae43Michael Jurka        int right = left + getWidth() - getPaddingLeft() - getPaddingRight();
9598b805b17158886035b38261eb611d8641701ae43Michael Jurka        int bottom = top + getHeight() - getPaddingTop() - getPaddingBottom();
9607f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        r.set(left, top, right, bottom);
9617f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        return r;
9627f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen    }
9637f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
96431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
96531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
96631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // TODO: currently ignoring padding
967aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
96831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
969aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
970aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
97131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
97231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int heightSpecSize =  MeasureSpec.getSize(heightMeasureSpec);
973aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
97431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        if (widthSpecMode == MeasureSpec.UNSPECIFIED || heightSpecMode == MeasureSpec.UNSPECIFIED) {
97531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            throw new RuntimeException("CellLayout cannot have UNSPECIFIED dimensions");
97631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
97731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
978d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        int numWidthGaps = mCountX - 1;
979d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        int numHeightGaps = mCountY - 1;
980d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen
981234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen        if (mOriginalWidthGap < 0 || mOriginalHeightGap < 0) {
9828b805b17158886035b38261eb611d8641701ae43Michael Jurka            int hSpace = widthSpecSize - getPaddingLeft() - getPaddingRight();
9838b805b17158886035b38261eb611d8641701ae43Michael Jurka            int vSpace = heightSpecSize - getPaddingTop() - getPaddingBottom();
9844b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung            int hFreeSpace = hSpace - (mCountX * mOriginalCellWidth);
9854b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung            int vFreeSpace = vSpace - (mCountY * mOriginalCellHeight);
9864b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung            mWidthGap = Math.min(mMaxGap, numWidthGaps > 0 ? (hFreeSpace / numWidthGaps) : 0);
9874b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung            mHeightGap = Math.min(mMaxGap,numHeightGaps > 0 ? (vFreeSpace / numHeightGaps) : 0);
988a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            mShortcutsAndWidgets.setCellDimensions(mCellWidth, mCellHeight, mWidthGap, mHeightGap);
989234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen        } else {
990234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen            mWidthGap = mOriginalWidthGap;
991234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen            mHeightGap = mOriginalHeightGap;
992ece7f5b3b55cab646941123e03589241a61678e2Winson Chung        }
9935f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka
9948c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka        // Initial values correspond to widthSpecMode == MeasureSpec.EXACTLY
9958c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka        int newWidth = widthSpecSize;
9968c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka        int newHeight = heightSpecSize;
9978c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka        if (widthSpecMode == MeasureSpec.AT_MOST) {
9988b805b17158886035b38261eb611d8641701ae43Michael Jurka            newWidth = getPaddingLeft() + getPaddingRight() + (mCountX * mCellWidth) +
9998c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka                ((mCountX - 1) * mWidthGap);
10008b805b17158886035b38261eb611d8641701ae43Michael Jurka            newHeight = getPaddingTop() + getPaddingBottom() + (mCountY * mCellHeight) +
10018c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka                ((mCountY - 1) * mHeightGap);
10028c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka            setMeasuredDimension(newWidth, newHeight);
10038c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka        }
100431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
10058c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka        int count = getChildCount();
100631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        for (int i = 0; i < count; i++) {
100731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            View child = getChildAt(i);
10088b805b17158886035b38261eb611d8641701ae43Michael Jurka            int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(newWidth - getPaddingLeft() -
10098b805b17158886035b38261eb611d8641701ae43Michael Jurka                    getPaddingRight(), MeasureSpec.EXACTLY);
10108b805b17158886035b38261eb611d8641701ae43Michael Jurka            int childheightMeasureSpec = MeasureSpec.makeMeasureSpec(newHeight - getPaddingTop() -
10118b805b17158886035b38261eb611d8641701ae43Michael Jurka                    getPaddingBottom(), MeasureSpec.EXACTLY);
101231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            child.measure(childWidthMeasureSpec, childheightMeasureSpec);
101331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
10148c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka        setMeasuredDimension(newWidth, newHeight);
101531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
101631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
101731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
101828750fba6a2d141eb9a1e566718c17236030b815Michael Jurka    protected void onLayout(boolean changed, int l, int t, int r, int b) {
101931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int count = getChildCount();
102031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        for (int i = 0; i < count; i++) {
10218c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka            View child = getChildAt(i);
10228b805b17158886035b38261eb611d8641701ae43Michael Jurka            child.layout(getPaddingLeft(), getPaddingTop(),
10238b805b17158886035b38261eb611d8641701ae43Michael Jurka                    r - l - getPaddingRight(), b - t - getPaddingBottom());
102431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
102531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
102631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
102731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
1028dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
1029dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka        super.onSizeChanged(w, h, oldw, oldh);
103018014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka        mBackgroundRect.set(0, 0, w, h);
1031b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        mForegroundRect.set(mForegroundPadding, mForegroundPadding,
1032b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen                w - 2 * mForegroundPadding, h - 2 * mForegroundPadding);
1033dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    }
1034dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka
1035dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    @Override
103631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    protected void setChildrenDrawingCacheEnabled(boolean enabled) {
1037a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.setChildrenDrawingCacheEnabled(enabled);
103831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
103931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
104031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
104131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    protected void setChildrenDrawnWithCacheEnabled(boolean enabled) {
1042a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.setChildrenDrawnWithCacheEnabled(enabled);
104331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
104431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
10455f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka    public float getBackgroundAlpha() {
10465f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka        return mBackgroundAlpha;
1047dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    }
1048dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka
10491b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen    public void setBackgroundAlphaMultiplier(float multiplier) {
10501b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen        mBackgroundAlphaMultiplier = multiplier;
10511b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen    }
10521b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen
1053ddb821981e0919bbd3b4c9a2b6aa1811d6c86bb6Adam Cohen    public float getBackgroundAlphaMultiplier() {
1054ddb821981e0919bbd3b4c9a2b6aa1811d6c86bb6Adam Cohen        return mBackgroundAlphaMultiplier;
1055ddb821981e0919bbd3b4c9a2b6aa1811d6c86bb6Adam Cohen    }
1056ddb821981e0919bbd3b4c9a2b6aa1811d6c86bb6Adam Cohen
10575f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka    public void setBackgroundAlpha(float alpha) {
1058afaa05014e0bf3ed1192f9ddec2af4283bc50248Michael Jurka        if (mBackgroundAlpha != alpha) {
1059afaa05014e0bf3ed1192f9ddec2af4283bc50248Michael Jurka            mBackgroundAlpha = alpha;
1060afaa05014e0bf3ed1192f9ddec2af4283bc50248Michael Jurka            invalidate();
1061afaa05014e0bf3ed1192f9ddec2af4283bc50248Michael Jurka        }
1062dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    }
1063dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka
1064a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka    public void setShortcutAndWidgetAlpha(float alpha) {
10650142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka        final int childCount = getChildCount();
10660142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka        for (int i = 0; i < childCount; i++) {
1067dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka            getChildAt(i).setAlpha(alpha);
1068dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka        }
1069dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    }
1070dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka
1071a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka    public ShortcutAndWidgetContainer getShortcutsAndWidgets() {
1072a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        if (getChildCount() > 0) {
1073a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            return (ShortcutAndWidgetContainer) getChildAt(0);
1074a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        }
1075a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        return null;
1076a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka    }
1077a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka
1078440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy    public View getChildAt(int x, int y) {
1079a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        return mShortcutsAndWidgets.getChildAt(x, y);
1080440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy    }
1081440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy
108276fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    public boolean animateChildToPosition(final View child, int cellX, int cellY, int duration,
1083482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            int delay, boolean permanent, boolean adjustOccupied) {
1084a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        ShortcutAndWidgetContainer clc = getShortcutsAndWidgets();
1085482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        boolean[][] occupied = mOccupied;
1086482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (!permanent) {
1087482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            occupied = mTmpOccupied;
1088482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1089482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
109019f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if (clc.indexOfChild(child) != -1) {
1091bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
1092bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            final ItemInfo info = (ItemInfo) child.getTag();
1093bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen
1094bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            // We cancel any existing animations
1095bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            if (mReorderAnimators.containsKey(lp)) {
1096bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                mReorderAnimators.get(lp).cancel();
1097bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                mReorderAnimators.remove(lp);
1098bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            }
1099bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen
1100482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            final int oldX = lp.x;
1101482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            final int oldY = lp.y;
1102482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (adjustOccupied) {
1103482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                occupied[lp.cellX][lp.cellY] = false;
1104482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                occupied[cellX][cellY] = true;
1105482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1106bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            lp.isLockedToGrid = true;
1107482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (permanent) {
1108482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                lp.cellX = info.cellX = cellX;
1109482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                lp.cellY = info.cellY = cellY;
1110482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            } else {
1111482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                lp.tmpCellX = cellX;
1112482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                lp.tmpCellY = cellY;
1113482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1114bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            clc.setupLp(lp);
1115bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            lp.isLockedToGrid = false;
1116482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            final int newX = lp.x;
1117482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            final int newY = lp.y;
1118bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen
111976fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen            lp.x = oldX;
112076fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen            lp.y = oldY;
112176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
1122482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            // Exit early if we're not actually moving the view
1123482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (oldX == newX && oldY == newY) {
1124482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                lp.isLockedToGrid = true;
1125482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                return true;
1126482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1127482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1128482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
1129482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            va.setDuration(duration);
1130482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            mReorderAnimators.put(lp, va);
1131482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1132482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            va.addUpdateListener(new AnimatorUpdateListener() {
1133482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                @Override
1134bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                public void onAnimationUpdate(ValueAnimator animation) {
1135482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    float r = ((Float) animation.getAnimatedValue()).floatValue();
113619f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    lp.x = (int) ((1 - r) * oldX + r * newX);
113719f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    lp.y = (int) ((1 - r) * oldY + r * newY);
11386b8a02d63a5d9cab8209381993e37db6a6afb753Adam Cohen                    child.requestLayout();
1139bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                }
1140bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            });
1141482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            va.addListener(new AnimatorListenerAdapter() {
1142bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                boolean cancelled = false;
1143bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                public void onAnimationEnd(Animator animation) {
1144bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    // If the animation was cancelled, it means that another animation
1145bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    // has interrupted this one, and we don't want to lock the item into
1146bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    // place just yet.
1147bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    if (!cancelled) {
1148bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                        lp.isLockedToGrid = true;
1149482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        child.requestLayout();
1150bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    }
1151bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    if (mReorderAnimators.containsKey(lp)) {
1152bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                        mReorderAnimators.remove(lp);
1153bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    }
1154bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                }
1155bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                public void onAnimationCancel(Animator animation) {
1156bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    cancelled = true;
1157bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                }
1158bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            });
1159482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            va.setStartDelay(delay);
1160482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            va.start();
1161bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            return true;
1162bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        }
1163bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        return false;
1164bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    }
1165bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen
11666569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    /**
11676569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     * Estimate where the top left cell of the dragged item will land if it is dropped.
11686569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     *
11696569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     * @param originX The X value of the top left corner of the item
11706569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     * @param originY The Y value of the top left corner of the item
11716569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     * @param spanX The number of horizontal cells that the item spans
11726569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     * @param spanY The number of vertical cells that the item spans
11736569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     * @param result The estimated drop cell X and Y.
11746569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     */
11756569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    void estimateDropCell(int originX, int originY, int spanX, int spanY, int[] result) {
1176d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        final int countX = mCountX;
1177d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        final int countY = mCountY;
11786569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
1179a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka        // pointToCellRounded takes the top left of a cell but will pad that with
1180a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka        // cellWidth/2 and cellHeight/2 when finding the matching cell
1181a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka        pointToCellRounded(originX, originY, result);
11826569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
11836569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        // If the item isn't fully on this screen, snap to the edges
11846569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        int rightOverhang = result[0] + spanX - countX;
11856569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        if (rightOverhang > 0) {
11866569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy            result[0] -= rightOverhang; // Snap to right
11876569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        }
11886569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        result[0] = Math.max(0, result[0]); // Snap to left
11896569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        int bottomOverhang = result[1] + spanY - countY;
11906569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        if (bottomOverhang > 0) {
11916569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy            result[1] -= bottomOverhang; // Snap to bottom
11926569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        }
11936569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        result[1] = Math.max(0, result[1]); // Snap to top
11946569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    }
11956569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
1196482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    void visualizeDropLocation(View v, Bitmap dragOutline, int originX, int originY, int cellX,
1197482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            int cellY, int spanX, int spanY, boolean resize, Point dragOffset, Rect dragRegion) {
119808ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy        final int oldDragCellX = mDragCell[0];
119908ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy        final int oldDragCellY = mDragCell[1];
1200482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1201b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung        if (v != null && dragOffset == null) {
1202a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung            mDragCenter.set(originX + (v.getWidth() / 2), originY + (v.getHeight() / 2));
1203a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung        } else {
1204a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung            mDragCenter.set(originX, originY);
1205a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung        }
12066569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
12072801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        if (dragOutline == null && v == null) {
12082801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            if (mCrosshairsDrawable != null) {
12092801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen                invalidate();
12102801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            }
12112801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            return;
12122801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        }
12132801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
1214482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (cellX != oldDragCellX || cellY != oldDragCellY) {
1215482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            mDragCell[0] = cellX;
1216482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            mDragCell[1] = cellY;
12176569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy            // Find the top left corner of the rect the object will occupy
1218de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy            final int[] topLeft = mTmpPoint;
1219482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            cellToPoint(cellX, cellY, topLeft);
1220de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy
12214be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            int left = topLeft[0];
12224be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            int top = topLeft[1];
12236569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
1224b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung            if (v != null && dragOffset == null) {
122599e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                // When drawing the drag outline, it did not account for margin offsets
122699e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                // added by the view's parent.
122799e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                MarginLayoutParams lp = (MarginLayoutParams) v.getLayoutParams();
122899e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                left += lp.leftMargin;
122999e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                top += lp.topMargin;
123099e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen
123199e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                // Offsets due to the size difference between the View and the dragOutline.
123299e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                // There is a size difference to account for the outer blur, which may lie
123399e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                // outside the bounds of the view.
1234a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung                top += (v.getHeight() - dragOutline.getHeight()) / 2;
1235ae915cecd36af4973061a1cb0b58c5be1be699a0Adam Cohen                // We center about the x axis
1236ae915cecd36af4973061a1cb0b58c5be1be699a0Adam Cohen                left += ((mCellWidth * spanX) + ((spanX - 1) * mWidthGap)
1237ae915cecd36af4973061a1cb0b58c5be1be699a0Adam Cohen                        - dragOutline.getWidth()) / 2;
12386639687cd67bab1aeef2a75e5c6bc458b20dc082Adam Cohen            } else {
1239b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                if (dragOffset != null && dragRegion != null) {
1240b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                    // Center the drag region *horizontally* in the cell and apply a drag
1241b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                    // outline offset
1242b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                    left += dragOffset.x + ((mCellWidth * spanX) + ((spanX - 1) * mWidthGap)
1243b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                             - dragRegion.width()) / 2;
1244b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                    top += dragOffset.y;
1245b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                } else {
1246b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                    // Center the drag outline in the cell
1247b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                    left += ((mCellWidth * spanX) + ((spanX - 1) * mWidthGap)
1248b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                            - dragOutline.getWidth()) / 2;
1249b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                    top += ((mCellHeight * spanY) + ((spanY - 1) * mHeightGap)
1250b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                            - dragOutline.getHeight()) / 2;
1251b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                }
1252a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung            }
12534be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            final int oldIndex = mDragOutlineCurrent;
125408ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy            mDragOutlineAnims[oldIndex].animateOut();
125508ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy            mDragOutlineCurrent = (oldIndex + 1) % mDragOutlines.length;
1256d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            Rect r = mDragOutlines[mDragOutlineCurrent];
1257d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            r.set(left, top, left + dragOutline.getWidth(), top + dragOutline.getHeight());
1258d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            if (resize) {
1259482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                cellToRect(cellX, cellY, spanX, spanY, r);
1260d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            }
1261150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung
126208ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy            mDragOutlineAnims[mDragOutlineCurrent].setTag(dragOutline);
126308ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy            mDragOutlineAnims[mDragOutlineCurrent].animateIn();
12646569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        }
126549250ad530385fcdd6072ca54697f670ec503b59Patrick Dubroy
126649250ad530385fcdd6072ca54697f670ec503b59Patrick Dubroy        // If we are drawing crosshairs, the entire CellLayout needs to be invalidated
126749250ad530385fcdd6072ca54697f670ec503b59Patrick Dubroy        if (mCrosshairsDrawable != null) {
126849250ad530385fcdd6072ca54697f670ec503b59Patrick Dubroy            invalidate();
126949250ad530385fcdd6072ca54697f670ec503b59Patrick Dubroy        }
12706569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    }
12716569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
1272e0310965022e7a1adb7ad489505d404186608689Adam Cohen    public void clearDragOutlines() {
1273e0310965022e7a1adb7ad489505d404186608689Adam Cohen        final int oldIndex = mDragOutlineCurrent;
1274e0310965022e7a1adb7ad489505d404186608689Adam Cohen        mDragOutlineAnims[oldIndex].animateOut();
1275d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        mDragCell[0] = mDragCell[1] = -1;
1276e0310965022e7a1adb7ad489505d404186608689Adam Cohen    }
1277e0310965022e7a1adb7ad489505d404186608689Adam Cohen
127831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
127970864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey     * Find a vacant area that will fit the given bounds nearest the requested
128070864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey     * cell location. Uses Euclidean distance to score multiple vacant areas.
1281aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     *
128251afc022fa76c79f0d1ece470ddc126c08fea8a4Romain Guy     * @param pixelX The X location at which you want to search for a vacant area.
128351afc022fa76c79f0d1ece470ddc126c08fea8a4Romain Guy     * @param pixelY The Y location at which you want to search for a vacant area.
128470864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey     * @param spanX Horizontal span of the object.
128570864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey     * @param spanY Vertical span of the object.
1286de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy     * @param result Array in which to place the result, or null (in which case a new array will
1287de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy     *        be allocated)
128870864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey     * @return The X, Y cell of a vacant area that can contain this object,
128970864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey     *         nearest the requested location.
129031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
1291d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    int[] findNearestVacantArea(int pixelX, int pixelY, int spanX, int spanY,
1292d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            int[] result) {
1293de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy        return findNearestVacantArea(pixelX, pixelY, spanX, spanY, null, result);
12946a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka    }
1295aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
12966a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka    /**
12976a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     * Find a vacant area that will fit the given bounds nearest the requested
12986a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     * cell location. Uses Euclidean distance to score multiple vacant areas.
12996a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     *
13006a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     * @param pixelX The X location at which you want to search for a vacant area.
13016a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     * @param pixelY The Y location at which you want to search for a vacant area.
1302d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param minSpanX The minimum horizontal span required
1303d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param minSpanY The minimum vertical span required
1304d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param spanX Horizontal span of the object.
1305d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param spanY Vertical span of the object.
1306d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param result Array in which to place the result, or null (in which case a new array will
1307d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *        be allocated)
1308d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @return The X, Y cell of a vacant area that can contain this object,
1309d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *         nearest the requested location.
1310d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     */
1311d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    int[] findNearestVacantArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX,
1312d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            int spanY, int[] result, int[] resultSpan) {
1313d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        return findNearestVacantArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, null,
1314d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                result, resultSpan);
1315d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    }
1316d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen
1317d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    /**
1318d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * Find a vacant area that will fit the given bounds nearest the requested
1319d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * cell location. Uses Euclidean distance to score multiple vacant areas.
1320d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *
1321d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param pixelX The X location at which you want to search for a vacant area.
1322d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param pixelY The Y location at which you want to search for a vacant area.
13236a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     * @param spanX Horizontal span of the object.
13246a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     * @param spanY Vertical span of the object.
1325df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param ignoreOccupied If true, the result can be an occupied cell
1326df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param result Array in which to place the result, or null (in which case a new array will
1327df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     *        be allocated)
13286a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     * @return The X, Y cell of a vacant area that can contain this object,
13296a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     *         nearest the requested location.
13306a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     */
1331df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    int[] findNearestArea(int pixelX, int pixelY, int spanX, int spanY, View ignoreView,
1332df0353815c629fc678824b07a234b89a1ff94208Adam Cohen            boolean ignoreOccupied, int[] result) {
1333d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        return findNearestArea(pixelX, pixelY, spanX, spanY,
1334482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                spanX, spanY, ignoreView, ignoreOccupied, result, null, mOccupied);
1335d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    }
1336d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen
1337d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    private final Stack<Rect> mTempRectStack = new Stack<Rect>();
1338d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    private void lazyInitTempRectStack() {
1339d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        if (mTempRectStack.isEmpty()) {
1340d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            for (int i = 0; i < mCountX * mCountY; i++) {
1341d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                mTempRectStack.push(new Rect());
1342d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            }
1343d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        }
1344d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    }
1345482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1346d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    private void recycleTempRects(Stack<Rect> used) {
1347d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        while (!used.isEmpty()) {
1348d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            mTempRectStack.push(used.pop());
1349d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        }
1350d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    }
1351d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen
1352d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    /**
1353d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * Find a vacant area that will fit the given bounds nearest the requested
1354d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * cell location. Uses Euclidean distance to score multiple vacant areas.
1355d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *
1356d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param pixelX The X location at which you want to search for a vacant area.
1357d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param pixelY The Y location at which you want to search for a vacant area.
1358d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param minSpanX The minimum horizontal span required
1359d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param minSpanY The minimum vertical span required
1360d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param spanX Horizontal span of the object.
1361d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param spanY Vertical span of the object.
1362d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param ignoreOccupied If true, the result can be an occupied cell
1363d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param result Array in which to place the result, or null (in which case a new array will
1364d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *        be allocated)
1365d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @return The X, Y cell of a vacant area that can contain this object,
1366d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *         nearest the requested location.
1367d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     */
1368d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    int[] findNearestArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, int spanY,
1369482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            View ignoreView, boolean ignoreOccupied, int[] result, int[] resultSpan,
1370482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            boolean[][] occupied) {
1371d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        lazyInitTempRectStack();
1372c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka        // mark space take by ignoreView as available (method checks if ignoreView is null)
1373482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsAsUnoccupiedForView(ignoreView, occupied);
1374c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka
1375e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        // For items with a spanX / spanY > 1, the passed in point (pixelX, pixelY) corresponds
1376e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        // to the center of the item, but we are searching based on the top-left cell, so
1377e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        // we translate the point over to correspond to the top-left.
1378e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        pixelX -= (mCellWidth + mWidthGap) * (spanX - 1) / 2f;
1379e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        pixelY -= (mCellHeight + mHeightGap) * (spanY - 1) / 2f;
1380e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen
138170864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey        // Keep track of best-scoring drop area
1382de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy        final int[] bestXY = result != null ? result : new int[2];
138370864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey        double bestDistance = Double.MAX_VALUE;
1384d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        final Rect bestRect = new Rect(-1, -1, -1, -1);
1385d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        final Stack<Rect> validRegions = new Stack<Rect>();
1386aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
1387de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy        final int countX = mCountX;
1388de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy        final int countY = mCountY;
1389de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy
1390d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        if (minSpanX <= 0 || minSpanY <= 0 || spanX <= 0 || spanY <= 0 ||
1391d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                spanX < minSpanX || spanY < minSpanY) {
1392d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            return bestXY;
1393d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        }
1394d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen
1395d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        for (int y = 0; y < countY - (minSpanY - 1); y++) {
1396c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka            inner:
1397d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            for (int x = 0; x < countX - (minSpanX - 1); x++) {
1398d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                int ySize = -1;
1399d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                int xSize = -1;
1400df0353815c629fc678824b07a234b89a1ff94208Adam Cohen                if (ignoreOccupied) {
1401d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    // First, let's see if this thing fits anywhere
1402d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    for (int i = 0; i < minSpanX; i++) {
1403d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        for (int j = 0; j < minSpanY; j++) {
1404df0353815c629fc678824b07a234b89a1ff94208Adam Cohen                            if (occupied[x + i][y + j]) {
1405df0353815c629fc678824b07a234b89a1ff94208Adam Cohen                                continue inner;
1406df0353815c629fc678824b07a234b89a1ff94208Adam Cohen                            }
1407c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                        }
1408c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                    }
1409d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    xSize = minSpanX;
1410d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    ySize = minSpanY;
1411d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen
1412d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    // We know that the item will fit at _some_ acceptable size, now let's see
1413d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    // how big we can make it. We'll alternate between incrementing x and y spans
1414d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    // until we hit a limit.
1415d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    boolean incX = true;
1416d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    boolean hitMaxX = xSize >= spanX;
1417d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    boolean hitMaxY = ySize >= spanY;
1418d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    while (!(hitMaxX && hitMaxY)) {
1419d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        if (incX && !hitMaxX) {
1420d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            for (int j = 0; j < ySize; j++) {
1421d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                if (x + xSize > countX -1 || occupied[x + xSize][y + j]) {
1422d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                    // We can't move out horizontally
1423d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                    hitMaxX = true;
1424d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                }
1425d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            }
1426d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            if (!hitMaxX) {
1427d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                xSize++;
1428d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            }
1429d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        } else if (!hitMaxY) {
1430d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            for (int i = 0; i < xSize; i++) {
1431d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                if (y + ySize > countY - 1 || occupied[x + i][y + ySize]) {
1432d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                    // We can't move out vertically
1433d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                    hitMaxY = true;
1434d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                }
1435d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            }
1436d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            if (!hitMaxY) {
1437d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                ySize++;
1438d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            }
1439d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        }
1440d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        hitMaxX |= xSize >= spanX;
1441d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        hitMaxY |= ySize >= spanY;
1442d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        incX = !incX;
1443d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    }
1444d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    incX = true;
1445d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    hitMaxX = xSize >= spanX;
1446d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    hitMaxY = ySize >= spanY;
1447c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                }
14480be025d64c1f84138fe430a58875886e66aae767Winson Chung                final int[] cellXY = mTmpXY;
1449e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen                cellToCenterPoint(x, y, cellXY);
1450c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka
1451d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                // We verify that the current rect is not a sub-rect of any of our previous
1452d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                // candidates. In this case, the current rect is disqualified in favour of the
1453d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                // containing rect.
1454d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                Rect currentRect = mTempRectStack.pop();
1455d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                currentRect.set(x, y, x + xSize, y + ySize);
1456d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                boolean contained = false;
1457d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                for (Rect r : validRegions) {
1458d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    if (r.contains(currentRect)) {
1459d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        contained = true;
1460d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        break;
1461d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    }
1462d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                }
1463d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                validRegions.push(currentRect);
1464c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                double distance = Math.sqrt(Math.pow(cellXY[0] - pixelX, 2)
1465c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                        + Math.pow(cellXY[1] - pixelY, 2));
1466482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1467d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                if ((distance <= bestDistance && !contained) ||
1468d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        currentRect.contains(bestRect)) {
1469c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                    bestDistance = distance;
1470c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                    bestXY[0] = x;
1471c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                    bestXY[1] = y;
1472d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    if (resultSpan != null) {
1473d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        resultSpan[0] = xSize;
1474d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        resultSpan[1] = ySize;
1475d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    }
1476d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    bestRect.set(currentRect);
1477c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                }
147831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            }
147931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
1480c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka        // re-mark space taken by ignoreView as occupied
1481482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsAsOccupiedForView(ignoreView, occupied);
148231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
1483c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        // Return -1, -1 if no suitable location found
1484c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        if (bestDistance == Double.MAX_VALUE) {
1485c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            bestXY[0] = -1;
1486c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            bestXY[1] = -1;
148770864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey        }
1488d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        recycleTempRects(validRegions);
1489c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        return bestXY;
149031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
1491aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
1492482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     /**
1493482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * Find a vacant area that will fit the given bounds nearest the requested
1494482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * cell location, and will also weigh in a suggested direction vector of the
1495482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * desired location. This method computers distance based on unit grid distances,
1496482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * not pixel distances.
1497482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     *
149847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param cellX The X cell nearest to which you want to search for a vacant area.
149947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param cellY The Y cell nearest which you want to search for a vacant area.
1500482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * @param spanX Horizontal span of the object.
1501482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * @param spanY Vertical span of the object.
150247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param direction The favored direction in which the views should move from x, y
150347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param exactDirectionOnly If this parameter is true, then only solutions where the direction
150447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     *        matches exactly. Otherwise we find the best matching direction.
150547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param occoupied The array which represents which cells in the CellLayout are occupied
150647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param blockOccupied The array which represents which cells in the specified block (cellX,
150747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     *        cellY, spanX, spanY) are occupied. This is used when try to move a group of views.
1508482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * @param result Array in which to place the result, or null (in which case a new array will
1509482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     *        be allocated)
1510482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * @return The X, Y cell of a vacant area that can contain this object,
1511482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     *         nearest the requested location.
1512482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     */
1513482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private int[] findNearestArea(int cellX, int cellY, int spanX, int spanY, int[] direction,
151447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            boolean[][] occupied, boolean blockOccupied[][], int[] result) {
1515482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // Keep track of best-scoring drop area
1516482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        final int[] bestXY = result != null ? result : new int[2];
1517482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        float bestDistance = Float.MAX_VALUE;
1518482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        int bestDirectionScore = Integer.MIN_VALUE;
1519482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1520482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        final int countX = mCountX;
1521482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        final int countY = mCountY;
1522482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1523482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int y = 0; y < countY - (spanY - 1); y++) {
1524482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            inner:
1525482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            for (int x = 0; x < countX - (spanX - 1); x++) {
1526482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                // First, let's see if this thing fits anywhere
1527482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                for (int i = 0; i < spanX; i++) {
1528482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    for (int j = 0; j < spanY; j++) {
152947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        if (occupied[x + i][y + j] && (blockOccupied == null || blockOccupied[i][j])) {
1530482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                            continue inner;
1531482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        }
1532482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    }
1533482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                }
1534482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1535482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                float distance = (float)
1536482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        Math.sqrt((x - cellX) * (x - cellX) + (y - cellY) * (y - cellY));
1537482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                int[] curDirection = mTmpPoint;
153847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                computeDirectionVector(x - cellX, y - cellY, curDirection);
153947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                // The direction score is just the dot product of the two candidate direction
154047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                // and that passed in.
1541482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                int curDirectionScore = direction[0] * curDirection[0] +
1542482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        direction[1] * curDirection[1];
154347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                boolean exactDirectionOnly = false;
154447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                boolean directionMatches = direction[0] == curDirection[0] &&
154547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        direction[0] == curDirection[0];
154647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                if ((directionMatches || !exactDirectionOnly) &&
154747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        Float.compare(distance,  bestDistance) < 0 || (Float.compare(distance,
1548482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        bestDistance) == 0 && curDirectionScore > bestDirectionScore)) {
1549482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    bestDistance = distance;
1550482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    bestDirectionScore = curDirectionScore;
1551482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    bestXY[0] = x;
1552482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    bestXY[1] = y;
1553482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                }
1554482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1555482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1556482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1557482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // Return -1, -1 if no suitable location found
1558482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (bestDistance == Float.MAX_VALUE) {
1559482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            bestXY[0] = -1;
1560482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            bestXY[1] = -1;
1561482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1562482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return bestXY;
1563482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1564482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
156547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    private int[] findNearestAreaInDirection(int cellX, int cellY, int spanX, int spanY,
156647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            int[] direction,boolean[][] occupied,
156747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            boolean blockOccupied[][], int[] result) {
156847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        // Keep track of best-scoring drop area
156947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        final int[] bestXY = result != null ? result : new int[2];
157047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        bestXY[0] = -1;
157147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        bestXY[1] = -1;
157247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        float bestDistance = Float.MAX_VALUE;
157347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
157447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        // We use this to march in a single direction
15755b53f29f809a0dad4a1e0717ba610ce737ee0f43Adam Cohen        if ((direction[0] != 0 && direction[1] != 0) ||
15765b53f29f809a0dad4a1e0717ba610ce737ee0f43Adam Cohen                (direction[0] == 0 && direction[1] == 0)) {
157747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            return bestXY;
157847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
157947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
158047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        // This will only incrememnet one of x or y based on the assertion above
158147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        int x = cellX + direction[0];
158247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        int y = cellY + direction[1];
158347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        while (x >= 0 && x + spanX <= mCountX && y >= 0 && y + spanY <= mCountY) {
158447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
158547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            boolean fail = false;
158647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            for (int i = 0; i < spanX; i++) {
158747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                for (int j = 0; j < spanY; j++) {
158847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    if (occupied[x + i][y + j] && (blockOccupied == null || blockOccupied[i][j])) {
158947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        fail = true;
159047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    }
159147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                }
159247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            }
159347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            if (!fail) {
159447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                float distance = (float)
159547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        Math.sqrt((x - cellX) * (x - cellX) + (y - cellY) * (y - cellY));
159647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                if (Float.compare(distance,  bestDistance) < 0) {
159747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    bestDistance = distance;
159847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    bestXY[0] = x;
159947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    bestXY[1] = y;
160047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                }
160147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            }
160247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            x += direction[0];
160347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            y += direction[1];
160447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
160547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        return bestXY;
160647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    }
160747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
1608482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private boolean addViewToTempLocation(View v, Rect rectOccupiedByPotentialDrop,
16098baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            int[] direction, ItemConfiguration currentState) {
16108baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        CellAndSpan c = currentState.map.get(v);
1611482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        boolean success = false;
16128baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, false);
1613482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsForRect(rectOccupiedByPotentialDrop, mTmpOccupied, true);
1614482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
16158baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        findNearestArea(c.x, c.y, c.spanX, c.spanY, direction, mTmpOccupied, null, mTempLocation);
1616482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1617482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (mTempLocation[0] >= 0 && mTempLocation[1] >= 0) {
16188baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            c.x = mTempLocation[0];
16198baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            c.y = mTempLocation[1];
1620482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            success = true;
1621482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1622482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
16238baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, true);
1624482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return success;
1625482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1626482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
162747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    // This method looks in the specified direction to see if there is an additional view
162847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    // immediately adjecent in that direction
162947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    private boolean addViewInDirection(ArrayList<View> views, Rect boundingRect, int[] direction,
163019f3792523fe2d55ea791a9286398a6120920690Adam Cohen            boolean[][] occupied, View dragView, ItemConfiguration currentState) {
163147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        boolean found = false;
163247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
1633a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        int childCount = mShortcutsAndWidgets.getChildCount();
163447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        Rect r0 = new Rect(boundingRect);
163547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        Rect r1 = new Rect();
163647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
163747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        int deltaX = 0;
163847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        int deltaY = 0;
163947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        if (direction[1] < 0) {
164047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            r0.set(r0.left, r0.top - 1, r0.right, r0.bottom);
164147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            deltaY = -1;
164247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        } else if (direction[1] > 0) {
164347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            r0.set(r0.left, r0.top, r0.right, r0.bottom + 1);
164447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            deltaY = 1;
164547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        } else if (direction[0] < 0) {
164647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            r0.set(r0.left - 1, r0.top, r0.right, r0.bottom);
164747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            deltaX = -1;
164847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        } else if (direction[0] > 0) {
164947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            r0.set(r0.left, r0.top, r0.right + 1, r0.bottom);
165047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            deltaX = 1;
165147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
165247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
165347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        for (int i = 0; i < childCount; i++) {
1654a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            View child = mShortcutsAndWidgets.getChildAt(i);
165519f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (views.contains(child) || child == dragView) continue;
16568baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = currentState.map.get(child);
165747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
16588baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
16598baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            r1.set(c.x, c.y, c.x + c.spanX, c.y + c.spanY);
166047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            if (Rect.intersects(r0, r1)) {
166147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                if (!lp.canReorder) {
166247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    return false;
166347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                }
166447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                boolean pushed = false;
16658baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                for (int x = c.x; x < c.x + c.spanX; x++) {
16668baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                    for (int y = c.y; y < c.y + c.spanY; y++) {
166747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        boolean inBounds = x - deltaX >= 0 && x -deltaX < mCountX
166847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                                && y - deltaY >= 0 && y - deltaY < mCountY;
166947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        if (inBounds && occupied[x - deltaX][y - deltaY]) {
167047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                            pushed = true;
167147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        }
167247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    }
167347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                }
167447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                if (pushed) {
167547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    views.add(child);
16768baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                    boundingRect.union(c.x, c.y, c.x + c.spanX, c.y + c.spanY);
167747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    found = true;
167847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                }
167947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            }
168047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
168147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        return found;
168247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    }
168347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
16848baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen    private boolean addViewsToTempLocation(ArrayList<View> views, Rect rectOccupiedByPotentialDrop,
168519f3792523fe2d55ea791a9286398a6120920690Adam Cohen            int[] direction, boolean push, View dragView, ItemConfiguration currentState) {
168647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        if (views.size() == 0) return true;
168747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
168847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        boolean success = false;
168947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        Rect boundingRect = null;
16908baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // We construct a rect which represents the entire group of views passed in
169147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        for (View v: views) {
16928baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = currentState.map.get(v);
169347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            if (boundingRect == null) {
16948baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                boundingRect = new Rect(c.x, c.y, c.x + c.spanX, c.y + c.spanY);
169547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            } else {
16968baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                boundingRect.union(c.x, c.y, c.x + c.spanX, c.y + c.spanY);
169747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            }
169847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
169947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
17008baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        @SuppressWarnings("unchecked")
170147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        ArrayList<View> dup = (ArrayList<View>) views.clone();
17028baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // We try and expand the group of views in the direction vector passed, based on
17038baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // whether they are physically adjacent, ie. based on "push mechanics".
170419f3792523fe2d55ea791a9286398a6120920690Adam Cohen        while (push && addViewInDirection(dup, boundingRect, direction, mTmpOccupied, dragView,
17058baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                currentState)) {
170647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
17078baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen
17088baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // Mark the occupied state as false for the group of views we want to move.
170947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        for (View v: dup) {
17108baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = currentState.map.get(v);
17118baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, false);
171247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
171347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
171447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        boolean[][] blockOccupied = new boolean[boundingRect.width()][boundingRect.height()];
171547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        int top = boundingRect.top;
171647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        int left = boundingRect.left;
17178baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // We mark more precisely which parts of the bounding rect are truly occupied, allowing
17188baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // for tetris-style interlocking.
171947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        for (View v: dup) {
17208baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = currentState.map.get(v);
17218baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            markCellsForView(c.x - left, c.y - top, c.spanX, c.spanY, blockOccupied, true);
172247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
172347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
172447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        markCellsForRect(rectOccupiedByPotentialDrop, mTmpOccupied, true);
172547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
17268baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        if (push) {
17278baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            findNearestAreaInDirection(boundingRect.left, boundingRect.top, boundingRect.width(),
17288baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                    boundingRect.height(), direction, mTmpOccupied, blockOccupied, mTempLocation);
17298baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        } else {
17308baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            findNearestArea(boundingRect.left, boundingRect.top, boundingRect.width(),
17318baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                    boundingRect.height(), direction, mTmpOccupied, blockOccupied, mTempLocation);
17328baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        }
173347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
17348baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // If we successfuly found a location by pushing the block of views, we commit it
173547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        if (mTempLocation[0] >= 0 && mTempLocation[1] >= 0) {
17368baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            int deltaX = mTempLocation[0] - boundingRect.left;
17378baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            int deltaY = mTempLocation[1] - boundingRect.top;
173847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            for (View v: dup) {
17398baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                CellAndSpan c = currentState.map.get(v);
17408baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                c.x += deltaX;
17418baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                c.y += deltaY;
174247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            }
174347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            success = true;
174447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
1745482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
17468baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // In either case, we set the occupied array as marked for the location of the views
17478baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        for (View v: dup) {
17488baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = currentState.map.get(v);
17498baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, true);
1750482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1751482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return success;
1752482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1753482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1754482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private void markCellsForRect(Rect r, boolean[][] occupied, boolean value) {
1755482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsForView(r.left, r.top, r.width(), r.height(), occupied, value);
1756482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1757482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1758482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private boolean rearrangementExists(int cellX, int cellY, int spanX, int spanY, int[] direction,
17598baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            View ignoreView, ItemConfiguration solution) {
1760482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
17618baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        mIntersectingViews.clear();
1762482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        mOccupiedRect.set(cellX, cellY, cellX + spanX, cellY + spanY);
1763482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
17648baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // Mark the desired location of the view currently being dragged.
1765482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (ignoreView != null) {
17668baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = solution.map.get(ignoreView);
176719f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (c != null) {
176819f3792523fe2d55ea791a9286398a6120920690Adam Cohen                c.x = cellX;
176919f3792523fe2d55ea791a9286398a6120920690Adam Cohen                c.y = cellY;
177019f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
1771482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1772482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        Rect r0 = new Rect(cellX, cellY, cellX + spanX, cellY + spanY);
1773482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        Rect r1 = new Rect();
17748baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        for (View child: solution.map.keySet()) {
1775482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (child == ignoreView) continue;
17768baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = solution.map.get(child);
1777482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
17788baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            r1.set(c.x, c.y, c.x + c.spanX, c.y + c.spanY);
1779482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (Rect.intersects(r0, r1)) {
1780482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                if (!lp.canReorder) {
1781482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    return false;
1782482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                }
1783482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                mIntersectingViews.add(child);
1784482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1785482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
178647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
17878baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // We try to move the intersecting views as a block using the push mechanic
178819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if (addViewsToTempLocation(mIntersectingViews, mOccupiedRect, direction, true, ignoreView,
178919f3792523fe2d55ea791a9286398a6120920690Adam Cohen                solution)) {
179047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            return true;
179147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
179247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        // Try the opposite direction
179347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        direction[0] *= -1;
179447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        direction[1] *= -1;
179519f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if (addViewsToTempLocation(mIntersectingViews, mOccupiedRect, direction, true, ignoreView,
179619f3792523fe2d55ea791a9286398a6120920690Adam Cohen                solution)) {
179747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            return true;
179847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
179947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        // Switch the direction back
180047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        direction[0] *= -1;
180147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        direction[1] *= -1;
180247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
18038baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // Next we try moving the views as a block , but without requiring the push mechanic
180419f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if (addViewsToTempLocation(mIntersectingViews, mOccupiedRect, direction, false, ignoreView,
180519f3792523fe2d55ea791a9286398a6120920690Adam Cohen                solution)) {
1806482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            return true;
1807482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
180847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
1809482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // Ok, they couldn't move as a block, let's move them individually
1810482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (View v : mIntersectingViews) {
18118baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            if (!addViewToTempLocation(v, mOccupiedRect, direction, solution)) {
1812482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                return false;
1813482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1814482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1815482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return true;
1816482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1817482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1818482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    /*
1819482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * Returns a pair (x, y), where x,y are in {-1, 0, 1} corresponding to vector between
1820482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * the provided point and the provided cell
1821482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     */
182247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    private void computeDirectionVector(float deltaX, float deltaY, int[] result) {
1823482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        double angle = Math.atan(((float) deltaY) / deltaX);
1824482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1825482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        result[0] = 0;
1826482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        result[1] = 0;
1827482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (Math.abs(Math.cos(angle)) > 0.5f) {
1828482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            result[0] = (int) Math.signum(deltaX);
1829482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1830482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (Math.abs(Math.sin(angle)) > 0.5f) {
1831482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            result[1] = (int) Math.signum(deltaY);
1832482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1833482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1834482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
18358baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen    private void copyOccupiedArray(boolean[][] occupied) {
18368baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        for (int i = 0; i < mCountX; i++) {
18378baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            for (int j = 0; j < mCountY; j++) {
18388baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                occupied[i][j] = mOccupied[i][j];
18398baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            }
18408baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        }
18418baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen    }
18428baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen
1843482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    ItemConfiguration simpleSwap(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX,
1844482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            int spanY, int[] direction, View dragView, boolean decX, ItemConfiguration solution) {
18458baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // Copy the current state into the solution. This solution will be manipulated as necessary.
18468baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        copyCurrentStateToSolution(solution, false);
18478baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // Copy the current occupied array into the temporary occupied array. This array will be
18488baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // manipulated as necessary to find a solution.
18498baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        copyOccupiedArray(mTmpOccupied);
1850482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1851482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // We find the nearest cell into which we would place the dragged item, assuming there's
1852482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // nothing in its way.
1853482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        int result[] = new int[2];
1854482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        result = findNearestArea(pixelX, pixelY, spanX, spanY, result);
1855482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1856482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        boolean success = false;
1857482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // First we try the exact nearest position of the item being dragged,
1858482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // we will then want to try to move this around to other neighbouring positions
18598baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        success = rearrangementExists(result[0], result[1], spanX, spanY, direction, dragView,
18608baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                solution);
1861482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1862482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (!success) {
1863482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            // We try shrinking the widget down to size in an alternating pattern, shrink 1 in
1864482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            // x, then 1 in y etc.
1865482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (spanX > minSpanX && (minSpanY == spanY || decX)) {
1866482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                return simpleSwap(pixelX, pixelY, minSpanX, minSpanY, spanX - 1, spanY, direction,
1867482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        dragView, false, solution);
1868482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            } else if (spanY > minSpanY) {
1869482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                return simpleSwap(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY - 1, direction,
1870482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        dragView, true, solution);
1871482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1872482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.isSolution = false;
1873482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        } else {
1874482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.isSolution = true;
1875482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewX = result[0];
1876482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewY = result[1];
1877482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewSpanX = spanX;
1878482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewSpanY = spanY;
1879482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1880482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return solution;
1881482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1882482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1883482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private void copyCurrentStateToSolution(ItemConfiguration solution, boolean temp) {
1884a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        int childCount = mShortcutsAndWidgets.getChildCount();
1885482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < childCount; i++) {
1886a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            View child = mShortcutsAndWidgets.getChildAt(i);
1887482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
18888baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c;
1889482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (temp) {
18908baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                c = new CellAndSpan(lp.tmpCellX, lp.tmpCellY, lp.cellHSpan, lp.cellVSpan);
1891482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            } else {
18928baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                c = new CellAndSpan(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan);
1893482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
18948baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            solution.map.put(child, c);
1895482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1896482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1897482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1898482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private void copySolutionToTempState(ItemConfiguration solution, View dragView) {
1899482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < mCountX; i++) {
1900482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            for (int j = 0; j < mCountY; j++) {
1901482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                mTmpOccupied[i][j] = false;
1902482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1903482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1904482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1905a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        int childCount = mShortcutsAndWidgets.getChildCount();
1906482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < childCount; i++) {
1907a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            View child = mShortcutsAndWidgets.getChildAt(i);
1908482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (child == dragView) continue;
1909482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
19108baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = solution.map.get(child);
19118baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            if (c != null) {
19128baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                lp.tmpCellX = c.x;
19138baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                lp.tmpCellY = c.y;
19148baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                lp.cellHSpan = c.spanX;
19158baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                lp.cellVSpan = c.spanY;
19168baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, true);
1917482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1918482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1919482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsForView(solution.dragViewX, solution.dragViewY, solution.dragViewSpanX,
1920482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                solution.dragViewSpanY, mTmpOccupied, true);
1921482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1922482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1923482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private void animateItemsToSolution(ItemConfiguration solution, View dragView, boolean
1924482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            commitDragView) {
1925482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1926482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        boolean[][] occupied = DESTRUCTIVE_REORDER ? mOccupied : mTmpOccupied;
1927482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < mCountX; i++) {
1928482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            for (int j = 0; j < mCountY; j++) {
1929482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                occupied[i][j] = false;
1930482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1931482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1932482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1933a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        int childCount = mShortcutsAndWidgets.getChildCount();
1934482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < childCount; i++) {
1935a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            View child = mShortcutsAndWidgets.getChildAt(i);
1936482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (child == dragView) continue;
19378baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = solution.map.get(child);
19388baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            if (c != null) {
193919f3792523fe2d55ea791a9286398a6120920690Adam Cohen                animateChildToPosition(child, c.x, c.y, REORDER_ANIMATION_DURATION, 0,
194019f3792523fe2d55ea791a9286398a6120920690Adam Cohen                        DESTRUCTIVE_REORDER, false);
19418baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                markCellsForView(c.x, c.y, c.spanX, c.spanY, occupied, true);
1942482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1943482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1944482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (commitDragView) {
1945482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            markCellsForView(solution.dragViewX, solution.dragViewY, solution.dragViewSpanX,
1946482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    solution.dragViewSpanY, occupied, true);
1947482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1948482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1949482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
195019f3792523fe2d55ea791a9286398a6120920690Adam Cohen    // This method starts or changes the reorder hint animations
195119f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private void beginOrAdjustHintAnimations(ItemConfiguration solution, View dragView, int delay) {
195219f3792523fe2d55ea791a9286398a6120920690Adam Cohen        int childCount = mShortcutsAndWidgets.getChildCount();
195319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        int timeForPriorAnimationToComplete = getMaxCompletionTime();
195419f3792523fe2d55ea791a9286398a6120920690Adam Cohen        for (int i = 0; i < childCount; i++) {
195519f3792523fe2d55ea791a9286398a6120920690Adam Cohen            View child = mShortcutsAndWidgets.getChildAt(i);
195619f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (child == dragView) continue;
195719f3792523fe2d55ea791a9286398a6120920690Adam Cohen            CellAndSpan c = solution.map.get(child);
195819f3792523fe2d55ea791a9286398a6120920690Adam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
195919f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (c != null) {
196019f3792523fe2d55ea791a9286398a6120920690Adam Cohen                ReorderHintAnimation rha = new ReorderHintAnimation(child, lp.cellX, lp.cellY,
196119f3792523fe2d55ea791a9286398a6120920690Adam Cohen                        c.x, c.y, c.spanX, c.spanY);
196219f3792523fe2d55ea791a9286398a6120920690Adam Cohen                rha.animate(timeForPriorAnimationToComplete);
196319f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
196419f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
196519f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
196619f3792523fe2d55ea791a9286398a6120920690Adam Cohen
196719f3792523fe2d55ea791a9286398a6120920690Adam Cohen    // Class which represents the reorder hint animations. These animations show that an item is
196819f3792523fe2d55ea791a9286398a6120920690Adam Cohen    // in a temporary state, and hint at where the item will return to.
196919f3792523fe2d55ea791a9286398a6120920690Adam Cohen    class ReorderHintAnimation {
197019f3792523fe2d55ea791a9286398a6120920690Adam Cohen        View child;
197119f3792523fe2d55ea791a9286398a6120920690Adam Cohen        float deltaX;
197219f3792523fe2d55ea791a9286398a6120920690Adam Cohen        float deltaY;
197319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        private static final int DURATION = 140;
197419f3792523fe2d55ea791a9286398a6120920690Adam Cohen        private int repeatCount;
197519f3792523fe2d55ea791a9286398a6120920690Adam Cohen        private boolean cancelOnCycleComplete = false;
197619f3792523fe2d55ea791a9286398a6120920690Adam Cohen        ValueAnimator va;
197719f3792523fe2d55ea791a9286398a6120920690Adam Cohen
197819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        public ReorderHintAnimation(View child, int cellX0, int cellY0, int cellX1, int cellY1,
197919f3792523fe2d55ea791a9286398a6120920690Adam Cohen                int spanX, int spanY) {
198019f3792523fe2d55ea791a9286398a6120920690Adam Cohen            regionToCenterPoint(cellX0, cellY0, spanX, spanY, mTmpPoint);
198119f3792523fe2d55ea791a9286398a6120920690Adam Cohen            final int x0 = mTmpPoint[0];
198219f3792523fe2d55ea791a9286398a6120920690Adam Cohen            final int y0 = mTmpPoint[1];
198319f3792523fe2d55ea791a9286398a6120920690Adam Cohen            regionToCenterPoint(cellX1, cellY1, spanX, spanY, mTmpPoint);
198419f3792523fe2d55ea791a9286398a6120920690Adam Cohen            final int x1 = mTmpPoint[0];
198519f3792523fe2d55ea791a9286398a6120920690Adam Cohen            final int y1 = mTmpPoint[1];
198619f3792523fe2d55ea791a9286398a6120920690Adam Cohen            final int dX = x1 - x0;
198719f3792523fe2d55ea791a9286398a6120920690Adam Cohen            final int dY = y1 - y0;
198819f3792523fe2d55ea791a9286398a6120920690Adam Cohen            deltaX = 0;
198919f3792523fe2d55ea791a9286398a6120920690Adam Cohen            deltaY = 0;
199019f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (dX == dY && dX == 0) {
199119f3792523fe2d55ea791a9286398a6120920690Adam Cohen            } else {
199219f3792523fe2d55ea791a9286398a6120920690Adam Cohen                if (dY == 0) {
199319f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    deltaX = mReorderHintAnimationMagnitude;
199419f3792523fe2d55ea791a9286398a6120920690Adam Cohen                } else if (dX == 0) {
199519f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    deltaY = mReorderHintAnimationMagnitude;
199619f3792523fe2d55ea791a9286398a6120920690Adam Cohen                } else {
199719f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    double angle = Math.atan( (float) (dY) / dX);
199819f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    deltaX = (int) (Math.cos(angle) * mReorderHintAnimationMagnitude);
199919f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    deltaY = (int) (Math.sin(angle) * mReorderHintAnimationMagnitude);
200019f3792523fe2d55ea791a9286398a6120920690Adam Cohen                }
200119f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
200219f3792523fe2d55ea791a9286398a6120920690Adam Cohen            this.child = child;
200319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
200419f3792523fe2d55ea791a9286398a6120920690Adam Cohen
200519f3792523fe2d55ea791a9286398a6120920690Adam Cohen        void animate(int delay) {
200619f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (mShakeAnimators.containsKey(child)) {
200719f3792523fe2d55ea791a9286398a6120920690Adam Cohen                ReorderHintAnimation oldAnimation = mShakeAnimators.get(child);
200819f3792523fe2d55ea791a9286398a6120920690Adam Cohen                oldAnimation.completeAnimation();
200919f3792523fe2d55ea791a9286398a6120920690Adam Cohen                mShakeAnimators.remove(child);
201019f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
201119f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (deltaX == 0 && deltaY == 0) {
201219f3792523fe2d55ea791a9286398a6120920690Adam Cohen                return;
201319f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
201419f3792523fe2d55ea791a9286398a6120920690Adam Cohen            va = ValueAnimator.ofFloat(0f, 1f);
201519f3792523fe2d55ea791a9286398a6120920690Adam Cohen            va.setRepeatMode(ValueAnimator.REVERSE);
201619f3792523fe2d55ea791a9286398a6120920690Adam Cohen            va.setRepeatCount(ValueAnimator.INFINITE);
201719f3792523fe2d55ea791a9286398a6120920690Adam Cohen            va.setDuration(DURATION);
201819f3792523fe2d55ea791a9286398a6120920690Adam Cohen            va.addUpdateListener(new AnimatorUpdateListener() {
201919f3792523fe2d55ea791a9286398a6120920690Adam Cohen                @Override
202019f3792523fe2d55ea791a9286398a6120920690Adam Cohen                public void onAnimationUpdate(ValueAnimator animation) {
202119f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    float r = ((Float) animation.getAnimatedValue()).floatValue();
202219f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    float x = r * deltaX;
202319f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    float y = r * deltaY;
202419f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    child.setTranslationX(x);
202519f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    child.setTranslationY(y);
202619f3792523fe2d55ea791a9286398a6120920690Adam Cohen                }
202719f3792523fe2d55ea791a9286398a6120920690Adam Cohen            });
202819f3792523fe2d55ea791a9286398a6120920690Adam Cohen            va.addListener(new AnimatorListenerAdapter() {
202919f3792523fe2d55ea791a9286398a6120920690Adam Cohen                public void onAnimationRepeat(Animator animation) {
203019f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    repeatCount++;
203119f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    // We make sure to end only after a full period
203219f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    if (cancelOnCycleComplete && repeatCount % 2 == 0) {
203319f3792523fe2d55ea791a9286398a6120920690Adam Cohen                        va.cancel();
203419f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    }
203519f3792523fe2d55ea791a9286398a6120920690Adam Cohen                }
203619f3792523fe2d55ea791a9286398a6120920690Adam Cohen            });
203719f3792523fe2d55ea791a9286398a6120920690Adam Cohen            va.setStartDelay(Math.max(REORDER_ANIMATION_DURATION, delay));
203819f3792523fe2d55ea791a9286398a6120920690Adam Cohen            mShakeAnimators.put(child, this);
203919f3792523fe2d55ea791a9286398a6120920690Adam Cohen            va.start();
204019f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
204119f3792523fe2d55ea791a9286398a6120920690Adam Cohen
204219f3792523fe2d55ea791a9286398a6120920690Adam Cohen
204319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        private void completeAnimation() {
204419f3792523fe2d55ea791a9286398a6120920690Adam Cohen            cancelOnCycleComplete = true;
204519f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
204619f3792523fe2d55ea791a9286398a6120920690Adam Cohen
204719f3792523fe2d55ea791a9286398a6120920690Adam Cohen        // Returns the time required to complete the current oscillating animation
204819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        private int completionTime() {
204919f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (repeatCount % 2 == 0) {
205019f3792523fe2d55ea791a9286398a6120920690Adam Cohen                return (int) (va.getDuration() - va.getCurrentPlayTime() + DURATION);
205119f3792523fe2d55ea791a9286398a6120920690Adam Cohen            } else {
205219f3792523fe2d55ea791a9286398a6120920690Adam Cohen                return (int) (va.getDuration() - va.getCurrentPlayTime());
205319f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
205419f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
205519f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
205619f3792523fe2d55ea791a9286398a6120920690Adam Cohen
205719f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private void completeAndClearReorderHintAnimations() {
205819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        for (ReorderHintAnimation a: mShakeAnimators.values()) {
205919f3792523fe2d55ea791a9286398a6120920690Adam Cohen            a.completeAnimation();
206019f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
206119f3792523fe2d55ea791a9286398a6120920690Adam Cohen        mShakeAnimators.clear();
206219f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
206319f3792523fe2d55ea791a9286398a6120920690Adam Cohen
206419f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private int getMaxCompletionTime() {
206519f3792523fe2d55ea791a9286398a6120920690Adam Cohen        int maxTime = 0;
206619f3792523fe2d55ea791a9286398a6120920690Adam Cohen        for (ReorderHintAnimation a: mShakeAnimators.values()) {
206719f3792523fe2d55ea791a9286398a6120920690Adam Cohen            maxTime = Math.max(maxTime, a.completionTime());
206819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
206919f3792523fe2d55ea791a9286398a6120920690Adam Cohen        return maxTime;
207019f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
207119f3792523fe2d55ea791a9286398a6120920690Adam Cohen
2072482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private void commitTempPlacement() {
2073482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < mCountX; i++) {
2074482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            for (int j = 0; j < mCountY; j++) {
2075482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                mOccupied[i][j] = mTmpOccupied[i][j];
2076482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
2077482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2078a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        int childCount = mShortcutsAndWidgets.getChildCount();
2079482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < childCount; i++) {
2080ea889a294be004f4b1c21e9b874f9e63abfb8bd6Adam Cohen            View child = mShortcutsAndWidgets.getChildAt(i);
2081ea889a294be004f4b1c21e9b874f9e63abfb8bd6Adam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
2082ea889a294be004f4b1c21e9b874f9e63abfb8bd6Adam Cohen            ItemInfo info = (ItemInfo) child.getTag();
20832acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen            // We do a null check here because the item info can be null in the case of the
20842acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen            // AllApps button in the hotseat.
20852acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen            if (info != null) {
20862acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen                info.cellX = lp.cellX = lp.tmpCellX;
20872acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen                info.cellY = lp.cellY = lp.tmpCellY;
2088bebf042666cffe52039b875a549a582abd78a431Adam Cohen                info.spanX = lp.cellHSpan;
2089bebf042666cffe52039b875a549a582abd78a431Adam Cohen                info.spanY = lp.cellVSpan;
20902acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen            }
2091482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
20922acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen        mLauncher.getWorkspace().updateItemLocationsInDatabase(this);
2093482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2094482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2095482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public void setUseTempCoords(boolean useTempCoords) {
2096a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        int childCount = mShortcutsAndWidgets.getChildCount();
2097482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < childCount; i++) {
2098a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            LayoutParams lp = (LayoutParams) mShortcutsAndWidgets.getChildAt(i).getLayoutParams();
2099482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            lp.useTmpCoords = useTempCoords;
2100482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2101482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2102482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2103482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    ItemConfiguration findConfigurationNoShuffle(int pixelX, int pixelY, int minSpanX, int minSpanY,
2104482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            int spanX, int spanY, View dragView, ItemConfiguration solution) {
2105482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        int[] result = new int[2];
2106482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        int[] resultSpan = new int[2];
2107482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        findNearestVacantArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, null, result,
2108482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                resultSpan);
2109482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (result[0] >= 0 && result[1] >= 0) {
2110482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            copyCurrentStateToSolution(solution, false);
2111482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewX = result[0];
2112482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewY = result[1];
2113482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewSpanX = resultSpan[0];
2114482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewSpanY = resultSpan[1];
2115482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.isSolution = true;
2116482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        } else {
2117482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.isSolution = false;
2118482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2119482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return solution;
2120482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2121482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2122482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public void prepareChildForDrag(View child) {
2123482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsAsUnoccupiedForView(child);
2124482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2125482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
212619f3792523fe2d55ea791a9286398a6120920690Adam Cohen    /* This seems like it should be obvious and straight-forward, but when the direction vector
212719f3792523fe2d55ea791a9286398a6120920690Adam Cohen    needs to match with the notion of the dragView pushing other views, we have to employ
212819f3792523fe2d55ea791a9286398a6120920690Adam Cohen    a slightly more subtle notion of the direction vector. The question is what two points is
212919f3792523fe2d55ea791a9286398a6120920690Adam Cohen    the vector between? The center of the dragView and its desired destination? Not quite, as
213019f3792523fe2d55ea791a9286398a6120920690Adam Cohen    this doesn't necessarily coincide with the interaction of the dragView and items occupying
213119f3792523fe2d55ea791a9286398a6120920690Adam Cohen    those cells. Instead we use some heuristics to often lock the vector to up, down, left
213219f3792523fe2d55ea791a9286398a6120920690Adam Cohen    or right, which helps make pushing feel right.
213319f3792523fe2d55ea791a9286398a6120920690Adam Cohen    */
213419f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private void getDirectionVectorForDrop(int dragViewCenterX, int dragViewCenterY, int spanX,
213519f3792523fe2d55ea791a9286398a6120920690Adam Cohen            int spanY, View dragView, int[] resultDirection) {
213619f3792523fe2d55ea791a9286398a6120920690Adam Cohen        int[] targetDestination = new int[2];
213719f3792523fe2d55ea791a9286398a6120920690Adam Cohen
213819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        findNearestArea(dragViewCenterX, dragViewCenterY, spanX, spanY, targetDestination);
213919f3792523fe2d55ea791a9286398a6120920690Adam Cohen        Rect dragRect = new Rect();
214019f3792523fe2d55ea791a9286398a6120920690Adam Cohen        regionToRect(targetDestination[0], targetDestination[1], spanX, spanY, dragRect);
214119f3792523fe2d55ea791a9286398a6120920690Adam Cohen        dragRect.offset(dragViewCenterX - dragRect.centerX(), dragViewCenterY - dragRect.centerY());
214219f3792523fe2d55ea791a9286398a6120920690Adam Cohen
214319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        Rect dropRegionRect = new Rect();
214419f3792523fe2d55ea791a9286398a6120920690Adam Cohen        getViewsIntersectingRegion(targetDestination[0], targetDestination[1], spanX, spanY,
214519f3792523fe2d55ea791a9286398a6120920690Adam Cohen                dragView, dropRegionRect, mIntersectingViews);
214619f3792523fe2d55ea791a9286398a6120920690Adam Cohen
214719f3792523fe2d55ea791a9286398a6120920690Adam Cohen        int dropRegionSpanX = dropRegionRect.width();
214819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        int dropRegionSpanY = dropRegionRect.height();
214919f3792523fe2d55ea791a9286398a6120920690Adam Cohen
215019f3792523fe2d55ea791a9286398a6120920690Adam Cohen        regionToRect(dropRegionRect.left, dropRegionRect.top, dropRegionRect.width(),
215119f3792523fe2d55ea791a9286398a6120920690Adam Cohen                dropRegionRect.height(), dropRegionRect);
215219f3792523fe2d55ea791a9286398a6120920690Adam Cohen
215319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        int deltaX = (dropRegionRect.centerX() - dragViewCenterX) / spanX;
215419f3792523fe2d55ea791a9286398a6120920690Adam Cohen        int deltaY = (dropRegionRect.centerY() - dragViewCenterY) / spanY;
215519f3792523fe2d55ea791a9286398a6120920690Adam Cohen
215619f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if (dropRegionSpanX == mCountX || spanX == mCountX) {
215719f3792523fe2d55ea791a9286398a6120920690Adam Cohen            deltaX = 0;
215819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
215919f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if (dropRegionSpanY == mCountY || spanY == mCountY) {
216019f3792523fe2d55ea791a9286398a6120920690Adam Cohen            deltaY = 0;
216119f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
216219f3792523fe2d55ea791a9286398a6120920690Adam Cohen
216319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if (deltaX == 0 && deltaY == 0) {
216419f3792523fe2d55ea791a9286398a6120920690Adam Cohen            // No idea what to do, give a random direction.
216519f3792523fe2d55ea791a9286398a6120920690Adam Cohen            resultDirection[0] = 1;
216619f3792523fe2d55ea791a9286398a6120920690Adam Cohen            resultDirection[1] = 0;
216719f3792523fe2d55ea791a9286398a6120920690Adam Cohen        } else {
216819f3792523fe2d55ea791a9286398a6120920690Adam Cohen            computeDirectionVector(deltaX, deltaY, resultDirection);
216919f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
217019f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
217119f3792523fe2d55ea791a9286398a6120920690Adam Cohen
217219f3792523fe2d55ea791a9286398a6120920690Adam Cohen    // For a given cell and span, fetch the set of views intersecting the region.
217319f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private void getViewsIntersectingRegion(int cellX, int cellY, int spanX, int spanY,
217419f3792523fe2d55ea791a9286398a6120920690Adam Cohen            View dragView, Rect boundingRect, ArrayList<View> intersectingViews) {
217519f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if (boundingRect != null) {
217619f3792523fe2d55ea791a9286398a6120920690Adam Cohen            boundingRect.set(cellX, cellY, cellX + spanX, cellY + spanY);
217719f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
217819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        intersectingViews.clear();
217919f3792523fe2d55ea791a9286398a6120920690Adam Cohen        Rect r0 = new Rect(cellX, cellY, cellX + spanX, cellY + spanY);
218019f3792523fe2d55ea791a9286398a6120920690Adam Cohen        Rect r1 = new Rect();
218119f3792523fe2d55ea791a9286398a6120920690Adam Cohen        final int count = mShortcutsAndWidgets.getChildCount();
218219f3792523fe2d55ea791a9286398a6120920690Adam Cohen        for (int i = 0; i < count; i++) {
218319f3792523fe2d55ea791a9286398a6120920690Adam Cohen            View child = mShortcutsAndWidgets.getChildAt(i);
218419f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (child == dragView) continue;
218519f3792523fe2d55ea791a9286398a6120920690Adam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
218619f3792523fe2d55ea791a9286398a6120920690Adam Cohen            r1.set(lp.cellX, lp.cellY, lp.cellX + lp.cellHSpan, lp.cellY + lp.cellVSpan);
218719f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (Rect.intersects(r0, r1)) {
218819f3792523fe2d55ea791a9286398a6120920690Adam Cohen                mIntersectingViews.add(child);
218919f3792523fe2d55ea791a9286398a6120920690Adam Cohen                if (boundingRect != null) {
219019f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    boundingRect.union(r1);
219119f3792523fe2d55ea791a9286398a6120920690Adam Cohen                }
219219f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
219319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
219419f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
219519f3792523fe2d55ea791a9286398a6120920690Adam Cohen
219619f3792523fe2d55ea791a9286398a6120920690Adam Cohen    boolean isNearestDropLocationOccupied(int pixelX, int pixelY, int spanX, int spanY,
219719f3792523fe2d55ea791a9286398a6120920690Adam Cohen            View dragView, int[] result) {
219819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        result = findNearestArea(pixelX, pixelY, spanX, spanY, result);
219919f3792523fe2d55ea791a9286398a6120920690Adam Cohen        getViewsIntersectingRegion(result[0], result[1], spanX, spanY, dragView, null,
220019f3792523fe2d55ea791a9286398a6120920690Adam Cohen                mIntersectingViews);
220119f3792523fe2d55ea791a9286398a6120920690Adam Cohen        return !mIntersectingViews.isEmpty();
220219f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
220319f3792523fe2d55ea791a9286398a6120920690Adam Cohen
220419f3792523fe2d55ea791a9286398a6120920690Adam Cohen    void revertTempState() {
220519f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if (!isItemPlacementDirty() || DESTRUCTIVE_REORDER) return;
220619f3792523fe2d55ea791a9286398a6120920690Adam Cohen        final int count = mShortcutsAndWidgets.getChildCount();
220719f3792523fe2d55ea791a9286398a6120920690Adam Cohen        for (int i = 0; i < count; i++) {
220819f3792523fe2d55ea791a9286398a6120920690Adam Cohen            View child = mShortcutsAndWidgets.getChildAt(i);
220919f3792523fe2d55ea791a9286398a6120920690Adam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
221019f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (lp.tmpCellX != lp.cellX || lp.tmpCellY != lp.cellY) {
221119f3792523fe2d55ea791a9286398a6120920690Adam Cohen                lp.tmpCellX = lp.cellX;
221219f3792523fe2d55ea791a9286398a6120920690Adam Cohen                lp.tmpCellY = lp.cellY;
221319f3792523fe2d55ea791a9286398a6120920690Adam Cohen                animateChildToPosition(child, lp.cellX, lp.cellY, REORDER_ANIMATION_DURATION,
221419f3792523fe2d55ea791a9286398a6120920690Adam Cohen                        0, false, false);
221519f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
221619f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
221719f3792523fe2d55ea791a9286398a6120920690Adam Cohen        completeAndClearReorderHintAnimations();
221819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        setItemPlacementDirty(false);
221919f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
222019f3792523fe2d55ea791a9286398a6120920690Adam Cohen
2221bebf042666cffe52039b875a549a582abd78a431Adam Cohen    boolean createAreaForResize(int cellX, int cellY, int spanX, int spanY,
2222bebf042666cffe52039b875a549a582abd78a431Adam Cohen            View dragView, int[] direction, boolean commit) {
2223bebf042666cffe52039b875a549a582abd78a431Adam Cohen        int[] pixelXY = new int[2];
2224bebf042666cffe52039b875a549a582abd78a431Adam Cohen        regionToCenterPoint(cellX, cellY, spanX, spanY, pixelXY);
2225bebf042666cffe52039b875a549a582abd78a431Adam Cohen
2226bebf042666cffe52039b875a549a582abd78a431Adam Cohen        // First we determine if things have moved enough to cause a different layout
2227bebf042666cffe52039b875a549a582abd78a431Adam Cohen        ItemConfiguration swapSolution = simpleSwap(pixelXY[0], pixelXY[1], spanX, spanY,
2228bebf042666cffe52039b875a549a582abd78a431Adam Cohen                 spanX,  spanY, direction, dragView,  true,  new ItemConfiguration());
2229bebf042666cffe52039b875a549a582abd78a431Adam Cohen
2230bebf042666cffe52039b875a549a582abd78a431Adam Cohen        setUseTempCoords(true);
2231bebf042666cffe52039b875a549a582abd78a431Adam Cohen        if (swapSolution != null && swapSolution.isSolution) {
2232bebf042666cffe52039b875a549a582abd78a431Adam Cohen            // If we're just testing for a possible location (MODE_ACCEPT_DROP), we don't bother
2233bebf042666cffe52039b875a549a582abd78a431Adam Cohen            // committing anything or animating anything as we just want to determine if a solution
2234bebf042666cffe52039b875a549a582abd78a431Adam Cohen            // exists
2235bebf042666cffe52039b875a549a582abd78a431Adam Cohen            copySolutionToTempState(swapSolution, dragView);
2236bebf042666cffe52039b875a549a582abd78a431Adam Cohen            setItemPlacementDirty(true);
2237bebf042666cffe52039b875a549a582abd78a431Adam Cohen            animateItemsToSolution(swapSolution, dragView, commit);
2238bebf042666cffe52039b875a549a582abd78a431Adam Cohen
2239bebf042666cffe52039b875a549a582abd78a431Adam Cohen            if (commit) {
2240bebf042666cffe52039b875a549a582abd78a431Adam Cohen                commitTempPlacement();
2241bebf042666cffe52039b875a549a582abd78a431Adam Cohen                completeAndClearReorderHintAnimations();
2242bebf042666cffe52039b875a549a582abd78a431Adam Cohen                setItemPlacementDirty(false);
2243bebf042666cffe52039b875a549a582abd78a431Adam Cohen            } else {
2244bebf042666cffe52039b875a549a582abd78a431Adam Cohen                beginOrAdjustHintAnimations(swapSolution, dragView,
2245bebf042666cffe52039b875a549a582abd78a431Adam Cohen                        REORDER_ANIMATION_DURATION);
2246bebf042666cffe52039b875a549a582abd78a431Adam Cohen            }
2247bebf042666cffe52039b875a549a582abd78a431Adam Cohen            mShortcutsAndWidgets.requestLayout();
2248bebf042666cffe52039b875a549a582abd78a431Adam Cohen        }
2249bebf042666cffe52039b875a549a582abd78a431Adam Cohen        return swapSolution.isSolution;
2250bebf042666cffe52039b875a549a582abd78a431Adam Cohen    }
2251bebf042666cffe52039b875a549a582abd78a431Adam Cohen
2252482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    int[] createArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, int spanY,
2253482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            View dragView, int[] result, int resultSpan[], int mode) {
2254482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // First we determine if things have moved enough to cause a different layout
225547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        result = findNearestArea(pixelX, pixelY, spanX, spanY, result);
2256482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2257482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (resultSpan == null) {
2258482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            resultSpan = new int[2];
2259482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2260482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
226119f3792523fe2d55ea791a9286398a6120920690Adam Cohen        // When we are checking drop validity or actually dropping, we don't recompute the
226219f3792523fe2d55ea791a9286398a6120920690Adam Cohen        // direction vector, since we want the solution to match the preview, and it's possible
226319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        // that the exact position of the item has changed to result in a new reordering outcome.
2264b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen        if ((mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL || mode == MODE_ACCEPT_DROP)
2265b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen               && mPreviousReorderDirection[0] != INVALID_DIRECTION) {
226619f3792523fe2d55ea791a9286398a6120920690Adam Cohen            mDirectionVector[0] = mPreviousReorderDirection[0];
226719f3792523fe2d55ea791a9286398a6120920690Adam Cohen            mDirectionVector[1] = mPreviousReorderDirection[1];
226819f3792523fe2d55ea791a9286398a6120920690Adam Cohen            // We reset this vector after drop
2269b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen            if (mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL) {
2270b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen                mPreviousReorderDirection[0] = INVALID_DIRECTION;
2271b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen                mPreviousReorderDirection[1] = INVALID_DIRECTION;
227219f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
227319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        } else {
227419f3792523fe2d55ea791a9286398a6120920690Adam Cohen            getDirectionVectorForDrop(pixelX, pixelY, spanX, spanY, dragView, mDirectionVector);
227519f3792523fe2d55ea791a9286398a6120920690Adam Cohen            mPreviousReorderDirection[0] = mDirectionVector[0];
227619f3792523fe2d55ea791a9286398a6120920690Adam Cohen            mPreviousReorderDirection[1] = mDirectionVector[1];
227719f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
227819f3792523fe2d55ea791a9286398a6120920690Adam Cohen
2279482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        ItemConfiguration swapSolution = simpleSwap(pixelX, pixelY, minSpanX, minSpanY,
2280482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                 spanX,  spanY, mDirectionVector, dragView,  true,  new ItemConfiguration());
2281482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2282482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // We attempt the approach which doesn't shuffle views at all
2283482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        ItemConfiguration noShuffleSolution = findConfigurationNoShuffle(pixelX, pixelY, minSpanX,
2284482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                minSpanY, spanX, spanY, dragView, new ItemConfiguration());
2285482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2286482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        ItemConfiguration finalSolution = null;
2287482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (swapSolution.isSolution && swapSolution.area() >= noShuffleSolution.area()) {
2288482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            finalSolution = swapSolution;
2289482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        } else if (noShuffleSolution.isSolution) {
2290482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            finalSolution = noShuffleSolution;
2291482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2292482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2293482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        boolean foundSolution = true;
2294482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (!DESTRUCTIVE_REORDER) {
2295482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            setUseTempCoords(true);
2296482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2297482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2298482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (finalSolution != null) {
2299482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            result[0] = finalSolution.dragViewX;
2300482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            result[1] = finalSolution.dragViewY;
2301482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            resultSpan[0] = finalSolution.dragViewSpanX;
2302482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            resultSpan[1] = finalSolution.dragViewSpanY;
2303482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2304482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            // If we're just testing for a possible location (MODE_ACCEPT_DROP), we don't bother
2305482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            // committing anything or animating anything as we just want to determine if a solution
2306482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            // exists
2307482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (mode == MODE_DRAG_OVER || mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL) {
2308482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                if (!DESTRUCTIVE_REORDER) {
2309482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    copySolutionToTempState(finalSolution, dragView);
2310482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                }
2311482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                setItemPlacementDirty(true);
2312482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                animateItemsToSolution(finalSolution, dragView, mode == MODE_ON_DROP);
2313482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
231419f3792523fe2d55ea791a9286398a6120920690Adam Cohen                if (!DESTRUCTIVE_REORDER &&
231519f3792523fe2d55ea791a9286398a6120920690Adam Cohen                        (mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL)) {
2316482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    commitTempPlacement();
231719f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    completeAndClearReorderHintAnimations();
231819f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    setItemPlacementDirty(false);
231919f3792523fe2d55ea791a9286398a6120920690Adam Cohen                } else {
232019f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    beginOrAdjustHintAnimations(finalSolution, dragView,
232119f3792523fe2d55ea791a9286398a6120920690Adam Cohen                            REORDER_ANIMATION_DURATION);
2322482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                }
2323482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
2324482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        } else {
2325482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            foundSolution = false;
2326482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            result[0] = result[1] = resultSpan[0] = resultSpan[1] = -1;
2327482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2328482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2329482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if ((mode == MODE_ON_DROP || !foundSolution) && !DESTRUCTIVE_REORDER) {
2330482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            setUseTempCoords(false);
2331482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2332482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2333a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.requestLayout();
2334482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return result;
2335482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2336482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
233719f3792523fe2d55ea791a9286398a6120920690Adam Cohen    void setItemPlacementDirty(boolean dirty) {
233819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        mItemPlacementDirty = dirty;
2339482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
234019f3792523fe2d55ea791a9286398a6120920690Adam Cohen    boolean isItemPlacementDirty() {
234119f3792523fe2d55ea791a9286398a6120920690Adam Cohen        return mItemPlacementDirty;
2342482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2343482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2344482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private class ItemConfiguration {
23458baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        HashMap<View, CellAndSpan> map = new HashMap<View, CellAndSpan>();
2346482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        boolean isSolution = false;
2347482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        int dragViewX, dragViewY, dragViewSpanX, dragViewSpanY;
2348482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2349482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        int area() {
2350482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            return dragViewSpanX * dragViewSpanY;
2351482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
23528baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen    }
23538baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen
23548baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen    private class CellAndSpan {
23558baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        int x, y;
23568baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        int spanX, spanY;
23578baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen
23588baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        public CellAndSpan(int x, int y, int spanX, int spanY) {
23598baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            this.x = x;
23608baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            this.y = y;
23618baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            this.spanX = spanX;
23628baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            this.spanY = spanY;
2363482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2364482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2365482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2366df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    /**
2367df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * Find a vacant area that will fit the given bounds nearest the requested
2368df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * cell location. Uses Euclidean distance to score multiple vacant areas.
2369df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     *
2370df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param pixelX The X location at which you want to search for a vacant area.
2371df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param pixelY The Y location at which you want to search for a vacant area.
2372df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param spanX Horizontal span of the object.
2373df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param spanY Vertical span of the object.
2374df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param ignoreView Considers space occupied by this view as unoccupied
2375df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param result Previously returned value to possibly recycle.
2376df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @return The X, Y cell of a vacant area that can contain this object,
2377df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     *         nearest the requested location.
2378df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     */
2379df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    int[] findNearestVacantArea(
2380df0353815c629fc678824b07a234b89a1ff94208Adam Cohen            int pixelX, int pixelY, int spanX, int spanY, View ignoreView, int[] result) {
2381df0353815c629fc678824b07a234b89a1ff94208Adam Cohen        return findNearestArea(pixelX, pixelY, spanX, spanY, ignoreView, true, result);
2382df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    }
2383df0353815c629fc678824b07a234b89a1ff94208Adam Cohen
2384df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    /**
2385d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * Find a vacant area that will fit the given bounds nearest the requested
2386d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * cell location. Uses Euclidean distance to score multiple vacant areas.
2387d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *
2388d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param pixelX The X location at which you want to search for a vacant area.
2389d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param pixelY The Y location at which you want to search for a vacant area.
2390d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param minSpanX The minimum horizontal span required
2391d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param minSpanY The minimum vertical span required
2392d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param spanX Horizontal span of the object.
2393d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param spanY Vertical span of the object.
2394d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param ignoreView Considers space occupied by this view as unoccupied
2395d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param result Previously returned value to possibly recycle.
2396d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @return The X, Y cell of a vacant area that can contain this object,
2397d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *         nearest the requested location.
2398d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     */
2399d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    int[] findNearestVacantArea(int pixelX, int pixelY, int minSpanX, int minSpanY,
2400d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            int spanX, int spanY, View ignoreView, int[] result, int[] resultSpan) {
2401482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return findNearestArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, ignoreView, true,
2402482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                result, resultSpan, mOccupied);
2403d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    }
2404d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen
2405d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    /**
2406df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * Find a starting cell position that will fit the given bounds nearest the requested
2407df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * cell location. Uses Euclidean distance to score multiple vacant areas.
2408df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     *
2409df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param pixelX The X location at which you want to search for a vacant area.
2410df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param pixelY The Y location at which you want to search for a vacant area.
2411df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param spanX Horizontal span of the object.
2412df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param spanY Vertical span of the object.
2413df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param ignoreView Considers space occupied by this view as unoccupied
2414df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param result Previously returned value to possibly recycle.
2415df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @return The X, Y cell of a vacant area that can contain this object,
2416df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     *         nearest the requested location.
2417df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     */
2418df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    int[] findNearestArea(
2419df0353815c629fc678824b07a234b89a1ff94208Adam Cohen            int pixelX, int pixelY, int spanX, int spanY, int[] result) {
2420df0353815c629fc678824b07a234b89a1ff94208Adam Cohen        return findNearestArea(pixelX, pixelY, spanX, spanY, null, false, result);
2421df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    }
2422df0353815c629fc678824b07a234b89a1ff94208Adam Cohen
24230280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    boolean existsEmptyCell() {
24240280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        return findCellForSpan(null, 1, 1);
24250280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
24260280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
24270280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    /**
24280280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * Finds the upper-left coordinate of the first rectangle in the grid that can
24290280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * hold a cell of the specified dimensions. If intersectX and intersectY are not -1,
24300280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * then this method will only return coordinates for rectangles that contain the cell
24310280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * (intersectX, intersectY)
24320280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     *
24330280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param cellXY The array that will contain the position of a vacant cell if such a cell
24340280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     *               can be found.
24350280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param spanX The horizontal span of the cell we want to find.
24360280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param spanY The vertical span of the cell we want to find.
24370280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     *
24380280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @return True if a vacant cell of the specified dimension was found, false otherwise.
24390280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     */
24400280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    boolean findCellForSpan(int[] cellXY, int spanX, int spanY) {
2441482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return findCellForSpanThatIntersectsIgnoring(cellXY, spanX, spanY, -1, -1, null, mOccupied);
24420280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
24430280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
24440280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    /**
24450280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * Like above, but ignores any cells occupied by the item "ignoreView"
24460280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     *
24470280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param cellXY The array that will contain the position of a vacant cell if such a cell
24480280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     *               can be found.
24490280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param spanX The horizontal span of the cell we want to find.
24500280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param spanY The vertical span of the cell we want to find.
24510280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param ignoreView The home screen item we should treat as not occupying any space
24520280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @return
24530280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     */
24540280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    boolean findCellForSpanIgnoring(int[] cellXY, int spanX, int spanY, View ignoreView) {
2455482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return findCellForSpanThatIntersectsIgnoring(cellXY, spanX, spanY, -1, -1,
2456482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                ignoreView, mOccupied);
24570280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
24580280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
24590280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    /**
24600280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * Like above, but if intersectX and intersectY are not -1, then this method will try to
24610280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * return coordinates for rectangles that contain the cell [intersectX, intersectY]
24620280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     *
24630280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param spanX The horizontal span of the cell we want to find.
24640280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param spanY The vertical span of the cell we want to find.
24650280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param ignoreView The home screen item we should treat as not occupying any space
24660280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param intersectX The X coordinate of the cell that we should try to overlap
24670280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param intersectX The Y coordinate of the cell that we should try to overlap
24680280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     *
24690280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @return True if a vacant cell of the specified dimension was found, false otherwise.
24700280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     */
24710280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    boolean findCellForSpanThatIntersects(int[] cellXY, int spanX, int spanY,
24720280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            int intersectX, int intersectY) {
24730280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        return findCellForSpanThatIntersectsIgnoring(
2474482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                cellXY, spanX, spanY, intersectX, intersectY, null, mOccupied);
24750280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
24760280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
24770280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    /**
24780280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * The superset of the above two methods
24790280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     */
24800280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    boolean findCellForSpanThatIntersectsIgnoring(int[] cellXY, int spanX, int spanY,
2481482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            int intersectX, int intersectY, View ignoreView, boolean occupied[][]) {
2482c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka        // mark space take by ignoreView as available (method checks if ignoreView is null)
2483482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsAsUnoccupiedForView(ignoreView, occupied);
24840280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
248528750fba6a2d141eb9a1e566718c17236030b815Michael Jurka        boolean foundCell = false;
24860280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        while (true) {
24870280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            int startX = 0;
24880280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            if (intersectX >= 0) {
24890280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                startX = Math.max(startX, intersectX - (spanX - 1));
24900280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            }
24910280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            int endX = mCountX - (spanX - 1);
24920280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            if (intersectX >= 0) {
24930280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                endX = Math.min(endX, intersectX + (spanX - 1) + (spanX == 1 ? 1 : 0));
24940280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            }
24950280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            int startY = 0;
24960280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            if (intersectY >= 0) {
24970280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                startY = Math.max(startY, intersectY - (spanY - 1));
24980280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            }
24990280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            int endY = mCountY - (spanY - 1);
25000280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            if (intersectY >= 0) {
25010280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                endY = Math.min(endY, intersectY + (spanY - 1) + (spanY == 1 ? 1 : 0));
25020280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            }
25030280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
2504bbc60d8e79416e37cbede55c159bf6aaa6c171d5Winson Chung            for (int y = startY; y < endY && !foundCell; y++) {
25050280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                inner:
2506bbc60d8e79416e37cbede55c159bf6aaa6c171d5Winson Chung                for (int x = startX; x < endX; x++) {
25070280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                    for (int i = 0; i < spanX; i++) {
25080280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                        for (int j = 0; j < spanY; j++) {
2509482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                            if (occupied[x + i][y + j]) {
2510bbc60d8e79416e37cbede55c159bf6aaa6c171d5Winson Chung                                // small optimization: we can skip to after the column we just found
25110280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                                // an occupied cell
2512bbc60d8e79416e37cbede55c159bf6aaa6c171d5Winson Chung                                x += i;
25130280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                                continue inner;
25140280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                            }
25150280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                        }
25160280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                    }
25170280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                    if (cellXY != null) {
25180280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                        cellXY[0] = x;
25190280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                        cellXY[1] = y;
25200280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                    }
252128750fba6a2d141eb9a1e566718c17236030b815Michael Jurka                    foundCell = true;
252228750fba6a2d141eb9a1e566718c17236030b815Michael Jurka                    break;
25230280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                }
25240280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            }
25250280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            if (intersectX == -1 && intersectY == -1) {
25260280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                break;
25270280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            } else {
25280280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                // if we failed to find anything, try again but without any requirements of
25290280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                // intersecting
25300280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                intersectX = -1;
25310280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                intersectY = -1;
25320280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                continue;
25330280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            }
25340280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        }
25350280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
2536c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka        // re-mark space taken by ignoreView as occupied
2537482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsAsOccupiedForView(ignoreView, occupied);
253828750fba6a2d141eb9a1e566718c17236030b815Michael Jurka        return foundCell;
25390280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
25400280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
254131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
2542c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung     * A drag event has begun over this layout.
2543c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung     * It may have begun over this layout (in which case onDragChild is called first),
2544c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung     * or it may have begun on another layout.
2545c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung     */
2546c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung    void onDragEnter() {
2547c6cc61d45836e4081920883cc4d448ccb0bb8417Adam Cohen        mDragEnforcer.onDragEnter();
2548c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung        if (!mDragging) {
2549c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung            // Fade in the drag indicators
2550c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung            if (mCrosshairsAnimator != null) {
2551c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung                mCrosshairsAnimator.animateIn();
2552c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung            }
2553c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung        }
2554c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung        mDragging = true;
2555c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung    }
2556c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung
2557c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung    /**
25580280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * Called when drag has left this CellLayout or has been completed (successfully or not)
25596569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     */
25600280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    void onDragExit() {
2561c6cc61d45836e4081920883cc4d448ccb0bb8417Adam Cohen        mDragEnforcer.onDragExit();
25624be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        // This can actually be called when we aren't in a drag, e.g. when adding a new
25634be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        // item to this layout via the customize drawer.
25644be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        // Guard against that case.
25654be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        if (mDragging) {
25664be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            mDragging = false;
25676569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
25684be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            // Fade out the drag indicators
25694be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            if (mCrosshairsAnimator != null) {
25704be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                mCrosshairsAnimator.animateOut();
25714be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            }
25724be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        }
257308ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy
257408ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy        // Invalidate the drag data
2575d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        mDragCell[0] = mDragCell[1] = -1;
257608ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy        mDragOutlineAnims[mDragOutlineCurrent].animateOut();
257708ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy        mDragOutlineCurrent = (mDragOutlineCurrent + 1) % mDragOutlineAnims.length;
257819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        revertTempState();
257933945b21544bc98381df17726a3537c292d8c985Michael Jurka        setIsDragOverlapping(false);
25806569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    }
25816569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
25826569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    /**
2583aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     * Mark a child as having been dropped.
2584de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy     * At the beginning of the drag operation, the child may have been on another
2585ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy     * screen, but it is re-parented before this method is called.
258631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     *
258731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param child The child that is being dropped
258831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
2589716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    void onDropChild(View child) {
2590d94533d04a5f8f5485f106d10af60169857ea899Romain Guy        if (child != null) {
2591d94533d04a5f8f5485f106d10af60169857ea899Romain Guy            LayoutParams lp = (LayoutParams) child.getLayoutParams();
259284f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy            lp.dropped = true;
2593d94533d04a5f8f5485f106d10af60169857ea899Romain Guy            child.requestLayout();
2594d94533d04a5f8f5485f106d10af60169857ea899Romain Guy        }
259531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
259631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
259731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
259831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * Computes a bounding rectangle for a range of cells
2599aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     *
260031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param cellX X coordinate of upper left corner expressed as a cell position
260131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param cellY Y coordinate of upper left corner expressed as a cell position
2602aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     * @param cellHSpan Width in cells
260331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param cellVSpan Height in cells
26046569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     * @param resultRect Rect into which to put the results
260531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
2606d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    public void cellToRect(int cellX, int cellY, int cellHSpan, int cellVSpan, Rect resultRect) {
260731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        final int cellWidth = mCellWidth;
260831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        final int cellHeight = mCellHeight;
260931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        final int widthGap = mWidthGap;
261031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        final int heightGap = mHeightGap;
2611aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
26124b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int hStartPadding = getPaddingLeft();
26134b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int vStartPadding = getPaddingTop();
2614aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
261531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int width = cellHSpan * cellWidth + ((cellHSpan - 1) * widthGap);
261631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int height = cellVSpan * cellHeight + ((cellVSpan - 1) * heightGap);
261731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
261831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int x = hStartPadding + cellX * (cellWidth + widthGap);
261931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int y = vStartPadding + cellY * (cellHeight + heightGap);
2620aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
26216569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        resultRect.set(x, y, x + width, y + height);
262231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
2623aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
262431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
2625aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     * Computes the required horizontal and vertical cell spans to always
262631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * fit the given rectangle.
2627aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     *
262831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param width Width in pixels
262931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param height Height in pixels
26308f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy     * @param result An array of length 2 in which to store the result (may be null).
263131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
26328f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy    public int[] rectToCell(int width, int height, int[] result) {
26339987a5c45e7d01a780d73b269bdce8d8a5309219Michael Jurka        return rectToCell(getResources(), width, height, result);
26349987a5c45e7d01a780d73b269bdce8d8a5309219Michael Jurka    }
26359987a5c45e7d01a780d73b269bdce8d8a5309219Michael Jurka
26369987a5c45e7d01a780d73b269bdce8d8a5309219Michael Jurka    public static int[] rectToCell(Resources resources, int width, int height, int[] result) {
263731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // Always assume we're working with the smallest span to make sure we
263831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // reserve enough space in both orientations.
263979e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato        int actualWidth = resources.getDimensionPixelSize(R.dimen.workspace_cell_width);
264079e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato        int actualHeight = resources.getDimensionPixelSize(R.dimen.workspace_cell_height);
264131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int smallerSize = Math.min(actualWidth, actualHeight);
264279e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato
264331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // Always round up to next largest cell
264454c725cc294cd43ed0650179bfae64a622547660Winson Chung        int spanX = (int) Math.ceil(width / (float) smallerSize);
264554c725cc294cd43ed0650179bfae64a622547660Winson Chung        int spanY = (int) Math.ceil(height / (float) smallerSize);
264679e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato
26478f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy        if (result == null) {
26488f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy            return new int[] { spanX, spanY };
26498f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy        }
26508f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy        result[0] = spanX;
26518f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy        result[1] = spanY;
26528f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy        return result;
265331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
265431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
2655f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka    public int[] cellSpansToSize(int hSpans, int vSpans) {
2656f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka        int[] size = new int[2];
2657f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka        size[0] = hSpans * mCellWidth + (hSpans - 1) * mWidthGap;
2658f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka        size[1] = vSpans * mCellHeight + (vSpans - 1) * mHeightGap;
2659f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka        return size;
2660f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka    }
2661f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka
266231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
2663047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy     * Calculate the grid spans needed to fit given item
2664047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy     */
2665047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy    public void calculateSpans(ItemInfo info) {
2666047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        final int minWidth;
2667047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        final int minHeight;
2668047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy
2669047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        if (info instanceof LauncherAppWidgetInfo) {
2670047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy            minWidth = ((LauncherAppWidgetInfo) info).minWidth;
2671047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy            minHeight = ((LauncherAppWidgetInfo) info).minHeight;
2672047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        } else if (info instanceof PendingAddWidgetInfo) {
2673047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy            minWidth = ((PendingAddWidgetInfo) info).minWidth;
2674047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy            minHeight = ((PendingAddWidgetInfo) info).minHeight;
2675047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        } else {
2676047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy            // It's not a widget, so it must be 1x1
2677047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy            info.spanX = info.spanY = 1;
2678047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy            return;
2679047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        }
2680047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        int[] spans = rectToCell(minWidth, minHeight, null);
2681047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        info.spanX = spans[0];
2682047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        info.spanY = spans[1];
2683047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy    }
2684047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy
2685047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy    /**
268631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * Find the first vacant cell, if there is one.
268731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     *
268831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param vacant Holds the x and y coordinate of the vacant cell
268931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param spanX Horizontal cell span.
269031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param spanY Vertical cell span.
2691aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     *
269231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @return True if a vacant cell was found
269331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
269431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public boolean getVacantCell(int[] vacant, int spanX, int spanY) {
269531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
26960280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        return findVacantCell(vacant, spanX, spanY, mCountX, mCountY, mOccupied);
269731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
269831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
269931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    static boolean findVacantCell(int[] vacant, int spanX, int spanY,
270031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            int xCount, int yCount, boolean[][] occupied) {
270131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
27022801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        for (int y = 0; y < yCount; y++) {
27032801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            for (int x = 0; x < xCount; x++) {
270431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                boolean available = !occupied[x][y];
270531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectout:            for (int i = x; i < x + spanX - 1 && x < xCount; i++) {
270631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                    for (int j = y; j < y + spanY - 1 && y < yCount; j++) {
270731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                        available = available && !occupied[i][j];
270831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                        if (!available) break out;
270931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                    }
271031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                }
271131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
271231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                if (available) {
271331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                    vacant[0] = x;
271431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                    vacant[1] = y;
271531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                    return true;
271631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                }
271731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            }
271831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
271931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
272031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        return false;
272131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
272231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
27230280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    private void clearOccupiedCells() {
27240280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        for (int x = 0; x < mCountX; x++) {
27250280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            for (int y = 0; y < mCountY; y++) {
27260280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                mOccupied[x][y] = false;
272731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            }
272831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
27290280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
273031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
2731d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    public void onMove(View view, int newCellX, int newCellY, int newSpanX, int newSpanY) {
27320280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        markCellsAsUnoccupiedForView(view);
2733482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsForView(newCellX, newCellY, newSpanX, newSpanY, mOccupied, true);
27340280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
273531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
2736d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    public void markCellsAsOccupiedForView(View view) {
2737482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsAsOccupiedForView(view, mOccupied);
2738482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2739482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public void markCellsAsOccupiedForView(View view, boolean[][] occupied) {
2740a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        if (view == null || view.getParent() != mShortcutsAndWidgets) return;
27410280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        LayoutParams lp = (LayoutParams) view.getLayoutParams();
2742482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, occupied, true);
27430280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
27440280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
2745d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    public void markCellsAsUnoccupiedForView(View view) {
2746482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsAsUnoccupiedForView(view, mOccupied);
2747482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2748482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public void markCellsAsUnoccupiedForView(View view, boolean occupied[][]) {
2749a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        if (view == null || view.getParent() != mShortcutsAndWidgets) return;
27500280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        LayoutParams lp = (LayoutParams) view.getLayoutParams();
2751482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, occupied, false);
27520280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
27530280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
2754482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private void markCellsForView(int cellX, int cellY, int spanX, int spanY, boolean[][] occupied,
2755482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            boolean value) {
2756482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (cellX < 0 || cellY < 0) return;
27570280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        for (int x = cellX; x < cellX + spanX && x < mCountX; x++) {
27580280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            for (int y = cellY; y < cellY + spanY && y < mCountY; y++) {
2759482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                occupied[x][y] = value;
276031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            }
276131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
276231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
276331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
27642801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    public int getDesiredWidth() {
27658b805b17158886035b38261eb611d8641701ae43Michael Jurka        return getPaddingLeft() + getPaddingRight() + (mCountX * mCellWidth) +
27662801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen                (Math.max((mCountX - 1), 0) * mWidthGap);
27672801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    }
27682801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
27692801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    public int getDesiredHeight()  {
27708b805b17158886035b38261eb611d8641701ae43Michael Jurka        return getPaddingTop() + getPaddingBottom() + (mCountY * mCellHeight) +
27712801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen                (Math.max((mCountY - 1), 0) * mHeightGap);
27722801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    }
27732801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
277466d72178af91d455700875635473be942bc90e54Michael Jurka    public boolean isOccupied(int x, int y) {
277566d72178af91d455700875635473be942bc90e54Michael Jurka        if (x < mCountX && y < mCountY) {
277666d72178af91d455700875635473be942bc90e54Michael Jurka            return mOccupied[x][y];
277766d72178af91d455700875635473be942bc90e54Michael Jurka        } else {
277866d72178af91d455700875635473be942bc90e54Michael Jurka            throw new RuntimeException("Position exceeds the bound of this CellLayout");
277966d72178af91d455700875635473be942bc90e54Michael Jurka        }
278066d72178af91d455700875635473be942bc90e54Michael Jurka    }
278166d72178af91d455700875635473be942bc90e54Michael Jurka
278231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
278331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
278431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        return new CellLayout.LayoutParams(getContext(), attrs);
278531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
278631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
278731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
278831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
278931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        return p instanceof CellLayout.LayoutParams;
279031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
279131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
279231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
279331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
279431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        return new CellLayout.LayoutParams(p);
279531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
279631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
2797aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung    public static class CellLayoutAnimationController extends LayoutAnimationController {
2798aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        public CellLayoutAnimationController(Animation animation, float delay) {
2799aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            super(animation, delay);
2800aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        }
2801aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
2802aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        @Override
2803aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        protected long getDelayForView(View view) {
2804aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            return (int) (Math.random() * 150);
2805aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        }
2806aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung    }
2807aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
280831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public static class LayoutParams extends ViewGroup.MarginLayoutParams {
280931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        /**
281031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         * Horizontal location of the item in the grid.
281131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         */
281231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        @ViewDebug.ExportedProperty
281331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public int cellX;
281431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
281531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        /**
281631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         * Vertical location of the item in the grid.
281731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         */
281831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        @ViewDebug.ExportedProperty
281931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public int cellY;
282031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
282131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        /**
2822482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         * Temporary horizontal location of the item in the grid during reorder
2823482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         */
2824482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        public int tmpCellX;
2825482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2826482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        /**
2827482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         * Temporary vertical location of the item in the grid during reorder
2828482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         */
2829482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        public int tmpCellY;
2830482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2831482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        /**
2832482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         * Indicates that the temporary coordinates should be used to layout the items
2833482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         */
2834482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        public boolean useTmpCoords;
2835482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2836482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        /**
283731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         * Number of cells spanned horizontally by the item.
283831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         */
283931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        @ViewDebug.ExportedProperty
284031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public int cellHSpan;
284131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
284231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        /**
284331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         * Number of cells spanned vertically by the item.
284431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         */
284531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        @ViewDebug.ExportedProperty
284631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public int cellVSpan;
2847aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
28481b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen        /**
28491b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen         * Indicates whether the item will set its x, y, width and height parameters freely,
28501b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen         * or whether these will be computed based on cellX, cellY, cellHSpan and cellVSpan.
28511b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen         */
2852d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        public boolean isLockedToGrid = true;
2853d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
2854482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        /**
2855482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         * Indicates whether this item can be reordered. Always true except in the case of the
2856482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         * the AllApps button.
2857482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         */
2858482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        public boolean canReorder = true;
2859482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
286031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // X coordinate of the view in the layout.
286131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        @ViewDebug.ExportedProperty
286231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int x;
286331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // Y coordinate of the view in the layout.
286431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        @ViewDebug.ExportedProperty
286531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int y;
286631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
286784f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy        boolean dropped;
2868fcb9e7144e58614f5ae0e9b272fb7ce040848c67Romain Guy
286931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public LayoutParams(Context c, AttributeSet attrs) {
287031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            super(c, attrs);
287131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            cellHSpan = 1;
287231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            cellVSpan = 1;
287331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
287431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
287531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public LayoutParams(ViewGroup.LayoutParams source) {
287631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            super(source);
287731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            cellHSpan = 1;
287831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            cellVSpan = 1;
287931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
2880aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
2881aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        public LayoutParams(LayoutParams source) {
2882aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            super(source);
2883aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            this.cellX = source.cellX;
2884aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            this.cellY = source.cellY;
2885aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            this.cellHSpan = source.cellHSpan;
2886aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            this.cellVSpan = source.cellVSpan;
2887aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        }
2888aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
288931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public LayoutParams(int cellX, int cellY, int cellHSpan, int cellVSpan) {
28908f19cdd62f6e2be05e3890916eabd11317ae1bc2Romain Guy            super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
289131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            this.cellX = cellX;
289231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            this.cellY = cellY;
289331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            this.cellHSpan = cellHSpan;
289431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            this.cellVSpan = cellVSpan;
289531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
289631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
28977f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public void setup(int cellWidth, int cellHeight, int widthGap, int heightGap) {
2898d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            if (isLockedToGrid) {
2899d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                final int myCellHSpan = cellHSpan;
2900d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                final int myCellVSpan = cellVSpan;
2901482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                final int myCellX = useTmpCoords ? tmpCellX : cellX;
2902482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                final int myCellY = useTmpCoords ? tmpCellY : cellY;
29031b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen
2904d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                width = myCellHSpan * cellWidth + ((myCellHSpan - 1) * widthGap) -
2905d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                        leftMargin - rightMargin;
2906d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                height = myCellVSpan * cellHeight + ((myCellVSpan - 1) * heightGap) -
2907d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                        topMargin - bottomMargin;
2908eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                x = (int) (myCellX * (cellWidth + widthGap) + leftMargin);
2909eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                y = (int) (myCellY * (cellHeight + heightGap) + topMargin);
2910d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            }
2911d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        }
2912d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
2913aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        public String toString() {
2914aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            return "(" + this.cellX + ", " + this.cellY + ")";
2915aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        }
29167f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
29177f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public void setWidth(int width) {
29187f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            this.width = width;
29197f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
29207f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
29217f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public int getWidth() {
29227f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            return width;
29237f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
29247f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
29257f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public void setHeight(int height) {
29267f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            this.height = height;
29277f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
29287f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
29297f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public int getHeight() {
29307f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            return height;
29317f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
29327f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
29337f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public void setX(int x) {
29347f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            this.x = x;
29357f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
29367f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
29377f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public int getX() {
29387f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            return x;
29397f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
29407f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
29417f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public void setY(int y) {
29427f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            this.y = y;
29437f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
29447f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
29457f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public int getY() {
29467f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            return y;
29477f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
294831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
294931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
29500280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    // This class stores info for two purposes:
29510280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    // 1. When dragging items (mDragInfo in Workspace), we store the View, its cellX & cellY,
29520280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    //    its spanX, spanY, and the screen it is on
29530280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    // 2. When long clicking on an empty cell in a CellLayout, we save information about the
29540280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    //    cellX and cellY coordinates and which page was clicked. We then set this as a tag on
29550280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    //    the CellLayout that was long clicked
2956e5fb0f27bca7afb996258a7163c76ca7390d7bffMichael Jurka    static final class CellInfo {
295731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        View cell;
2958a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka        int cellX = -1;
2959a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka        int cellY = -1;
296031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int spanX;
296131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int spanY;
296231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int screen;
29633d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        long container;
296431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
296531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        @Override
296631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public String toString() {
2967aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            return "Cell[view=" + (cell == null ? "null" : cell.getClass())
2968aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung                    + ", x=" + cellX + ", y=" + cellY + "]";
296931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
297031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
2971d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka
2972d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka    public boolean lastDownOnOccupiedCell() {
2973d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka        return mLastDownOnOccupiedCell;
2974d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka    }
297531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project}
2976