CellLayout.java revision 50e6e565bcf1f51023c2a14d31b17c8a550aac84
131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project/*
231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project *
431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * you may not use this file except in compliance with the License.
631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * You may obtain a copy of the License at
731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project *
831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project *
1031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
1131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
1231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * See the License for the specific language governing permissions and
1431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * limitations under the License.
1531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */
1631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
17a5902524d4403885eb4c50360bf3465c6be796efJoe Onoratopackage com.android.launcher2;
1831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
194be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onoratoimport android.animation.Animator;
2050e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keelyimport android.animation.AnimatorSet;
2150e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keelyimport android.animation.ObjectAnimator;
224be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onoratoimport android.animation.AnimatorListenerAdapter;
2300397b1d9233409d9d6b233b077ae12d09768ce8Chet Haaseimport android.animation.TimeInterpolator;
24de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroyimport android.animation.ValueAnimator;
25de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroyimport android.animation.ValueAnimator.AnimatorUpdateListener;
2631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.content.Context;
2779e56263dbcbe85dc434df372bc6e6730aa13477Joe Onoratoimport android.content.res.Resources;
28aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chungimport android.content.res.TypedArray;
294be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onoratoimport android.graphics.Bitmap;
30aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chungimport android.graphics.Canvas;
310dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynnimport android.graphics.Color;
324be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onoratoimport android.graphics.Paint;
33de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroyimport android.graphics.Point;
34de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroyimport android.graphics.PointF;
35b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohenimport android.graphics.PorterDuff;
36b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohenimport android.graphics.PorterDuffXfermode;
3731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.graphics.Rect;
38482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohenimport android.graphics.drawable.ColorDrawable;
396569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroyimport android.graphics.drawable.Drawable;
40b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohenimport android.graphics.drawable.NinePatchDrawable;
4131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.util.AttributeSet;
424be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onoratoimport android.util.Log;
4331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.MotionEvent;
4431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.View;
4531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.ViewDebug;
4631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.ViewGroup;
47aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chungimport android.view.animation.Animation;
48150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chungimport android.view.animation.DecelerateInterpolator;
49aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chungimport android.view.animation.LayoutAnimationController;
5031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
516639687cd67bab1aeef2a75e5c6bc458b20dc082Adam Cohenimport com.android.launcher.R;
5269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohenimport com.android.launcher2.FolderIcon.FolderRingAnimator;
538e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy
5469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohenimport java.util.ArrayList;
55c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohenimport java.util.Arrays;
56bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohenimport java.util.HashMap;
57d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohenimport java.util.Stack;
58c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen
59bdb5c5342adc550559fd723af461e53248f2fba8Michael Jurkapublic class CellLayout extends ViewGroup {
60aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung    static final String TAG = "CellLayout";
61aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
622acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen    private Launcher mLauncher;
6331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private int mCellWidth;
6431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private int mCellHeight;
65aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
66d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen    private int mCountX;
67d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen    private int mCountY;
6831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
69234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen    private int mOriginalWidthGap;
70234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen    private int mOriginalHeightGap;
7131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private int mWidthGap;
7231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private int mHeightGap;
734b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung    private int mMaxGap;
74ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen    private boolean mScrollingTransformsDirty = false;
7531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
7631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private final Rect mRect = new Rect();
7731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private final CellInfo mCellInfo = new CellInfo();
78aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
79de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy    // These are temporary variables to prevent having to allocate a new object just to
80de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy    // return an (x, y) value from helper functions. Do NOT use them to maintain other state.
810be025d64c1f84138fe430a58875886e66aae767Winson Chung    private final int[] mTmpXY = new int[2];
82de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy    private final int[] mTmpPoint = new int[2];
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
125482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private HashMap<CellLayout.LayoutParams, Animator> mReorderAnimators = new
126482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            HashMap<CellLayout.LayoutParams, Animator>();
12719f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private HashMap<View, ReorderHintAnimation>
12819f3792523fe2d55ea791a9286398a6120920690Adam Cohen            mShakeAnimators = new HashMap<View, ReorderHintAnimation>();
12919f3792523fe2d55ea791a9286398a6120920690Adam Cohen
13019f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private boolean mItemPlacementDirty = false;
131bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen
1326569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    // When a drag operation is in progress, holds the nearest cell to the touch point
1336569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    private final int[] mDragCell = new int[2];
13431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
1354be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato    private boolean mDragging = false;
1364be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato
137ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy    private TimeInterpolator mEaseOutInterpolator;
138a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka    private ShortcutAndWidgetContainer mShortcutsAndWidgets;
139ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy
1400dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn    private boolean mIsHotseat = false;
141eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung    private float mChildScale = 1f;
142eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung    private float mHotseatChildScale = 1f;
1430dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn
144482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public static final int MODE_DRAG_OVER = 0;
145482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public static final int MODE_ON_DROP = 1;
146482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public static final int MODE_ON_DROP_EXTERNAL = 2;
147482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public static final int MODE_ACCEPT_DROP = 3;
14819f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private static final boolean DESTRUCTIVE_REORDER = false;
149482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private static final boolean DEBUG_VISUALIZE_OCCUPIED = false;
150482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
151a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen    static final int LANDSCAPE = 0;
152a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen    static final int PORTRAIT = 1;
153a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen
15450e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely    private static final float REORDER_HINT_MAGNITUDE = 0.10f;
15519f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private static final int REORDER_ANIMATION_DURATION = 150;
15619f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private float mReorderHintAnimationMagnitude;
15719f3792523fe2d55ea791a9286398a6120920690Adam Cohen
158482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private ArrayList<View> mIntersectingViews = new ArrayList<View>();
159482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private Rect mOccupiedRect = new Rect();
160482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private int[] mDirectionVector = new int[2];
16119f3792523fe2d55ea791a9286398a6120920690Adam Cohen    int[] mPreviousReorderDirection = new int[2];
162b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen    private static final int INVALID_DIRECTION = -100;
163c6cc61d45836e4081920883cc4d448ccb0bb8417Adam Cohen    private DropTarget.DragEnforcer mDragEnforcer;
164482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1658a0bff5e35f63321178bbf777ec24d42544866b3Romain Guy    private final static PorterDuffXfermode sAddBlendMode =
1668a0bff5e35f63321178bbf777ec24d42544866b3Romain Guy            new PorterDuffXfermode(PorterDuff.Mode.ADD);
1678a0bff5e35f63321178bbf777ec24d42544866b3Romain Guy
16831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public CellLayout(Context context) {
16931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        this(context, null);
17031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
17131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
17231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public CellLayout(Context context, AttributeSet attrs) {
17331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        this(context, attrs, 0);
17431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
17531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
17631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public CellLayout(Context context, AttributeSet attrs, int defStyle) {
17731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        super(context, attrs, defStyle);
1788b805b17158886035b38261eb611d8641701ae43Michael Jurka        mDragEnforcer = new DropTarget.DragEnforcer(context);
1796569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
1806569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        // A ViewGroup usually does not draw, but CellLayout needs to draw a rectangle to show
1816569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        // the user where a dragged item will land when dropped.
1826569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        setWillNotDraw(false);
1832acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen        mLauncher = (Launcher) context;
184a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka
18531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CellLayout, defStyle, 0);
18631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
187f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        mCellWidth = a.getDimensionPixelSize(R.styleable.CellLayout_cellWidth, 10);
188f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        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
230ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy        mEaseOutInterpolator = new DecelerateInterpolator(2.5f); // Quint ease out
231de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy
232046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy
233b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung        mDragCell[0] = mDragCell[1] = -1;
2344be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        for (int i = 0; i < mDragOutlines.length; i++) {
235d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            mDragOutlines[i] = new Rect(-1, -1, -1, -1);
236046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        }
237046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy
238046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        // When dragging things around the home screens, we show a green outline of
239046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        // where the item will land. The outlines gradually fade out, leaving a trail
240046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        // behind the drag path.
241046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        // Set up all the animations that are used to implement this fading.
242046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        final int duration = res.getInteger(R.integer.config_dragOutlineFadeTime);
243472b281d5cb4f5660df981a6c912266b9f5703feChet Haase        final float fromAlphaValue = 0;
244472b281d5cb4f5660df981a6c912266b9f5703feChet Haase        final float toAlphaValue = (float)res.getInteger(R.integer.config_dragOutlineMaxAlpha);
2454be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato
2468e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy        Arrays.fill(mDragOutlineAlphas, fromAlphaValue);
2474be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato
2484be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        for (int i = 0; i < mDragOutlineAnims.length; i++) {
249046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy            final InterruptibleInOutAnimator anim =
250046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy                new InterruptibleInOutAnimator(duration, fromAlphaValue, toAlphaValue);
251ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy            anim.getAnimator().setInterpolator(mEaseOutInterpolator);
252046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy            final int thisIndex = i;
253472b281d5cb4f5660df981a6c912266b9f5703feChet Haase            anim.getAnimator().addUpdateListener(new AnimatorUpdateListener() {
254de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                public void onAnimationUpdate(ValueAnimator animation) {
2554be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    final Bitmap outline = (Bitmap)anim.getTag();
2564be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato
2574be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    // If an animation is started and then stopped very quickly, we can still
2584be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    // get spurious updates we've cleared the tag. Guard against this.
2594be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    if (outline == null) {
2603a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka                        @SuppressWarnings("all") // suppress dead code warning
2613a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka                        final boolean debug = false;
2623a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka                        if (debug) {
263fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy                            Object val = animation.getAnimatedValue();
264fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy                            Log.d(TAG, "anim " + thisIndex + " update: " + val +
265fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy                                     ", isStopped " + anim.isStopped());
266fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy                        }
2674be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                        // Try to prevent it from continuing to run
2684be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                        animation.cancel();
2694be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    } else {
270472b281d5cb4f5660df981a6c912266b9f5703feChet Haase                        mDragOutlineAlphas[thisIndex] = (Float) animation.getAnimatedValue();
271d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        CellLayout.this.invalidate(mDragOutlines[thisIndex]);
2724be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    }
273de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                }
274de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy            });
2754be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            // The animation holds a reference to the drag outline bitmap as long is it's
2764be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            // running. This way the bitmap can be GCed when the animations are complete.
277472b281d5cb4f5660df981a6c912266b9f5703feChet Haase            anim.getAnimator().addListener(new AnimatorListenerAdapter() {
2783c4c20fbe682cb4b3ef94f09afe0af09171583f3Michael Jurka                @Override
2794be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                public void onAnimationEnd(Animator animation) {
280472b281d5cb4f5660df981a6c912266b9f5703feChet Haase                    if ((Float) ((ValueAnimator) animation).getAnimatedValue() == 0f) {
2814be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                        anim.setTag(null);
2824be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    }
2834be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                }
2844be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            });
2854be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            mDragOutlineAnims[i] = anim;
286de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy        }
287ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy
28818014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka        mBackgroundRect = new Rect();
289b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        mForegroundRect = new Rect();
290bea15195346bab3c52b0156e92f2b71f0811b210Michael Jurka
291a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets = new ShortcutAndWidgetContainer(context);
292a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.setCellDimensions(mCellWidth, mCellHeight, mWidthGap, mHeightGap);
293a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        addView(mShortcutsAndWidgets);
29418014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka    }
29518014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka
296f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka    static int widthInPortrait(Resources r, int numCells) {
297f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka        // We use this method from Workspace to figure out how many rows/columns Launcher should
298f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka        // have. We ignore the left/right padding on CellLayout because it turns out in our design
299f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka        // the padding extends outside the visible screen size, but it looked fine anyway.
300f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka        int cellWidth = r.getDimensionPixelSize(R.dimen.workspace_cell_width);
3014b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        int minGap = Math.min(r.getDimensionPixelSize(R.dimen.workspace_width_gap),
3024b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                r.getDimensionPixelSize(R.dimen.workspace_height_gap));
303f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka
3044b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        return  minGap * (numCells - 1) + cellWidth * numCells;
305f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka    }
306f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka
307f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka    static int heightInLandscape(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 cellHeight = r.getDimensionPixelSize(R.dimen.workspace_cell_height);
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) + cellHeight * numCells;
316f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka    }
317f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka
3182801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    public void enableHardwareLayers() {
319a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.enableHardwareLayers();
3202801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    }
3212801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
3222801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    public void setGridSize(int x, int y) {
3232801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        mCountX = x;
3242801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        mCountY = y;
3252801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        mOccupied = new boolean[mCountX][mCountY];
326482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        mTmpOccupied = new boolean[mCountX][mCountY];
3277fbec10b36818f100b631f3d73fe1ad5360975aaAdam Cohen        mTempRectStack.clear();
32876fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        requestLayout();
3292801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    }
3302801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
33196864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy    private void invalidateBubbleTextView(BubbleTextView icon) {
33296864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        final int padding = icon.getPressedOrFocusedBackgroundPadding();
3334b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        invalidate(icon.getLeft() + getPaddingLeft() - padding,
3344b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                icon.getTop() + getPaddingTop() - padding,
3354b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                icon.getRight() + getPaddingLeft() + padding,
3364b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                icon.getBottom() + getPaddingTop() + padding);
33796864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy    }
33896864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy
339b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    void setOverScrollAmount(float r, boolean left) {
340b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        if (left && mOverScrollForegroundDrawable != mOverScrollLeft) {
341b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen            mOverScrollForegroundDrawable = mOverScrollLeft;
342b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        } else if (!left && mOverScrollForegroundDrawable != mOverScrollRight) {
343b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen            mOverScrollForegroundDrawable = mOverScrollRight;
344b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        }
345b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen
346b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        mForegroundAlpha = (int) Math.round((r * 255));
347b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        mOverScrollForegroundDrawable.setAlpha(mForegroundAlpha);
348b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        invalidate();
349b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    }
350b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen
35196864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy    void setPressedOrFocusedIcon(BubbleTextView icon) {
35296864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        // We draw the pressed or focused BubbleTextView's background in CellLayout because it
35396864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        // requires an expanded clip rect (due to the glow's blur radius)
35496864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        BubbleTextView oldIcon = mPressedOrFocusedIcon;
35596864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        mPressedOrFocusedIcon = icon;
35696864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        if (oldIcon != null) {
35796864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy            invalidateBubbleTextView(oldIcon);
35896864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        }
35996864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        if (mPressedOrFocusedIcon != null) {
36096864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy            invalidateBubbleTextView(mPressedOrFocusedIcon);
36196864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        }
36296864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy    }
36396864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy
36433945b21544bc98381df17726a3537c292d8c985Michael Jurka    void setIsDragOverlapping(boolean isDragOverlapping) {
36533945b21544bc98381df17726a3537c292d8c985Michael Jurka        if (mIsDragOverlapping != isDragOverlapping) {
36633945b21544bc98381df17726a3537c292d8c985Michael Jurka            mIsDragOverlapping = isDragOverlapping;
36733945b21544bc98381df17726a3537c292d8c985Michael Jurka            invalidate();
36833945b21544bc98381df17726a3537c292d8c985Michael Jurka        }
36933945b21544bc98381df17726a3537c292d8c985Michael Jurka    }
37033945b21544bc98381df17726a3537c292d8c985Michael Jurka
37133945b21544bc98381df17726a3537c292d8c985Michael Jurka    boolean getIsDragOverlapping() {
37233945b21544bc98381df17726a3537c292d8c985Michael Jurka        return mIsDragOverlapping;
37333945b21544bc98381df17726a3537c292d8c985Michael Jurka    }
37433945b21544bc98381df17726a3537c292d8c985Michael Jurka
375ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen    protected void setOverscrollTransformsDirty(boolean dirty) {
376ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen        mScrollingTransformsDirty = dirty;
377ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen    }
378ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen
379ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen    protected void resetOverscrollTransforms() {
380ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen        if (mScrollingTransformsDirty) {
381ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            setOverscrollTransformsDirty(false);
382ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            setTranslationX(0);
383ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            setRotationY(0);
384ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            // It doesn't matter if we pass true or false here, the important thing is that we
385ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            // pass 0, which results in the overscroll drawable not being drawn any more.
386ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            setOverScrollAmount(0, false);
387ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            setPivotX(getMeasuredWidth() / 2);
388ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            setPivotY(getMeasuredHeight() / 2);
389ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen        }
390ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen    }
391ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen
392a6abce8464b57ce91e8f083951ad263370fc2da8Romain Guy    @Override
3931262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy    protected void onDraw(Canvas canvas) {
3943e7c7634531302271270c8cf418abc959d621cbcMichael Jurka        // When we're large, we are either drawn in a "hover" state (ie when dragging an item to
3953e7c7634531302271270c8cf418abc959d621cbcMichael Jurka        // a neighboring page) or with just a normal background (if backgroundAlpha > 0.0f)
3963e7c7634531302271270c8cf418abc959d621cbcMichael Jurka        // When we're small, we are either drawn normally or in the "accepts drops" state (during
3973e7c7634531302271270c8cf418abc959d621cbcMichael Jurka        // a drag). However, we also drag the mini hover background *over* one of those two
3983e7c7634531302271270c8cf418abc959d621cbcMichael Jurka        // backgrounds
399b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung        if (mBackgroundAlpha > 0.0f) {
400f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen            Drawable bg;
40133945b21544bc98381df17726a3537c292d8c985Michael Jurka
40233945b21544bc98381df17726a3537c292d8c985Michael Jurka            if (mIsDragOverlapping) {
40333945b21544bc98381df17726a3537c292d8c985Michael Jurka                // In the mini case, we draw the active_glow bg *over* the active background
404bdf78559f223ac11e01e3311edd5a48a80383e1eMichael Jurka                bg = mActiveGlowBackground;
405f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen            } else {
406bdf78559f223ac11e01e3311edd5a48a80383e1eMichael Jurka                bg = mNormalBackground;
407f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen            }
40833945b21544bc98381df17726a3537c292d8c985Michael Jurka
40933945b21544bc98381df17726a3537c292d8c985Michael Jurka            bg.setAlpha((int) (mBackgroundAlpha * mBackgroundAlphaMultiplier * 255));
41033945b21544bc98381df17726a3537c292d8c985Michael Jurka            bg.setBounds(mBackgroundRect);
41133945b21544bc98381df17726a3537c292d8c985Michael Jurka            bg.draw(canvas);
412a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka        }
41331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
4148e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy        final Paint paint = mDragOutlinePaint;
4154be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        for (int i = 0; i < mDragOutlines.length; i++) {
416472b281d5cb4f5660df981a6c912266b9f5703feChet Haase            final float alpha = mDragOutlineAlphas[i];
4174be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            if (alpha > 0) {
418d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                final Rect r = mDragOutlines[i];
4194be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                final Bitmap b = (Bitmap) mDragOutlineAnims[i].getTag();
420472b281d5cb4f5660df981a6c912266b9f5703feChet Haase                paint.setAlpha((int)(alpha + .5f));
421d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                canvas.drawBitmap(b, null, r, paint);
422150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung            }
4236569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        }
42496864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy
42596864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        // We draw the pressed or focused BubbleTextView's background in CellLayout because it
42696864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        // requires an expanded clip rect (due to the glow's blur radius)
42796864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        if (mPressedOrFocusedIcon != null) {
42896864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy            final int padding = mPressedOrFocusedIcon.getPressedOrFocusedBackgroundPadding();
42996864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy            final Bitmap b = mPressedOrFocusedIcon.getPressedOrFocusedBackground();
43096864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy            if (b != null) {
43196864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy                canvas.drawBitmap(b,
4324b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                        mPressedOrFocusedIcon.getLeft() + getPaddingLeft() - padding,
4334b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                        mPressedOrFocusedIcon.getTop() + getPaddingTop() - padding,
43496864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy                        null);
43596864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy            }
43696864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        }
43769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
438482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (DEBUG_VISUALIZE_OCCUPIED) {
439482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            int[] pt = new int[2];
440482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            ColorDrawable cd = new ColorDrawable(Color.RED);
441482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            cd.setBounds(0, 0, 80, 80);
442482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            for (int i = 0; i < mCountX; i++) {
443482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                for (int j = 0; j < mCountY; j++) {
444482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    if (mOccupied[i][j]) {
445482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        cellToPoint(i, j, pt);
446482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        canvas.save();
447482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        canvas.translate(pt[0], pt[1]);
448482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        cd.draw(canvas);
449482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        canvas.restore();
450482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    }
451482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                }
452482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
453482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
454482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
455850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn        int previewOffset = FolderRingAnimator.sPreviewSize;
456850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn
45769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        // The folder outer / inner ring image(s)
45869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        for (int i = 0; i < mFolderOuterRings.size(); i++) {
45969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            FolderRingAnimator fra = mFolderOuterRings.get(i);
46069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
46169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            // Draw outer ring
46269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            Drawable d = FolderRingAnimator.sSharedOuterRingDrawable;
46369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            int width = (int) fra.getOuterRingSize();
46469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            int height = width;
46569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            cellToPoint(fra.mCellX, fra.mCellY, mTempLocation);
46669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
46769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            int centerX = mTempLocation[0] + mCellWidth / 2;
468850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn            int centerY = mTempLocation[1] + previewOffset / 2;
46969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
47069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            canvas.save();
47169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            canvas.translate(centerX - width / 2, centerY - height / 2);
47269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            d.setBounds(0, 0, width, height);
47369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            d.draw(canvas);
47469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            canvas.restore();
47569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
47669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            // Draw inner ring
47769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            d = FolderRingAnimator.sSharedInnerRingDrawable;
47869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            width = (int) fra.getInnerRingSize();
47969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            height = width;
48069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            cellToPoint(fra.mCellX, fra.mCellY, mTempLocation);
48169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
48269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            centerX = mTempLocation[0] + mCellWidth / 2;
483850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn            centerY = mTempLocation[1] + previewOffset / 2;
48469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            canvas.save();
48569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            canvas.translate(centerX - width / 2, centerY - width / 2);
48669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            d.setBounds(0, 0, width, height);
48769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            d.draw(canvas);
48869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            canvas.restore();
48969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        }
490c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen
491c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        if (mFolderLeaveBehindCell[0] >= 0 && mFolderLeaveBehindCell[1] >= 0) {
492c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            Drawable d = FolderIcon.sSharedFolderLeaveBehind;
493c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            int width = d.getIntrinsicWidth();
494c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            int height = d.getIntrinsicHeight();
495c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen
496c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            cellToPoint(mFolderLeaveBehindCell[0], mFolderLeaveBehindCell[1], mTempLocation);
497c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            int centerX = mTempLocation[0] + mCellWidth / 2;
498850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn            int centerY = mTempLocation[1] + previewOffset / 2;
499c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen
500c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            canvas.save();
501c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            canvas.translate(centerX - width / 2, centerY - width / 2);
502c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            d.setBounds(0, 0, width, height);
503c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            d.draw(canvas);
504c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            canvas.restore();
505c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        }
50669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen    }
50769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
508b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    @Override
509b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    protected void dispatchDraw(Canvas canvas) {
510b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        super.dispatchDraw(canvas);
511b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        if (mForegroundAlpha > 0) {
512b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen            mOverScrollForegroundDrawable.setBounds(mForegroundRect);
513b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen            Paint p = ((NinePatchDrawable) mOverScrollForegroundDrawable).getPaint();
5148a0bff5e35f63321178bbf777ec24d42544866b3Romain Guy            p.setXfermode(sAddBlendMode);
515b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen            mOverScrollForegroundDrawable.draw(canvas);
516b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen            p.setXfermode(null);
517b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        }
518b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    }
519b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen
52069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen    public void showFolderAccept(FolderRingAnimator fra) {
52169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        mFolderOuterRings.add(fra);
52269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen    }
52369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
52469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen    public void hideFolderAccept(FolderRingAnimator fra) {
52569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        if (mFolderOuterRings.contains(fra)) {
52669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            mFolderOuterRings.remove(fra);
52769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        }
52869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        invalidate();
5296569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    }
5306569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
531c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen    public void setFolderLeaveBehindCell(int x, int y) {
532c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        mFolderLeaveBehindCell[0] = x;
533c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        mFolderLeaveBehindCell[1] = y;
534c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        invalidate();
535c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen    }
536c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen
537c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen    public void clearFolderLeaveBehind() {
538c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        mFolderLeaveBehindCell[0] = -1;
539c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        mFolderLeaveBehindCell[1] = -1;
540c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        invalidate();
541c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen    }
542c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen
5436569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    @Override
544e6235dd225404239b55c459245543f3302326112Michael Jurka    public boolean shouldDelayChildPressedState() {
545e6235dd225404239b55c459245543f3302326112Michael Jurka        return false;
546e6235dd225404239b55c459245543f3302326112Michael Jurka    }
547e6235dd225404239b55c459245543f3302326112Michael Jurka
548e6235dd225404239b55c459245543f3302326112Michael Jurka    @Override
54983f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey    public void cancelLongPress() {
55083f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey        super.cancelLongPress();
55183f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey
55283f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey        // Cancel long press for all children
55383f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey        final int count = getChildCount();
55483f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey        for (int i = 0; i < count; i++) {
55583f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey            final View child = getChildAt(i);
55683f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey            child.cancelLongPress();
55783f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey        }
55883f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey    }
55983f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey
560dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    public void setOnInterceptTouchListener(View.OnTouchListener listener) {
561dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka        mInterceptTouchListener = listener;
562dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    }
563dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka
56431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    int getCountX() {
565d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        return mCountX;
56631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
56731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
56831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    int getCountY() {
569d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        return mCountY;
57031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
57131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
5720dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn    public void setIsHotseat(boolean isHotseat) {
5730dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn        mIsHotseat = isHotseat;
5740dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn    }
5750dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn
576eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung    public float getChildrenScale() {
577eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung        return mIsHotseat ? mHotseatChildScale : mChildScale;
578eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung    }
579eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung
5800dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn
581850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn    private void scaleChild(BubbleTextView bubbleChild, float scale) {
582bc239a15464f543a41b960b946aa77258454efafAndrew Flynn        // If we haven't measured the child yet, do it now
583bc239a15464f543a41b960b946aa77258454efafAndrew Flynn        // (this happens if we're being dropped from all-apps
584bc239a15464f543a41b960b946aa77258454efafAndrew Flynn        if (bubbleChild.getLayoutParams() instanceof LayoutParams &&
585bc239a15464f543a41b960b946aa77258454efafAndrew Flynn                (bubbleChild.getMeasuredWidth() | bubbleChild.getMeasuredHeight()) == 0) {
586a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            getShortcutsAndWidgets().measureChild(bubbleChild);
587bc239a15464f543a41b960b946aa77258454efafAndrew Flynn        }
588bc239a15464f543a41b960b946aa77258454efafAndrew Flynn
589bc239a15464f543a41b960b946aa77258454efafAndrew Flynn        bubbleChild.setScaleX(scale);
590bc239a15464f543a41b960b946aa77258454efafAndrew Flynn        bubbleChild.setScaleY(scale);
591bc239a15464f543a41b960b946aa77258454efafAndrew Flynn    }
592bc239a15464f543a41b960b946aa77258454efafAndrew Flynn
593bc239a15464f543a41b960b946aa77258454efafAndrew Flynn    private void resetChild(BubbleTextView bubbleChild) {
594bc239a15464f543a41b960b946aa77258454efafAndrew Flynn        bubbleChild.setScaleX(1f);
595bc239a15464f543a41b960b946aa77258454efafAndrew Flynn        bubbleChild.setScaleY(1f);
596bc239a15464f543a41b960b946aa77258454efafAndrew Flynn
597bc239a15464f543a41b960b946aa77258454efafAndrew Flynn        bubbleChild.setTextColor(getResources().getColor(R.color.workspace_icon_text_color));
598bc239a15464f543a41b960b946aa77258454efafAndrew Flynn    }
599bc239a15464f543a41b960b946aa77258454efafAndrew Flynn
6000dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn    public boolean addViewToCellLayout(View child, int index, int childId, LayoutParams params,
601850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn            boolean markCells) {
602aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        final LayoutParams lp = params;
603aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
6040dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn        // Hotseat icons - scale down and remove text
6050dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn        // Don't scale the all apps button
6060dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn        // scale percent set to -1 means do not scale
6070dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn        // Only scale BubbleTextViews
6080dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn        if (child instanceof BubbleTextView) {
6090dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn            BubbleTextView bubbleChild = (BubbleTextView) child;
6100dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn
611bc239a15464f543a41b960b946aa77258454efafAndrew Flynn            // Start the child with 100% scale and visible text
612bc239a15464f543a41b960b946aa77258454efafAndrew Flynn            resetChild(bubbleChild);
613bc239a15464f543a41b960b946aa77258454efafAndrew Flynn
614850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn            if (mIsHotseat && mHotseatChildScale >= 0) {
615bc239a15464f543a41b960b946aa77258454efafAndrew Flynn                // Scale/make transparent for a hotseat
616850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn                scaleChild(bubbleChild, mHotseatChildScale);
6170dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn
618bc239a15464f543a41b960b946aa77258454efafAndrew Flynn                bubbleChild.setTextColor(getResources().getColor(android.R.color.transparent));
619eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung            } else if (mChildScale >= 0) {
620bc239a15464f543a41b960b946aa77258454efafAndrew Flynn                // Else possibly still scale it if we need to for smaller icons
621850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn                scaleChild(bubbleChild, mChildScale);
6220dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn            }
6230dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn        }
6240dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn
62531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // Generate an id for each view, this assumes we have at most 256x256 cells
62631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // per workspace screen
627d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        if (lp.cellX >= 0 && lp.cellX <= mCountX - 1 && lp.cellY >= 0 && lp.cellY <= mCountY - 1) {
628aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            // If the horizontal or vertical span is set to -1, it is taken to
629aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            // mean that it spans the extent of the CellLayout
630d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen            if (lp.cellHSpan < 0) lp.cellHSpan = mCountX;
631d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen            if (lp.cellVSpan < 0) lp.cellVSpan = mCountY;
632aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
633aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            child.setId(childId);
63431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
635a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            mShortcutsAndWidgets.addView(child, index, lp);
636dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka
637f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka            if (markCells) markCellsAsOccupiedForView(child);
6380280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
639aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            return true;
640aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        }
641aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        return false;
64231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
6433e7c7634531302271270c8cf418abc959d621cbcMichael Jurka
64431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
6450280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public void removeAllViews() {
6460280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        clearOccupiedCells();
647a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.removeAllViews();
6480280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
6490280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
6500280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    @Override
6510280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public void removeAllViewsInLayout() {
652a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        if (mShortcutsAndWidgets.getChildCount() > 0) {
6537cfc2825c3a1029f962d2fc387ae2eaa85b51798Michael Jurka            clearOccupiedCells();
654a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            mShortcutsAndWidgets.removeAllViewsInLayout();
6557cfc2825c3a1029f962d2fc387ae2eaa85b51798Michael Jurka        }
6560280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
6570280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
658f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka    public void removeViewWithoutMarkingCells(View view) {
659a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.removeView(view);
660f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka    }
661f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka
6620280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    @Override
6630280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public void removeView(View view) {
6640280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        markCellsAsUnoccupiedForView(view);
665a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.removeView(view);
6660280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
6670280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
6680280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    @Override
6690280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public void removeViewAt(int index) {
670a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        markCellsAsUnoccupiedForView(mShortcutsAndWidgets.getChildAt(index));
671a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.removeViewAt(index);
6720280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
6730280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
6740280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    @Override
6750280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public void removeViewInLayout(View view) {
6760280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        markCellsAsUnoccupiedForView(view);
677a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.removeViewInLayout(view);
6780280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
6790280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
6800280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    @Override
6810280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public void removeViews(int start, int count) {
6820280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        for (int i = start; i < start + count; i++) {
683a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            markCellsAsUnoccupiedForView(mShortcutsAndWidgets.getChildAt(i));
6840280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        }
685a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.removeViews(start, count);
6860280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
6870280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
6880280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    @Override
6890280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public void removeViewsInLayout(int start, int count) {
6900280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        for (int i = start; i < start + count; i++) {
691a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            markCellsAsUnoccupiedForView(mShortcutsAndWidgets.getChildAt(i));
6920280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        }
693a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.removeViewsInLayout(start, count);
694abded66084680bb31cc7ea403c88f44f79a3c884Michael Jurka    }
695abded66084680bb31cc7ea403c88f44f79a3c884Michael Jurka
69631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
69731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    protected void onAttachedToWindow() {
69831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        super.onAttachedToWindow();
69931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        mCellInfo.screen = ((ViewGroup) getParent()).indexOfChild(this);
70031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
70131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
702af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka    public void setTagToCellInfoForPoint(int touchX, int touchY) {
70331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        final CellInfo cellInfo = mCellInfo;
704eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung        Rect frame = mRect;
7058b805b17158886035b38261eb611d8641701ae43Michael Jurka        final int x = touchX + getScrollX();
7068b805b17158886035b38261eb611d8641701ae43Michael Jurka        final int y = touchY + getScrollY();
707a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        final int count = mShortcutsAndWidgets.getChildCount();
70831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
709af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka        boolean found = false;
710af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka        for (int i = count - 1; i >= 0; i--) {
711a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            final View child = mShortcutsAndWidgets.getChildAt(i);
712d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
713af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka
7141b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen            if ((child.getVisibility() == VISIBLE || child.getAnimation() != null) &&
7151b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen                    lp.isLockedToGrid) {
716af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                child.getHitRect(frame);
7170be025d64c1f84138fe430a58875886e66aae767Winson Chung
718eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                float scale = child.getScaleX();
719eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                frame = new Rect(child.getLeft(), child.getTop(), child.getRight(),
720eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                        child.getBottom());
7210be025d64c1f84138fe430a58875886e66aae767Winson Chung                // The child hit rect is relative to the CellLayoutChildren parent, so we need to
7220be025d64c1f84138fe430a58875886e66aae767Winson Chung                // offset that by this CellLayout's padding to test an (x,y) point that is relative
7230be025d64c1f84138fe430a58875886e66aae767Winson Chung                // to this view.
7248b805b17158886035b38261eb611d8641701ae43Michael Jurka                frame.offset(getPaddingLeft(), getPaddingTop());
725eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                frame.inset((int) (frame.width() * (1f - scale) / 2),
726eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                        (int) (frame.height() * (1f - scale) / 2));
7270be025d64c1f84138fe430a58875886e66aae767Winson Chung
728af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                if (frame.contains(x, y)) {
729af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                    cellInfo.cell = child;
730af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                    cellInfo.cellX = lp.cellX;
731af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                    cellInfo.cellY = lp.cellY;
732af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                    cellInfo.spanX = lp.cellHSpan;
733af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                    cellInfo.spanY = lp.cellVSpan;
734af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                    found = true;
735af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                    break;
73631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                }
73731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            }
738af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka        }
739aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
740d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka        mLastDownOnOccupiedCell = found;
741d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka
742af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka        if (!found) {
7430be025d64c1f84138fe430a58875886e66aae767Winson Chung            final int cellXY[] = mTmpXY;
744af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka            pointToCellExact(x, y, cellXY);
74531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
746af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka            cellInfo.cell = null;
747af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka            cellInfo.cellX = cellXY[0];
748af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka            cellInfo.cellY = cellXY[1];
749af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka            cellInfo.spanX = 1;
750af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka            cellInfo.spanY = 1;
751af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka        }
752af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka        setTag(cellInfo);
753af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka    }
75431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
755af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka    @Override
756af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka    public boolean onInterceptTouchEvent(MotionEvent ev) {
757c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        // First we clear the tag to ensure that on every touch down we start with a fresh slate,
758c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        // even in the case where we return early. Not clearing here was causing bugs whereby on
759c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        // long-press we'd end up picking up an item from a previous drag operation.
760c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        final int action = ev.getAction();
761c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen
762c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        if (action == MotionEvent.ACTION_DOWN) {
763c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen            clearTagCellInfo();
764c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        }
765c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen
766dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka        if (mInterceptTouchListener != null && mInterceptTouchListener.onTouch(this, ev)) {
767dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka            return true;
768dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka        }
76931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
770af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka        if (action == MotionEvent.ACTION_DOWN) {
771af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka            setTagToCellInfoForPoint((int) ev.getX(), (int) ev.getY());
77231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
773eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung
77431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        return false;
77531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
77631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
777c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen    private void clearTagCellInfo() {
778c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        final CellInfo cellInfo = mCellInfo;
779c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        cellInfo.cell = null;
780c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        cellInfo.cellX = -1;
781c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        cellInfo.cellY = -1;
782c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        cellInfo.spanX = 0;
783c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        cellInfo.spanY = 0;
784c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        setTag(cellInfo);
785c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen    }
786c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen
78731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public CellInfo getTag() {
7880280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        return (CellInfo) super.getTag();
78931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
79031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
7916569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    /**
792aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     * Given a point, return the cell that strictly encloses that point
79331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param x X coordinate of the point
79431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param y Y coordinate of the point
79531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param result Array of 2 ints to hold the x and y coordinate of the cell
79631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
79731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    void pointToCellExact(int x, int y, int[] result) {
7984b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int hStartPadding = getPaddingLeft();
7994b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int vStartPadding = getPaddingTop();
80031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
80131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        result[0] = (x - hStartPadding) / (mCellWidth + mWidthGap);
80231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        result[1] = (y - vStartPadding) / (mCellHeight + mHeightGap);
80331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
804d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        final int xAxis = mCountX;
805d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        final int yAxis = mCountY;
80631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
80731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        if (result[0] < 0) result[0] = 0;
80831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        if (result[0] >= xAxis) result[0] = xAxis - 1;
80931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        if (result[1] < 0) result[1] = 0;
81031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        if (result[1] >= yAxis) result[1] = yAxis - 1;
81131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
812aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
81331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
81431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * Given a point, return the cell that most closely encloses that point
81531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param x X coordinate of the point
81631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param y Y coordinate of the point
81731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param result Array of 2 ints to hold the x and y coordinate of the cell
81831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
81931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    void pointToCellRounded(int x, int y, int[] result) {
82031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        pointToCellExact(x + (mCellWidth / 2), y + (mCellHeight / 2), result);
82131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
82231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
82331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
82431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * Given a cell coordinate, return the point that represents the upper left corner of that cell
825aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     *
826aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     * @param cellX X coordinate of the cell
82731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param cellY Y coordinate of the cell
828aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     *
82931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param result Array of 2 ints to hold the x and y coordinate of the point
83031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
83131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    void cellToPoint(int cellX, int cellY, int[] result) {
8324b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int hStartPadding = getPaddingLeft();
8334b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int vStartPadding = getPaddingTop();
83431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
83531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        result[0] = hStartPadding + cellX * (mCellWidth + mWidthGap);
83631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        result[1] = vStartPadding + cellY * (mCellHeight + mHeightGap);
83731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
83831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
839e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen    /**
840482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * Given a cell coordinate, return the point that represents the center of the cell
841e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen     *
842e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen     * @param cellX X coordinate of the cell
843e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen     * @param cellY Y coordinate of the cell
844e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen     *
845e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen     * @param result Array of 2 ints to hold the x and y coordinate of the point
846e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen     */
847e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen    void cellToCenterPoint(int cellX, int cellY, int[] result) {
84847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        regionToCenterPoint(cellX, cellY, 1, 1, result);
84947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    }
85047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
85147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    /**
85247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * Given a cell coordinate and span return the point that represents the center of the regio
85347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     *
85447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param cellX X coordinate of the cell
85547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param cellY Y coordinate of the cell
85647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     *
85747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param result Array of 2 ints to hold the x and y coordinate of the point
85847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     */
85947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    void regionToCenterPoint(int cellX, int cellY, int spanX, int spanY, int[] result) {
8604b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int hStartPadding = getPaddingLeft();
8614b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int vStartPadding = getPaddingTop();
86247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        result[0] = hStartPadding + cellX * (mCellWidth + mWidthGap) +
86347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                (spanX * mCellWidth + (spanX - 1) * mWidthGap) / 2;
86447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        result[1] = vStartPadding + cellY * (mCellHeight + mHeightGap) +
86547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                (spanY * mCellHeight + (spanY - 1) * mHeightGap) / 2;
866e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen    }
867e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen
86819f3792523fe2d55ea791a9286398a6120920690Adam Cohen     /**
86919f3792523fe2d55ea791a9286398a6120920690Adam Cohen     * Given a cell coordinate and span fills out a corresponding pixel rect
87019f3792523fe2d55ea791a9286398a6120920690Adam Cohen     *
87119f3792523fe2d55ea791a9286398a6120920690Adam Cohen     * @param cellX X coordinate of the cell
87219f3792523fe2d55ea791a9286398a6120920690Adam Cohen     * @param cellY Y coordinate of the cell
87319f3792523fe2d55ea791a9286398a6120920690Adam Cohen     * @param result Rect in which to write the result
87419f3792523fe2d55ea791a9286398a6120920690Adam Cohen     */
87519f3792523fe2d55ea791a9286398a6120920690Adam Cohen     void regionToRect(int cellX, int cellY, int spanX, int spanY, Rect result) {
87619f3792523fe2d55ea791a9286398a6120920690Adam Cohen        final int hStartPadding = getPaddingLeft();
87719f3792523fe2d55ea791a9286398a6120920690Adam Cohen        final int vStartPadding = getPaddingTop();
87819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        final int left = hStartPadding + cellX * (mCellWidth + mWidthGap);
87919f3792523fe2d55ea791a9286398a6120920690Adam Cohen        final int top = vStartPadding + cellY * (mCellHeight + mHeightGap);
88019f3792523fe2d55ea791a9286398a6120920690Adam Cohen        result.set(left, top, left + (spanX * mCellWidth + (spanX - 1) * mWidthGap),
88119f3792523fe2d55ea791a9286398a6120920690Adam Cohen                top + (spanY * mCellHeight + (spanY - 1) * mHeightGap));
88219f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
88319f3792523fe2d55ea791a9286398a6120920690Adam Cohen
884482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public float getDistanceFromCell(float x, float y, int[] cell) {
885482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        cellToCenterPoint(cell[0], cell[1], mTmpPoint);
886482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        float distance = (float) Math.sqrt( Math.pow(x - mTmpPoint[0], 2) +
887482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                Math.pow(y - mTmpPoint[1], 2));
888482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return distance;
889482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
890482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
89184f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy    int getCellWidth() {
89284f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy        return mCellWidth;
89384f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy    }
89484f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy
89584f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy    int getCellHeight() {
89684f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy        return mCellHeight;
89784f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy    }
89884f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy
899d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    int getWidthGap() {
900d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        return mWidthGap;
901d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    }
902d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
903d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    int getHeightGap() {
904d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        return mHeightGap;
905d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    }
906d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
9077f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen    Rect getContentRect(Rect r) {
9087f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        if (r == null) {
9097f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            r = new Rect();
9107f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
9117f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        int left = getPaddingLeft();
9127f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        int top = getPaddingTop();
9138b805b17158886035b38261eb611d8641701ae43Michael Jurka        int right = left + getWidth() - getPaddingLeft() - getPaddingRight();
9148b805b17158886035b38261eb611d8641701ae43Michael Jurka        int bottom = top + getHeight() - getPaddingTop() - getPaddingBottom();
9157f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        r.set(left, top, right, bottom);
9167f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        return r;
9177f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen    }
9187f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
919a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen    static void getMetrics(Rect metrics, Resources res, int measureWidth, int measureHeight,
920a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen            int countX, int countY, int orientation) {
921a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen        int numWidthGaps = countX - 1;
922a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen        int numHeightGaps = countY - 1;
923f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen
924f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        int widthGap;
925f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        int heightGap;
926f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        int cellWidth;
927f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        int cellHeight;
928f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        int paddingLeft;
929f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        int paddingRight;
930f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        int paddingTop;
931f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        int paddingBottom;
932f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen
933a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen        int maxGap = res.getDimensionPixelSize(R.dimen.workspace_max_gap);
934f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        if (orientation == LANDSCAPE) {
935f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            cellWidth = res.getDimensionPixelSize(R.dimen.workspace_cell_width_land);
936f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            cellHeight = res.getDimensionPixelSize(R.dimen.workspace_cell_height_land);
937f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            widthGap = res.getDimensionPixelSize(R.dimen.workspace_width_gap_land);
938f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            heightGap = res.getDimensionPixelSize(R.dimen.workspace_height_gap_land);
939f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            paddingLeft = res.getDimensionPixelSize(R.dimen.cell_layout_left_padding_land);
940f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            paddingRight = res.getDimensionPixelSize(R.dimen.cell_layout_right_padding_land);
941f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            paddingTop = res.getDimensionPixelSize(R.dimen.cell_layout_top_padding_land);
942f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            paddingBottom = res.getDimensionPixelSize(R.dimen.cell_layout_bottom_padding_land);
943f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        } else {
944f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            // PORTRAIT
945f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            cellWidth = res.getDimensionPixelSize(R.dimen.workspace_cell_width_port);
946f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            cellHeight = res.getDimensionPixelSize(R.dimen.workspace_cell_height_port);
947f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            widthGap = res.getDimensionPixelSize(R.dimen.workspace_width_gap_port);
948f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            heightGap = res.getDimensionPixelSize(R.dimen.workspace_height_gap_port);
949f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            paddingLeft = res.getDimensionPixelSize(R.dimen.cell_layout_left_padding_port);
950f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            paddingRight = res.getDimensionPixelSize(R.dimen.cell_layout_right_padding_port);
951f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            paddingTop = res.getDimensionPixelSize(R.dimen.cell_layout_top_padding_port);
952f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            paddingBottom = res.getDimensionPixelSize(R.dimen.cell_layout_bottom_padding_port);
953f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        }
954f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen
955f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        if (widthGap < 0 || heightGap < 0) {
956f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            int hSpace = measureWidth - paddingLeft - paddingRight;
957f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            int vSpace = measureHeight - paddingTop - paddingBottom;
958a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen            int hFreeSpace = hSpace - (countX * cellWidth);
959a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen            int vFreeSpace = vSpace - (countY * cellHeight);
960a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen            widthGap = Math.min(maxGap, numWidthGaps > 0 ? (hFreeSpace / numWidthGaps) : 0);
961a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen            heightGap = Math.min(maxGap, numHeightGaps > 0 ? (vFreeSpace / numHeightGaps) : 0);
962f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        }
963f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        metrics.set(cellWidth, cellHeight, widthGap, heightGap);
964f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen    }
965f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen
96631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
96731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
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) {
982dd13e3d0f9925b7bb80c37e21d039aab4fa7e7a1Michael Jurka            int hSpace = widthSpecSize - getPaddingLeft() - getPaddingRight();
983dd13e3d0f9925b7bb80c37e21d039aab4fa7e7a1Michael Jurka            int vSpace = heightSpecSize - getPaddingTop() - getPaddingBottom();
984f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            int hFreeSpace = hSpace - (mCountX * mCellWidth);
985f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            int vFreeSpace = vSpace - (mCountY * mCellHeight);
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            return;
12092801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        }
12102801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
1211482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (cellX != oldDragCellX || cellY != oldDragCellY) {
1212482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            mDragCell[0] = cellX;
1213482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            mDragCell[1] = cellY;
12146569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy            // Find the top left corner of the rect the object will occupy
1215de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy            final int[] topLeft = mTmpPoint;
1216482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            cellToPoint(cellX, cellY, topLeft);
1217de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy
12184be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            int left = topLeft[0];
12194be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            int top = topLeft[1];
12206569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
1221b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung            if (v != null && dragOffset == null) {
122299e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                // When drawing the drag outline, it did not account for margin offsets
122399e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                // added by the view's parent.
122499e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                MarginLayoutParams lp = (MarginLayoutParams) v.getLayoutParams();
122599e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                left += lp.leftMargin;
122699e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                top += lp.topMargin;
122799e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen
122899e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                // Offsets due to the size difference between the View and the dragOutline.
122999e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                // There is a size difference to account for the outer blur, which may lie
123099e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                // outside the bounds of the view.
1231a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung                top += (v.getHeight() - dragOutline.getHeight()) / 2;
1232ae915cecd36af4973061a1cb0b58c5be1be699a0Adam Cohen                // We center about the x axis
1233ae915cecd36af4973061a1cb0b58c5be1be699a0Adam Cohen                left += ((mCellWidth * spanX) + ((spanX - 1) * mWidthGap)
1234ae915cecd36af4973061a1cb0b58c5be1be699a0Adam Cohen                        - dragOutline.getWidth()) / 2;
12356639687cd67bab1aeef2a75e5c6bc458b20dc082Adam Cohen            } else {
1236b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                if (dragOffset != null && dragRegion != null) {
1237b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                    // Center the drag region *horizontally* in the cell and apply a drag
1238b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                    // outline offset
1239b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                    left += dragOffset.x + ((mCellWidth * spanX) + ((spanX - 1) * mWidthGap)
1240b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                             - dragRegion.width()) / 2;
1241b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                    top += dragOffset.y;
1242b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                } else {
1243b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                    // Center the drag outline in the cell
1244b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                    left += ((mCellWidth * spanX) + ((spanX - 1) * mWidthGap)
1245b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                            - dragOutline.getWidth()) / 2;
1246b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                    top += ((mCellHeight * spanY) + ((spanY - 1) * mHeightGap)
1247b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                            - dragOutline.getHeight()) / 2;
1248b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                }
1249a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung            }
12504be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            final int oldIndex = mDragOutlineCurrent;
125108ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy            mDragOutlineAnims[oldIndex].animateOut();
125208ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy            mDragOutlineCurrent = (oldIndex + 1) % mDragOutlines.length;
1253d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            Rect r = mDragOutlines[mDragOutlineCurrent];
1254d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            r.set(left, top, left + dragOutline.getWidth(), top + dragOutline.getHeight());
1255d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            if (resize) {
1256482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                cellToRect(cellX, cellY, spanX, spanY, r);
1257d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            }
1258150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung
125908ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy            mDragOutlineAnims[mDragOutlineCurrent].setTag(dragOutline);
126008ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy            mDragOutlineAnims[mDragOutlineCurrent].animateIn();
12616569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        }
12626569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    }
12636569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
1264e0310965022e7a1adb7ad489505d404186608689Adam Cohen    public void clearDragOutlines() {
1265e0310965022e7a1adb7ad489505d404186608689Adam Cohen        final int oldIndex = mDragOutlineCurrent;
1266e0310965022e7a1adb7ad489505d404186608689Adam Cohen        mDragOutlineAnims[oldIndex].animateOut();
1267d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        mDragCell[0] = mDragCell[1] = -1;
1268e0310965022e7a1adb7ad489505d404186608689Adam Cohen    }
1269e0310965022e7a1adb7ad489505d404186608689Adam Cohen
127031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
127170864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey     * Find a vacant area that will fit the given bounds nearest the requested
127270864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey     * cell location. Uses Euclidean distance to score multiple vacant areas.
1273aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     *
127451afc022fa76c79f0d1ece470ddc126c08fea8a4Romain Guy     * @param pixelX The X location at which you want to search for a vacant area.
127551afc022fa76c79f0d1ece470ddc126c08fea8a4Romain Guy     * @param pixelY The Y location at which you want to search for a vacant area.
127670864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey     * @param spanX Horizontal span of the object.
127770864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey     * @param spanY Vertical span of the object.
1278de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy     * @param result Array in which to place the result, or null (in which case a new array will
1279de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy     *        be allocated)
128070864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey     * @return The X, Y cell of a vacant area that can contain this object,
128170864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey     *         nearest the requested location.
128231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
1283d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    int[] findNearestVacantArea(int pixelX, int pixelY, int spanX, int spanY,
1284d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            int[] result) {
1285de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy        return findNearestVacantArea(pixelX, pixelY, spanX, spanY, null, result);
12866a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka    }
1287aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
12886a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka    /**
12896a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     * Find a vacant area that will fit the given bounds nearest the requested
12906a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     * cell location. Uses Euclidean distance to score multiple vacant areas.
12916a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     *
12926a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     * @param pixelX The X location at which you want to search for a vacant area.
12936a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     * @param pixelY The Y location at which you want to search for a vacant area.
1294d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param minSpanX The minimum horizontal span required
1295d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param minSpanY The minimum vertical span required
1296d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param spanX Horizontal span of the object.
1297d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param spanY Vertical span of the object.
1298d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param result Array in which to place the result, or null (in which case a new array will
1299d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *        be allocated)
1300d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @return The X, Y cell of a vacant area that can contain this object,
1301d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *         nearest the requested location.
1302d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     */
1303d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    int[] findNearestVacantArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX,
1304d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            int spanY, int[] result, int[] resultSpan) {
1305d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        return findNearestVacantArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, null,
1306d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                result, resultSpan);
1307d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    }
1308d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen
1309d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    /**
1310d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * Find a vacant area that will fit the given bounds nearest the requested
1311d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * cell location. Uses Euclidean distance to score multiple vacant areas.
1312d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *
1313d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param pixelX The X location at which you want to search for a vacant area.
1314d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param pixelY The Y location at which you want to search for a vacant area.
13156a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     * @param spanX Horizontal span of the object.
13166a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     * @param spanY Vertical span of the object.
1317df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param ignoreOccupied If true, the result can be an occupied cell
1318df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param result Array in which to place the result, or null (in which case a new array will
1319df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     *        be allocated)
13206a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     * @return The X, Y cell of a vacant area that can contain this object,
13216a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     *         nearest the requested location.
13226a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     */
1323df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    int[] findNearestArea(int pixelX, int pixelY, int spanX, int spanY, View ignoreView,
1324df0353815c629fc678824b07a234b89a1ff94208Adam Cohen            boolean ignoreOccupied, int[] result) {
1325d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        return findNearestArea(pixelX, pixelY, spanX, spanY,
1326482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                spanX, spanY, ignoreView, ignoreOccupied, result, null, mOccupied);
1327d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    }
1328d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen
1329d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    private final Stack<Rect> mTempRectStack = new Stack<Rect>();
1330d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    private void lazyInitTempRectStack() {
1331d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        if (mTempRectStack.isEmpty()) {
1332d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            for (int i = 0; i < mCountX * mCountY; i++) {
1333d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                mTempRectStack.push(new Rect());
1334d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            }
1335d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        }
1336d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    }
1337482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1338d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    private void recycleTempRects(Stack<Rect> used) {
1339d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        while (!used.isEmpty()) {
1340d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            mTempRectStack.push(used.pop());
1341d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        }
1342d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    }
1343d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen
1344d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    /**
1345d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * Find a vacant area that will fit the given bounds nearest the requested
1346d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * cell location. Uses Euclidean distance to score multiple vacant areas.
1347d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *
1348d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param pixelX The X location at which you want to search for a vacant area.
1349d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param pixelY The Y location at which you want to search for a vacant area.
1350d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param minSpanX The minimum horizontal span required
1351d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param minSpanY The minimum vertical span required
1352d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param spanX Horizontal span of the object.
1353d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param spanY Vertical span of the object.
1354d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param ignoreOccupied If true, the result can be an occupied cell
1355d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param result Array in which to place the result, or null (in which case a new array will
1356d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *        be allocated)
1357d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @return The X, Y cell of a vacant area that can contain this object,
1358d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *         nearest the requested location.
1359d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     */
1360d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    int[] findNearestArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, int spanY,
1361482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            View ignoreView, boolean ignoreOccupied, int[] result, int[] resultSpan,
1362482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            boolean[][] occupied) {
1363d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        lazyInitTempRectStack();
1364c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka        // mark space take by ignoreView as available (method checks if ignoreView is null)
1365482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsAsUnoccupiedForView(ignoreView, occupied);
1366c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka
1367e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        // For items with a spanX / spanY > 1, the passed in point (pixelX, pixelY) corresponds
1368e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        // to the center of the item, but we are searching based on the top-left cell, so
1369e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        // we translate the point over to correspond to the top-left.
1370e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        pixelX -= (mCellWidth + mWidthGap) * (spanX - 1) / 2f;
1371e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        pixelY -= (mCellHeight + mHeightGap) * (spanY - 1) / 2f;
1372e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen
137370864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey        // Keep track of best-scoring drop area
1374de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy        final int[] bestXY = result != null ? result : new int[2];
137570864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey        double bestDistance = Double.MAX_VALUE;
1376d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        final Rect bestRect = new Rect(-1, -1, -1, -1);
1377d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        final Stack<Rect> validRegions = new Stack<Rect>();
1378aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
1379de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy        final int countX = mCountX;
1380de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy        final int countY = mCountY;
1381de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy
1382d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        if (minSpanX <= 0 || minSpanY <= 0 || spanX <= 0 || spanY <= 0 ||
1383d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                spanX < minSpanX || spanY < minSpanY) {
1384d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            return bestXY;
1385d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        }
1386d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen
1387d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        for (int y = 0; y < countY - (minSpanY - 1); y++) {
1388c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka            inner:
1389d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            for (int x = 0; x < countX - (minSpanX - 1); x++) {
1390d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                int ySize = -1;
1391d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                int xSize = -1;
1392df0353815c629fc678824b07a234b89a1ff94208Adam Cohen                if (ignoreOccupied) {
1393d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    // First, let's see if this thing fits anywhere
1394d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    for (int i = 0; i < minSpanX; i++) {
1395d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        for (int j = 0; j < minSpanY; j++) {
1396df0353815c629fc678824b07a234b89a1ff94208Adam Cohen                            if (occupied[x + i][y + j]) {
1397df0353815c629fc678824b07a234b89a1ff94208Adam Cohen                                continue inner;
1398df0353815c629fc678824b07a234b89a1ff94208Adam Cohen                            }
1399c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                        }
1400c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                    }
1401d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    xSize = minSpanX;
1402d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    ySize = minSpanY;
1403d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen
1404d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    // We know that the item will fit at _some_ acceptable size, now let's see
1405d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    // how big we can make it. We'll alternate between incrementing x and y spans
1406d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    // until we hit a limit.
1407d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    boolean incX = true;
1408d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    boolean hitMaxX = xSize >= spanX;
1409d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    boolean hitMaxY = ySize >= spanY;
1410d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    while (!(hitMaxX && hitMaxY)) {
1411d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        if (incX && !hitMaxX) {
1412d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            for (int j = 0; j < ySize; j++) {
1413d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                if (x + xSize > countX -1 || occupied[x + xSize][y + j]) {
1414d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                    // We can't move out horizontally
1415d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                    hitMaxX = true;
1416d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                }
1417d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            }
1418d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            if (!hitMaxX) {
1419d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                xSize++;
1420d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            }
1421d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        } else if (!hitMaxY) {
1422d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            for (int i = 0; i < xSize; i++) {
1423d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                if (y + ySize > countY - 1 || occupied[x + i][y + ySize]) {
1424d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                    // We can't move out vertically
1425d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                    hitMaxY = true;
1426d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                }
1427d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            }
1428d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            if (!hitMaxY) {
1429d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                ySize++;
1430d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            }
1431d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        }
1432d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        hitMaxX |= xSize >= spanX;
1433d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        hitMaxY |= ySize >= spanY;
1434d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        incX = !incX;
1435d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    }
1436d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    incX = true;
1437d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    hitMaxX = xSize >= spanX;
1438d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    hitMaxY = ySize >= spanY;
1439c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                }
14400be025d64c1f84138fe430a58875886e66aae767Winson Chung                final int[] cellXY = mTmpXY;
1441e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen                cellToCenterPoint(x, y, cellXY);
1442c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka
1443d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                // We verify that the current rect is not a sub-rect of any of our previous
1444d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                // candidates. In this case, the current rect is disqualified in favour of the
1445d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                // containing rect.
1446d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                Rect currentRect = mTempRectStack.pop();
1447d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                currentRect.set(x, y, x + xSize, y + ySize);
1448d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                boolean contained = false;
1449d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                for (Rect r : validRegions) {
1450d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    if (r.contains(currentRect)) {
1451d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        contained = true;
1452d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        break;
1453d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    }
1454d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                }
1455d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                validRegions.push(currentRect);
1456c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                double distance = Math.sqrt(Math.pow(cellXY[0] - pixelX, 2)
1457c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                        + Math.pow(cellXY[1] - pixelY, 2));
1458482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1459d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                if ((distance <= bestDistance && !contained) ||
1460d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        currentRect.contains(bestRect)) {
1461c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                    bestDistance = distance;
1462c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                    bestXY[0] = x;
1463c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                    bestXY[1] = y;
1464d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    if (resultSpan != null) {
1465d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        resultSpan[0] = xSize;
1466d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        resultSpan[1] = ySize;
1467d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    }
1468d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    bestRect.set(currentRect);
1469c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                }
147031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            }
147131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
1472c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka        // re-mark space taken by ignoreView as occupied
1473482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsAsOccupiedForView(ignoreView, occupied);
147431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
1475c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        // Return -1, -1 if no suitable location found
1476c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        if (bestDistance == Double.MAX_VALUE) {
1477c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            bestXY[0] = -1;
1478c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            bestXY[1] = -1;
147970864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey        }
1480d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        recycleTempRects(validRegions);
1481c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        return bestXY;
148231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
1483aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
1484482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     /**
1485482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * Find a vacant area that will fit the given bounds nearest the requested
1486482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * cell location, and will also weigh in a suggested direction vector of the
1487482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * desired location. This method computers distance based on unit grid distances,
1488482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * not pixel distances.
1489482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     *
149047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param cellX The X cell nearest to which you want to search for a vacant area.
149147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param cellY The Y cell nearest which you want to search for a vacant area.
1492482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * @param spanX Horizontal span of the object.
1493482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * @param spanY Vertical span of the object.
149447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param direction The favored direction in which the views should move from x, y
149547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param exactDirectionOnly If this parameter is true, then only solutions where the direction
149647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     *        matches exactly. Otherwise we find the best matching direction.
149747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param occoupied The array which represents which cells in the CellLayout are occupied
149847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param blockOccupied The array which represents which cells in the specified block (cellX,
149947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     *        cellY, spanX, spanY) are occupied. This is used when try to move a group of views.
1500482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * @param result Array in which to place the result, or null (in which case a new array will
1501482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     *        be allocated)
1502482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * @return The X, Y cell of a vacant area that can contain this object,
1503482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     *         nearest the requested location.
1504482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     */
1505482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private int[] findNearestArea(int cellX, int cellY, int spanX, int spanY, int[] direction,
150647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            boolean[][] occupied, boolean blockOccupied[][], int[] result) {
1507482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // Keep track of best-scoring drop area
1508482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        final int[] bestXY = result != null ? result : new int[2];
1509482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        float bestDistance = Float.MAX_VALUE;
1510482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        int bestDirectionScore = Integer.MIN_VALUE;
1511482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1512482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        final int countX = mCountX;
1513482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        final int countY = mCountY;
1514482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1515482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int y = 0; y < countY - (spanY - 1); y++) {
1516482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            inner:
1517482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            for (int x = 0; x < countX - (spanX - 1); x++) {
1518482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                // First, let's see if this thing fits anywhere
1519482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                for (int i = 0; i < spanX; i++) {
1520482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    for (int j = 0; j < spanY; j++) {
152147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        if (occupied[x + i][y + j] && (blockOccupied == null || blockOccupied[i][j])) {
1522482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                            continue inner;
1523482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        }
1524482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    }
1525482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                }
1526482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1527482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                float distance = (float)
1528482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        Math.sqrt((x - cellX) * (x - cellX) + (y - cellY) * (y - cellY));
1529482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                int[] curDirection = mTmpPoint;
153047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                computeDirectionVector(x - cellX, y - cellY, curDirection);
153147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                // The direction score is just the dot product of the two candidate direction
153247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                // and that passed in.
1533482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                int curDirectionScore = direction[0] * curDirection[0] +
1534482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        direction[1] * curDirection[1];
153547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                boolean exactDirectionOnly = false;
153647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                boolean directionMatches = direction[0] == curDirection[0] &&
153747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        direction[0] == curDirection[0];
153847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                if ((directionMatches || !exactDirectionOnly) &&
153947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        Float.compare(distance,  bestDistance) < 0 || (Float.compare(distance,
1540482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        bestDistance) == 0 && curDirectionScore > bestDirectionScore)) {
1541482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    bestDistance = distance;
1542482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    bestDirectionScore = curDirectionScore;
1543482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    bestXY[0] = x;
1544482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    bestXY[1] = y;
1545482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                }
1546482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1547482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1548482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1549482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // Return -1, -1 if no suitable location found
1550482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (bestDistance == Float.MAX_VALUE) {
1551482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            bestXY[0] = -1;
1552482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            bestXY[1] = -1;
1553482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1554482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return bestXY;
1555482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1556482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
155747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    private int[] findNearestAreaInDirection(int cellX, int cellY, int spanX, int spanY,
155847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            int[] direction,boolean[][] occupied,
155947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            boolean blockOccupied[][], int[] result) {
156047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        // Keep track of best-scoring drop area
156147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        final int[] bestXY = result != null ? result : new int[2];
156247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        bestXY[0] = -1;
156347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        bestXY[1] = -1;
156447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        float bestDistance = Float.MAX_VALUE;
156547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
156647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        // We use this to march in a single direction
15675b53f29f809a0dad4a1e0717ba610ce737ee0f43Adam Cohen        if ((direction[0] != 0 && direction[1] != 0) ||
15685b53f29f809a0dad4a1e0717ba610ce737ee0f43Adam Cohen                (direction[0] == 0 && direction[1] == 0)) {
156947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            return bestXY;
157047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
157147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
157247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        // This will only incrememnet one of x or y based on the assertion above
157347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        int x = cellX + direction[0];
157447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        int y = cellY + direction[1];
157547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        while (x >= 0 && x + spanX <= mCountX && y >= 0 && y + spanY <= mCountY) {
157647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
157747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            boolean fail = false;
157847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            for (int i = 0; i < spanX; i++) {
157947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                for (int j = 0; j < spanY; j++) {
158047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    if (occupied[x + i][y + j] && (blockOccupied == null || blockOccupied[i][j])) {
158147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        fail = true;
158247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    }
158347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                }
158447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            }
158547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            if (!fail) {
158647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                float distance = (float)
158747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        Math.sqrt((x - cellX) * (x - cellX) + (y - cellY) * (y - cellY));
158847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                if (Float.compare(distance,  bestDistance) < 0) {
158947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    bestDistance = distance;
159047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    bestXY[0] = x;
159147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    bestXY[1] = y;
159247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                }
159347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            }
159447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            x += direction[0];
159547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            y += direction[1];
159647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
159747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        return bestXY;
159847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    }
159947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
1600482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private boolean addViewToTempLocation(View v, Rect rectOccupiedByPotentialDrop,
16018baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            int[] direction, ItemConfiguration currentState) {
16028baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        CellAndSpan c = currentState.map.get(v);
1603482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        boolean success = false;
16048baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, false);
1605482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsForRect(rectOccupiedByPotentialDrop, mTmpOccupied, true);
1606482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
16078baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        findNearestArea(c.x, c.y, c.spanX, c.spanY, direction, mTmpOccupied, null, mTempLocation);
1608482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1609482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (mTempLocation[0] >= 0 && mTempLocation[1] >= 0) {
16108baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            c.x = mTempLocation[0];
16118baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            c.y = mTempLocation[1];
1612482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            success = true;
1613482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1614482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
16158baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, true);
1616482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return success;
1617482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1618482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
161947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    // This method looks in the specified direction to see if there is an additional view
162047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    // immediately adjecent in that direction
162147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    private boolean addViewInDirection(ArrayList<View> views, Rect boundingRect, int[] direction,
162219f3792523fe2d55ea791a9286398a6120920690Adam Cohen            boolean[][] occupied, View dragView, ItemConfiguration currentState) {
162347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        boolean found = false;
162447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
1625a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        int childCount = mShortcutsAndWidgets.getChildCount();
162647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        Rect r0 = new Rect(boundingRect);
162747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        Rect r1 = new Rect();
162847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
162947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        int deltaX = 0;
163047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        int deltaY = 0;
163147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        if (direction[1] < 0) {
163247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            r0.set(r0.left, r0.top - 1, r0.right, r0.bottom);
163347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            deltaY = -1;
163447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        } else if (direction[1] > 0) {
163547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            r0.set(r0.left, r0.top, r0.right, r0.bottom + 1);
163647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            deltaY = 1;
163747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        } else if (direction[0] < 0) {
163847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            r0.set(r0.left - 1, r0.top, r0.right, r0.bottom);
163947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            deltaX = -1;
164047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        } else if (direction[0] > 0) {
164147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            r0.set(r0.left, r0.top, r0.right + 1, r0.bottom);
164247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            deltaX = 1;
164347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
164447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
164547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        for (int i = 0; i < childCount; i++) {
1646a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            View child = mShortcutsAndWidgets.getChildAt(i);
164719f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (views.contains(child) || child == dragView) continue;
16488baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = currentState.map.get(child);
164947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
16508baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
16518baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            r1.set(c.x, c.y, c.x + c.spanX, c.y + c.spanY);
165247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            if (Rect.intersects(r0, r1)) {
165347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                if (!lp.canReorder) {
165447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    return false;
165547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                }
165647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                boolean pushed = false;
16578baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                for (int x = c.x; x < c.x + c.spanX; x++) {
16588baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                    for (int y = c.y; y < c.y + c.spanY; y++) {
165947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        boolean inBounds = x - deltaX >= 0 && x -deltaX < mCountX
166047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                                && y - deltaY >= 0 && y - deltaY < mCountY;
166147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        if (inBounds && occupied[x - deltaX][y - deltaY]) {
166247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                            pushed = true;
166347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        }
166447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    }
166547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                }
166647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                if (pushed) {
166747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    views.add(child);
16688baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                    boundingRect.union(c.x, c.y, c.x + c.spanX, c.y + c.spanY);
166947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    found = true;
167047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                }
167147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            }
167247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
167347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        return found;
167447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    }
167547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
16768baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen    private boolean addViewsToTempLocation(ArrayList<View> views, Rect rectOccupiedByPotentialDrop,
167719f3792523fe2d55ea791a9286398a6120920690Adam Cohen            int[] direction, boolean push, View dragView, ItemConfiguration currentState) {
167847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        if (views.size() == 0) return true;
167947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
168047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        boolean success = false;
168147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        Rect boundingRect = null;
16828baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // We construct a rect which represents the entire group of views passed in
168347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        for (View v: views) {
16848baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = currentState.map.get(v);
168547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            if (boundingRect == null) {
16868baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                boundingRect = new Rect(c.x, c.y, c.x + c.spanX, c.y + c.spanY);
168747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            } else {
16888baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                boundingRect.union(c.x, c.y, c.x + c.spanX, c.y + c.spanY);
168947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            }
169047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
169147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
16928baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        @SuppressWarnings("unchecked")
169347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        ArrayList<View> dup = (ArrayList<View>) views.clone();
16948baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // We try and expand the group of views in the direction vector passed, based on
16958baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // whether they are physically adjacent, ie. based on "push mechanics".
169619f3792523fe2d55ea791a9286398a6120920690Adam Cohen        while (push && addViewInDirection(dup, boundingRect, direction, mTmpOccupied, dragView,
16978baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                currentState)) {
169847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
16998baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen
17008baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // Mark the occupied state as false for the group of views we want to move.
170147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        for (View v: dup) {
17028baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = currentState.map.get(v);
17038baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, false);
170447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
170547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
170647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        boolean[][] blockOccupied = new boolean[boundingRect.width()][boundingRect.height()];
170747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        int top = boundingRect.top;
170847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        int left = boundingRect.left;
17098baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // We mark more precisely which parts of the bounding rect are truly occupied, allowing
17108baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // for tetris-style interlocking.
171147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        for (View v: dup) {
17128baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = currentState.map.get(v);
17138baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            markCellsForView(c.x - left, c.y - top, c.spanX, c.spanY, blockOccupied, true);
171447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
171547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
171647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        markCellsForRect(rectOccupiedByPotentialDrop, mTmpOccupied, true);
171747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
17188baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        if (push) {
17198baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            findNearestAreaInDirection(boundingRect.left, boundingRect.top, boundingRect.width(),
17208baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                    boundingRect.height(), direction, mTmpOccupied, blockOccupied, mTempLocation);
17218baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        } else {
17228baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            findNearestArea(boundingRect.left, boundingRect.top, boundingRect.width(),
17238baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                    boundingRect.height(), direction, mTmpOccupied, blockOccupied, mTempLocation);
17248baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        }
172547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
17268baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // If we successfuly found a location by pushing the block of views, we commit it
172747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        if (mTempLocation[0] >= 0 && mTempLocation[1] >= 0) {
17288baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            int deltaX = mTempLocation[0] - boundingRect.left;
17298baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            int deltaY = mTempLocation[1] - boundingRect.top;
173047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            for (View v: dup) {
17318baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                CellAndSpan c = currentState.map.get(v);
17328baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                c.x += deltaX;
17338baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                c.y += deltaY;
173447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            }
173547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            success = true;
173647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
1737482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
17388baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // In either case, we set the occupied array as marked for the location of the views
17398baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        for (View v: dup) {
17408baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = currentState.map.get(v);
17418baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, true);
1742482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1743482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return success;
1744482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1745482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1746482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private void markCellsForRect(Rect r, boolean[][] occupied, boolean value) {
1747482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsForView(r.left, r.top, r.width(), r.height(), occupied, value);
1748482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1749482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1750482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private boolean rearrangementExists(int cellX, int cellY, int spanX, int spanY, int[] direction,
17518baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            View ignoreView, ItemConfiguration solution) {
1752e3e03bcd313ba8060f2832b6a16dea6fd6d532eaWinson Chung        // Return early if get invalid cell positions
1753e3e03bcd313ba8060f2832b6a16dea6fd6d532eaWinson Chung        if (cellX < 0 || cellY < 0) return false;
1754482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
17558baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        mIntersectingViews.clear();
1756482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        mOccupiedRect.set(cellX, cellY, cellX + spanX, cellY + spanY);
1757482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
17588baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // Mark the desired location of the view currently being dragged.
1759482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (ignoreView != null) {
17608baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = solution.map.get(ignoreView);
176119f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (c != null) {
176219f3792523fe2d55ea791a9286398a6120920690Adam Cohen                c.x = cellX;
176319f3792523fe2d55ea791a9286398a6120920690Adam Cohen                c.y = cellY;
176419f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
1765482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1766482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        Rect r0 = new Rect(cellX, cellY, cellX + spanX, cellY + spanY);
1767482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        Rect r1 = new Rect();
17688baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        for (View child: solution.map.keySet()) {
1769482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (child == ignoreView) continue;
17708baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = solution.map.get(child);
1771482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
17728baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            r1.set(c.x, c.y, c.x + c.spanX, c.y + c.spanY);
1773482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (Rect.intersects(r0, r1)) {
1774482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                if (!lp.canReorder) {
1775482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    return false;
1776482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                }
1777482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                mIntersectingViews.add(child);
1778482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1779482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
178047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
17818baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // We try to move the intersecting views as a block using the push mechanic
178219f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if (addViewsToTempLocation(mIntersectingViews, mOccupiedRect, direction, true, ignoreView,
178319f3792523fe2d55ea791a9286398a6120920690Adam Cohen                solution)) {
178447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            return true;
178547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
178647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        // Try the opposite direction
178747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        direction[0] *= -1;
178847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        direction[1] *= -1;
178919f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if (addViewsToTempLocation(mIntersectingViews, mOccupiedRect, direction, true, ignoreView,
179019f3792523fe2d55ea791a9286398a6120920690Adam Cohen                solution)) {
179147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            return true;
179247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
179347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        // Switch the direction back
179447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        direction[0] *= -1;
179547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        direction[1] *= -1;
179647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
17978baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // Next we try moving the views as a block , but without requiring the push mechanic
179819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if (addViewsToTempLocation(mIntersectingViews, mOccupiedRect, direction, false, ignoreView,
179919f3792523fe2d55ea791a9286398a6120920690Adam Cohen                solution)) {
1800482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            return true;
1801482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
180247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
1803482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // Ok, they couldn't move as a block, let's move them individually
1804482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (View v : mIntersectingViews) {
18058baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            if (!addViewToTempLocation(v, mOccupiedRect, direction, solution)) {
1806482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                return false;
1807482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1808482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1809482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return true;
1810482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1811482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1812482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    /*
1813482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * Returns a pair (x, y), where x,y are in {-1, 0, 1} corresponding to vector between
1814482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * the provided point and the provided cell
1815482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     */
181647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    private void computeDirectionVector(float deltaX, float deltaY, int[] result) {
1817482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        double angle = Math.atan(((float) deltaY) / deltaX);
1818482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1819482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        result[0] = 0;
1820482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        result[1] = 0;
1821482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (Math.abs(Math.cos(angle)) > 0.5f) {
1822482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            result[0] = (int) Math.signum(deltaX);
1823482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1824482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (Math.abs(Math.sin(angle)) > 0.5f) {
1825482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            result[1] = (int) Math.signum(deltaY);
1826482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1827482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1828482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
18298baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen    private void copyOccupiedArray(boolean[][] occupied) {
18308baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        for (int i = 0; i < mCountX; i++) {
18318baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            for (int j = 0; j < mCountY; j++) {
18328baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                occupied[i][j] = mOccupied[i][j];
18338baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            }
18348baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        }
18358baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen    }
18368baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen
1837482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    ItemConfiguration simpleSwap(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX,
1838482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            int spanY, int[] direction, View dragView, boolean decX, ItemConfiguration solution) {
18398baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // Copy the current state into the solution. This solution will be manipulated as necessary.
18408baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        copyCurrentStateToSolution(solution, false);
18418baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // Copy the current occupied array into the temporary occupied array. This array will be
18428baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // manipulated as necessary to find a solution.
18438baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        copyOccupiedArray(mTmpOccupied);
1844482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1845482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // We find the nearest cell into which we would place the dragged item, assuming there's
1846482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // nothing in its way.
1847482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        int result[] = new int[2];
1848482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        result = findNearestArea(pixelX, pixelY, spanX, spanY, result);
1849482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1850482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        boolean success = false;
1851482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // First we try the exact nearest position of the item being dragged,
1852482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // we will then want to try to move this around to other neighbouring positions
18538baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        success = rearrangementExists(result[0], result[1], spanX, spanY, direction, dragView,
18548baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                solution);
1855482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1856482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (!success) {
1857482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            // We try shrinking the widget down to size in an alternating pattern, shrink 1 in
1858482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            // x, then 1 in y etc.
1859482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (spanX > minSpanX && (minSpanY == spanY || decX)) {
1860482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                return simpleSwap(pixelX, pixelY, minSpanX, minSpanY, spanX - 1, spanY, direction,
1861482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        dragView, false, solution);
1862482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            } else if (spanY > minSpanY) {
1863482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                return simpleSwap(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY - 1, direction,
1864482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        dragView, true, solution);
1865482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1866482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.isSolution = false;
1867482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        } else {
1868482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.isSolution = true;
1869482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewX = result[0];
1870482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewY = result[1];
1871482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewSpanX = spanX;
1872482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewSpanY = spanY;
1873482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1874482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return solution;
1875482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1876482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1877482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private void copyCurrentStateToSolution(ItemConfiguration solution, boolean temp) {
1878a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        int childCount = mShortcutsAndWidgets.getChildCount();
1879482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < childCount; i++) {
1880a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            View child = mShortcutsAndWidgets.getChildAt(i);
1881482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
18828baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c;
1883482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (temp) {
18848baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                c = new CellAndSpan(lp.tmpCellX, lp.tmpCellY, lp.cellHSpan, lp.cellVSpan);
1885482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            } else {
18868baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                c = new CellAndSpan(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan);
1887482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
18888baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            solution.map.put(child, c);
1889482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1890482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1891482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1892482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private void copySolutionToTempState(ItemConfiguration solution, View dragView) {
1893482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < mCountX; i++) {
1894482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            for (int j = 0; j < mCountY; j++) {
1895482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                mTmpOccupied[i][j] = false;
1896482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1897482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1898482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1899a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        int childCount = mShortcutsAndWidgets.getChildCount();
1900482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < childCount; i++) {
1901a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            View child = mShortcutsAndWidgets.getChildAt(i);
1902482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (child == dragView) continue;
1903482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
19048baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = solution.map.get(child);
19058baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            if (c != null) {
19068baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                lp.tmpCellX = c.x;
19078baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                lp.tmpCellY = c.y;
19088baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                lp.cellHSpan = c.spanX;
19098baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                lp.cellVSpan = c.spanY;
19108baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, true);
1911482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1912482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1913482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsForView(solution.dragViewX, solution.dragViewY, solution.dragViewSpanX,
1914482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                solution.dragViewSpanY, mTmpOccupied, true);
1915482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1916482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1917482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private void animateItemsToSolution(ItemConfiguration solution, View dragView, boolean
1918482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            commitDragView) {
1919482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1920482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        boolean[][] occupied = DESTRUCTIVE_REORDER ? mOccupied : mTmpOccupied;
1921482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < mCountX; i++) {
1922482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            for (int j = 0; j < mCountY; j++) {
1923482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                occupied[i][j] = false;
1924482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1925482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1926482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1927a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        int childCount = mShortcutsAndWidgets.getChildCount();
1928482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < childCount; i++) {
1929a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            View child = mShortcutsAndWidgets.getChildAt(i);
1930482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (child == dragView) continue;
19318baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = solution.map.get(child);
19328baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            if (c != null) {
193319f3792523fe2d55ea791a9286398a6120920690Adam Cohen                animateChildToPosition(child, c.x, c.y, REORDER_ANIMATION_DURATION, 0,
193419f3792523fe2d55ea791a9286398a6120920690Adam Cohen                        DESTRUCTIVE_REORDER, false);
19358baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                markCellsForView(c.x, c.y, c.spanX, c.spanY, occupied, true);
1936482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1937482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1938482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (commitDragView) {
1939482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            markCellsForView(solution.dragViewX, solution.dragViewY, solution.dragViewSpanX,
1940482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    solution.dragViewSpanY, occupied, true);
1941482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1942482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1943482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
194419f3792523fe2d55ea791a9286398a6120920690Adam Cohen    // This method starts or changes the reorder hint animations
194519f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private void beginOrAdjustHintAnimations(ItemConfiguration solution, View dragView, int delay) {
194619f3792523fe2d55ea791a9286398a6120920690Adam Cohen        int childCount = mShortcutsAndWidgets.getChildCount();
194719f3792523fe2d55ea791a9286398a6120920690Adam Cohen        int timeForPriorAnimationToComplete = getMaxCompletionTime();
194819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        for (int i = 0; i < childCount; i++) {
194919f3792523fe2d55ea791a9286398a6120920690Adam Cohen            View child = mShortcutsAndWidgets.getChildAt(i);
195019f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (child == dragView) continue;
195119f3792523fe2d55ea791a9286398a6120920690Adam Cohen            CellAndSpan c = solution.map.get(child);
195219f3792523fe2d55ea791a9286398a6120920690Adam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
195319f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (c != null) {
195419f3792523fe2d55ea791a9286398a6120920690Adam Cohen                ReorderHintAnimation rha = new ReorderHintAnimation(child, lp.cellX, lp.cellY,
195519f3792523fe2d55ea791a9286398a6120920690Adam Cohen                        c.x, c.y, c.spanX, c.spanY);
195619f3792523fe2d55ea791a9286398a6120920690Adam Cohen                rha.animate(timeForPriorAnimationToComplete);
195719f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
195819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
195919f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
196019f3792523fe2d55ea791a9286398a6120920690Adam Cohen
196119f3792523fe2d55ea791a9286398a6120920690Adam Cohen    // Class which represents the reorder hint animations. These animations show that an item is
196219f3792523fe2d55ea791a9286398a6120920690Adam Cohen    // in a temporary state, and hint at where the item will return to.
196319f3792523fe2d55ea791a9286398a6120920690Adam Cohen    class ReorderHintAnimation {
196419f3792523fe2d55ea791a9286398a6120920690Adam Cohen        View child;
196519f3792523fe2d55ea791a9286398a6120920690Adam Cohen        float deltaX;
196619f3792523fe2d55ea791a9286398a6120920690Adam Cohen        float deltaY;
196750e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely        private static final int DURATION = 300;
196819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        private int repeatCount;
196919f3792523fe2d55ea791a9286398a6120920690Adam Cohen        private boolean cancelOnCycleComplete = false;
197019f3792523fe2d55ea791a9286398a6120920690Adam Cohen        ValueAnimator va;
197119f3792523fe2d55ea791a9286398a6120920690Adam Cohen
197219f3792523fe2d55ea791a9286398a6120920690Adam Cohen        public ReorderHintAnimation(View child, int cellX0, int cellY0, int cellX1, int cellY1,
197319f3792523fe2d55ea791a9286398a6120920690Adam Cohen                int spanX, int spanY) {
197419f3792523fe2d55ea791a9286398a6120920690Adam Cohen            regionToCenterPoint(cellX0, cellY0, spanX, spanY, mTmpPoint);
197519f3792523fe2d55ea791a9286398a6120920690Adam Cohen            final int x0 = mTmpPoint[0];
197619f3792523fe2d55ea791a9286398a6120920690Adam Cohen            final int y0 = mTmpPoint[1];
197719f3792523fe2d55ea791a9286398a6120920690Adam Cohen            regionToCenterPoint(cellX1, cellY1, spanX, spanY, mTmpPoint);
197819f3792523fe2d55ea791a9286398a6120920690Adam Cohen            final int x1 = mTmpPoint[0];
197919f3792523fe2d55ea791a9286398a6120920690Adam Cohen            final int y1 = mTmpPoint[1];
198019f3792523fe2d55ea791a9286398a6120920690Adam Cohen            final int dX = x1 - x0;
198119f3792523fe2d55ea791a9286398a6120920690Adam Cohen            final int dY = y1 - y0;
198219f3792523fe2d55ea791a9286398a6120920690Adam Cohen            deltaX = 0;
198319f3792523fe2d55ea791a9286398a6120920690Adam Cohen            deltaY = 0;
198419f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (dX == dY && dX == 0) {
198519f3792523fe2d55ea791a9286398a6120920690Adam Cohen            } else {
198619f3792523fe2d55ea791a9286398a6120920690Adam Cohen                if (dY == 0) {
198719f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    deltaX = mReorderHintAnimationMagnitude;
198819f3792523fe2d55ea791a9286398a6120920690Adam Cohen                } else if (dX == 0) {
198919f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    deltaY = mReorderHintAnimationMagnitude;
199019f3792523fe2d55ea791a9286398a6120920690Adam Cohen                } else {
199119f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    double angle = Math.atan( (float) (dY) / dX);
199219f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    deltaX = (int) (Math.cos(angle) * mReorderHintAnimationMagnitude);
199319f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    deltaY = (int) (Math.sin(angle) * mReorderHintAnimationMagnitude);
199419f3792523fe2d55ea791a9286398a6120920690Adam Cohen                }
199519f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
199650e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely            child.setPivotY(child.getMeasuredHeight() * 0.5f);
199750e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely            child.setPivotX(child.getMeasuredWidth() * 0.5f);
199819f3792523fe2d55ea791a9286398a6120920690Adam Cohen            this.child = child;
199919f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
200019f3792523fe2d55ea791a9286398a6120920690Adam Cohen
200119f3792523fe2d55ea791a9286398a6120920690Adam Cohen        void animate(int delay) {
200219f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (mShakeAnimators.containsKey(child)) {
200319f3792523fe2d55ea791a9286398a6120920690Adam Cohen                ReorderHintAnimation oldAnimation = mShakeAnimators.get(child);
200419f3792523fe2d55ea791a9286398a6120920690Adam Cohen                oldAnimation.completeAnimation();
200519f3792523fe2d55ea791a9286398a6120920690Adam Cohen                mShakeAnimators.remove(child);
200619f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
200719f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (deltaX == 0 && deltaY == 0) {
200819f3792523fe2d55ea791a9286398a6120920690Adam Cohen                return;
200919f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
201019f3792523fe2d55ea791a9286398a6120920690Adam Cohen            va = ValueAnimator.ofFloat(0f, 1f);
201119f3792523fe2d55ea791a9286398a6120920690Adam Cohen            va.setRepeatMode(ValueAnimator.REVERSE);
201219f3792523fe2d55ea791a9286398a6120920690Adam Cohen            va.setRepeatCount(ValueAnimator.INFINITE);
201350e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely            va.setDuration((int) (DURATION * (1.0f + Math.random()*.08f)));
201419f3792523fe2d55ea791a9286398a6120920690Adam Cohen            va.addUpdateListener(new AnimatorUpdateListener() {
201519f3792523fe2d55ea791a9286398a6120920690Adam Cohen                @Override
201619f3792523fe2d55ea791a9286398a6120920690Adam Cohen                public void onAnimationUpdate(ValueAnimator animation) {
201719f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    float r = ((Float) animation.getAnimatedValue()).floatValue();
201819f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    float x = r * deltaX;
201919f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    float y = r * deltaY;
202019f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    child.setTranslationX(x);
202119f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    child.setTranslationY(y);
202250e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely                    float sf = 4.0f / child.getWidth();
202350e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely                    float s = 1.0f - r * sf;
202450e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely                    child.setScaleX(s);
202550e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely                    child.setScaleY(s);
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        }
204650e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely        private void completeAnimationImmediately() {
204750e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely            va.cancel();
204850e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely
204950e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely            AnimatorSet s = new AnimatorSet();
205050e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely            s.playTogether(
205150e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely                ObjectAnimator.ofFloat(child, "scaleX", 1f),
205250e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely                ObjectAnimator.ofFloat(child, "scaleY", 1f),
205350e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely                ObjectAnimator.ofFloat(child, "translationX", 0f),
205450e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely                ObjectAnimator.ofFloat(child, "translationX", 0f)
205550e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely            );
205650e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely            s.setDuration(REORDER_ANIMATION_DURATION);
205750e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely            s.setInterpolator(new android.view.animation.DecelerateInterpolator(1.5f));
205850e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely            s.start();
205950e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely        }
206050e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely
206119f3792523fe2d55ea791a9286398a6120920690Adam Cohen
206219f3792523fe2d55ea791a9286398a6120920690Adam Cohen        // Returns the time required to complete the current oscillating animation
206319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        private int completionTime() {
206419f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (repeatCount % 2 == 0) {
206519f3792523fe2d55ea791a9286398a6120920690Adam Cohen                return (int) (va.getDuration() - va.getCurrentPlayTime() + DURATION);
206619f3792523fe2d55ea791a9286398a6120920690Adam Cohen            } else {
206719f3792523fe2d55ea791a9286398a6120920690Adam Cohen                return (int) (va.getDuration() - va.getCurrentPlayTime());
206819f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
206919f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
207019f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
207119f3792523fe2d55ea791a9286398a6120920690Adam Cohen
207219f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private void completeAndClearReorderHintAnimations() {
207319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        for (ReorderHintAnimation a: mShakeAnimators.values()) {
207450e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely            a.completeAnimationImmediately();
207519f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
207619f3792523fe2d55ea791a9286398a6120920690Adam Cohen        mShakeAnimators.clear();
207719f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
207819f3792523fe2d55ea791a9286398a6120920690Adam Cohen
207919f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private int getMaxCompletionTime() {
208019f3792523fe2d55ea791a9286398a6120920690Adam Cohen        int maxTime = 0;
208119f3792523fe2d55ea791a9286398a6120920690Adam Cohen        for (ReorderHintAnimation a: mShakeAnimators.values()) {
208219f3792523fe2d55ea791a9286398a6120920690Adam Cohen            maxTime = Math.max(maxTime, a.completionTime());
208319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
208419f3792523fe2d55ea791a9286398a6120920690Adam Cohen        return maxTime;
208519f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
208619f3792523fe2d55ea791a9286398a6120920690Adam Cohen
2087482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private void commitTempPlacement() {
2088482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < mCountX; i++) {
2089482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            for (int j = 0; j < mCountY; j++) {
2090482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                mOccupied[i][j] = mTmpOccupied[i][j];
2091482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
2092482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2093a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        int childCount = mShortcutsAndWidgets.getChildCount();
2094482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < childCount; i++) {
2095ea889a294be004f4b1c21e9b874f9e63abfb8bd6Adam Cohen            View child = mShortcutsAndWidgets.getChildAt(i);
2096ea889a294be004f4b1c21e9b874f9e63abfb8bd6Adam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
2097ea889a294be004f4b1c21e9b874f9e63abfb8bd6Adam Cohen            ItemInfo info = (ItemInfo) child.getTag();
20982acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen            // We do a null check here because the item info can be null in the case of the
20992acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen            // AllApps button in the hotseat.
21002acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen            if (info != null) {
21012acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen                info.cellX = lp.cellX = lp.tmpCellX;
21022acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen                info.cellY = lp.cellY = lp.tmpCellY;
2103bebf042666cffe52039b875a549a582abd78a431Adam Cohen                info.spanX = lp.cellHSpan;
2104bebf042666cffe52039b875a549a582abd78a431Adam Cohen                info.spanY = lp.cellVSpan;
21052acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen            }
2106482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
21072acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen        mLauncher.getWorkspace().updateItemLocationsInDatabase(this);
2108482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2109482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2110482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public void setUseTempCoords(boolean useTempCoords) {
2111a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        int childCount = mShortcutsAndWidgets.getChildCount();
2112482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < childCount; i++) {
2113a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            LayoutParams lp = (LayoutParams) mShortcutsAndWidgets.getChildAt(i).getLayoutParams();
2114482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            lp.useTmpCoords = useTempCoords;
2115482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2116482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2117482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2118482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    ItemConfiguration findConfigurationNoShuffle(int pixelX, int pixelY, int minSpanX, int minSpanY,
2119482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            int spanX, int spanY, View dragView, ItemConfiguration solution) {
2120482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        int[] result = new int[2];
2121482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        int[] resultSpan = new int[2];
2122482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        findNearestVacantArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, null, result,
2123482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                resultSpan);
2124482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (result[0] >= 0 && result[1] >= 0) {
2125482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            copyCurrentStateToSolution(solution, false);
2126482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewX = result[0];
2127482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewY = result[1];
2128482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewSpanX = resultSpan[0];
2129482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewSpanY = resultSpan[1];
2130482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.isSolution = true;
2131482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        } else {
2132482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.isSolution = false;
2133482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2134482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return solution;
2135482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2136482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2137482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public void prepareChildForDrag(View child) {
2138482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsAsUnoccupiedForView(child);
2139482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2140482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
214119f3792523fe2d55ea791a9286398a6120920690Adam Cohen    /* This seems like it should be obvious and straight-forward, but when the direction vector
214219f3792523fe2d55ea791a9286398a6120920690Adam Cohen    needs to match with the notion of the dragView pushing other views, we have to employ
214319f3792523fe2d55ea791a9286398a6120920690Adam Cohen    a slightly more subtle notion of the direction vector. The question is what two points is
214419f3792523fe2d55ea791a9286398a6120920690Adam Cohen    the vector between? The center of the dragView and its desired destination? Not quite, as
214519f3792523fe2d55ea791a9286398a6120920690Adam Cohen    this doesn't necessarily coincide with the interaction of the dragView and items occupying
214619f3792523fe2d55ea791a9286398a6120920690Adam Cohen    those cells. Instead we use some heuristics to often lock the vector to up, down, left
214719f3792523fe2d55ea791a9286398a6120920690Adam Cohen    or right, which helps make pushing feel right.
214819f3792523fe2d55ea791a9286398a6120920690Adam Cohen    */
214919f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private void getDirectionVectorForDrop(int dragViewCenterX, int dragViewCenterY, int spanX,
215019f3792523fe2d55ea791a9286398a6120920690Adam Cohen            int spanY, View dragView, int[] resultDirection) {
215119f3792523fe2d55ea791a9286398a6120920690Adam Cohen        int[] targetDestination = new int[2];
215219f3792523fe2d55ea791a9286398a6120920690Adam Cohen
215319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        findNearestArea(dragViewCenterX, dragViewCenterY, spanX, spanY, targetDestination);
215419f3792523fe2d55ea791a9286398a6120920690Adam Cohen        Rect dragRect = new Rect();
215519f3792523fe2d55ea791a9286398a6120920690Adam Cohen        regionToRect(targetDestination[0], targetDestination[1], spanX, spanY, dragRect);
215619f3792523fe2d55ea791a9286398a6120920690Adam Cohen        dragRect.offset(dragViewCenterX - dragRect.centerX(), dragViewCenterY - dragRect.centerY());
215719f3792523fe2d55ea791a9286398a6120920690Adam Cohen
215819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        Rect dropRegionRect = new Rect();
215919f3792523fe2d55ea791a9286398a6120920690Adam Cohen        getViewsIntersectingRegion(targetDestination[0], targetDestination[1], spanX, spanY,
216019f3792523fe2d55ea791a9286398a6120920690Adam Cohen                dragView, dropRegionRect, mIntersectingViews);
216119f3792523fe2d55ea791a9286398a6120920690Adam Cohen
216219f3792523fe2d55ea791a9286398a6120920690Adam Cohen        int dropRegionSpanX = dropRegionRect.width();
216319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        int dropRegionSpanY = dropRegionRect.height();
216419f3792523fe2d55ea791a9286398a6120920690Adam Cohen
216519f3792523fe2d55ea791a9286398a6120920690Adam Cohen        regionToRect(dropRegionRect.left, dropRegionRect.top, dropRegionRect.width(),
216619f3792523fe2d55ea791a9286398a6120920690Adam Cohen                dropRegionRect.height(), dropRegionRect);
216719f3792523fe2d55ea791a9286398a6120920690Adam Cohen
216819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        int deltaX = (dropRegionRect.centerX() - dragViewCenterX) / spanX;
216919f3792523fe2d55ea791a9286398a6120920690Adam Cohen        int deltaY = (dropRegionRect.centerY() - dragViewCenterY) / spanY;
217019f3792523fe2d55ea791a9286398a6120920690Adam Cohen
217119f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if (dropRegionSpanX == mCountX || spanX == mCountX) {
217219f3792523fe2d55ea791a9286398a6120920690Adam Cohen            deltaX = 0;
217319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
217419f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if (dropRegionSpanY == mCountY || spanY == mCountY) {
217519f3792523fe2d55ea791a9286398a6120920690Adam Cohen            deltaY = 0;
217619f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
217719f3792523fe2d55ea791a9286398a6120920690Adam Cohen
217819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if (deltaX == 0 && deltaY == 0) {
217919f3792523fe2d55ea791a9286398a6120920690Adam Cohen            // No idea what to do, give a random direction.
218019f3792523fe2d55ea791a9286398a6120920690Adam Cohen            resultDirection[0] = 1;
218119f3792523fe2d55ea791a9286398a6120920690Adam Cohen            resultDirection[1] = 0;
218219f3792523fe2d55ea791a9286398a6120920690Adam Cohen        } else {
218319f3792523fe2d55ea791a9286398a6120920690Adam Cohen            computeDirectionVector(deltaX, deltaY, resultDirection);
218419f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
218519f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
218619f3792523fe2d55ea791a9286398a6120920690Adam Cohen
218719f3792523fe2d55ea791a9286398a6120920690Adam Cohen    // For a given cell and span, fetch the set of views intersecting the region.
218819f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private void getViewsIntersectingRegion(int cellX, int cellY, int spanX, int spanY,
218919f3792523fe2d55ea791a9286398a6120920690Adam Cohen            View dragView, Rect boundingRect, ArrayList<View> intersectingViews) {
219019f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if (boundingRect != null) {
219119f3792523fe2d55ea791a9286398a6120920690Adam Cohen            boundingRect.set(cellX, cellY, cellX + spanX, cellY + spanY);
219219f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
219319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        intersectingViews.clear();
219419f3792523fe2d55ea791a9286398a6120920690Adam Cohen        Rect r0 = new Rect(cellX, cellY, cellX + spanX, cellY + spanY);
219519f3792523fe2d55ea791a9286398a6120920690Adam Cohen        Rect r1 = new Rect();
219619f3792523fe2d55ea791a9286398a6120920690Adam Cohen        final int count = mShortcutsAndWidgets.getChildCount();
219719f3792523fe2d55ea791a9286398a6120920690Adam Cohen        for (int i = 0; i < count; i++) {
219819f3792523fe2d55ea791a9286398a6120920690Adam Cohen            View child = mShortcutsAndWidgets.getChildAt(i);
219919f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (child == dragView) continue;
220019f3792523fe2d55ea791a9286398a6120920690Adam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
220119f3792523fe2d55ea791a9286398a6120920690Adam Cohen            r1.set(lp.cellX, lp.cellY, lp.cellX + lp.cellHSpan, lp.cellY + lp.cellVSpan);
220219f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (Rect.intersects(r0, r1)) {
220319f3792523fe2d55ea791a9286398a6120920690Adam Cohen                mIntersectingViews.add(child);
220419f3792523fe2d55ea791a9286398a6120920690Adam Cohen                if (boundingRect != null) {
220519f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    boundingRect.union(r1);
220619f3792523fe2d55ea791a9286398a6120920690Adam Cohen                }
220719f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
220819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
220919f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
221019f3792523fe2d55ea791a9286398a6120920690Adam Cohen
221119f3792523fe2d55ea791a9286398a6120920690Adam Cohen    boolean isNearestDropLocationOccupied(int pixelX, int pixelY, int spanX, int spanY,
221219f3792523fe2d55ea791a9286398a6120920690Adam Cohen            View dragView, int[] result) {
221319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        result = findNearestArea(pixelX, pixelY, spanX, spanY, result);
221419f3792523fe2d55ea791a9286398a6120920690Adam Cohen        getViewsIntersectingRegion(result[0], result[1], spanX, spanY, dragView, null,
221519f3792523fe2d55ea791a9286398a6120920690Adam Cohen                mIntersectingViews);
221619f3792523fe2d55ea791a9286398a6120920690Adam Cohen        return !mIntersectingViews.isEmpty();
221719f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
221819f3792523fe2d55ea791a9286398a6120920690Adam Cohen
221919f3792523fe2d55ea791a9286398a6120920690Adam Cohen    void revertTempState() {
222019f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if (!isItemPlacementDirty() || DESTRUCTIVE_REORDER) return;
222119f3792523fe2d55ea791a9286398a6120920690Adam Cohen        final int count = mShortcutsAndWidgets.getChildCount();
222219f3792523fe2d55ea791a9286398a6120920690Adam Cohen        for (int i = 0; i < count; i++) {
222319f3792523fe2d55ea791a9286398a6120920690Adam Cohen            View child = mShortcutsAndWidgets.getChildAt(i);
222419f3792523fe2d55ea791a9286398a6120920690Adam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
222519f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (lp.tmpCellX != lp.cellX || lp.tmpCellY != lp.cellY) {
222619f3792523fe2d55ea791a9286398a6120920690Adam Cohen                lp.tmpCellX = lp.cellX;
222719f3792523fe2d55ea791a9286398a6120920690Adam Cohen                lp.tmpCellY = lp.cellY;
222819f3792523fe2d55ea791a9286398a6120920690Adam Cohen                animateChildToPosition(child, lp.cellX, lp.cellY, REORDER_ANIMATION_DURATION,
222919f3792523fe2d55ea791a9286398a6120920690Adam Cohen                        0, false, false);
223019f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
223119f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
223219f3792523fe2d55ea791a9286398a6120920690Adam Cohen        completeAndClearReorderHintAnimations();
223319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        setItemPlacementDirty(false);
223419f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
223519f3792523fe2d55ea791a9286398a6120920690Adam Cohen
2236bebf042666cffe52039b875a549a582abd78a431Adam Cohen    boolean createAreaForResize(int cellX, int cellY, int spanX, int spanY,
2237bebf042666cffe52039b875a549a582abd78a431Adam Cohen            View dragView, int[] direction, boolean commit) {
2238bebf042666cffe52039b875a549a582abd78a431Adam Cohen        int[] pixelXY = new int[2];
2239bebf042666cffe52039b875a549a582abd78a431Adam Cohen        regionToCenterPoint(cellX, cellY, spanX, spanY, pixelXY);
2240bebf042666cffe52039b875a549a582abd78a431Adam Cohen
2241bebf042666cffe52039b875a549a582abd78a431Adam Cohen        // First we determine if things have moved enough to cause a different layout
2242bebf042666cffe52039b875a549a582abd78a431Adam Cohen        ItemConfiguration swapSolution = simpleSwap(pixelXY[0], pixelXY[1], spanX, spanY,
2243bebf042666cffe52039b875a549a582abd78a431Adam Cohen                 spanX,  spanY, direction, dragView,  true,  new ItemConfiguration());
2244bebf042666cffe52039b875a549a582abd78a431Adam Cohen
2245bebf042666cffe52039b875a549a582abd78a431Adam Cohen        setUseTempCoords(true);
2246bebf042666cffe52039b875a549a582abd78a431Adam Cohen        if (swapSolution != null && swapSolution.isSolution) {
2247bebf042666cffe52039b875a549a582abd78a431Adam Cohen            // If we're just testing for a possible location (MODE_ACCEPT_DROP), we don't bother
2248bebf042666cffe52039b875a549a582abd78a431Adam Cohen            // committing anything or animating anything as we just want to determine if a solution
2249bebf042666cffe52039b875a549a582abd78a431Adam Cohen            // exists
2250bebf042666cffe52039b875a549a582abd78a431Adam Cohen            copySolutionToTempState(swapSolution, dragView);
2251bebf042666cffe52039b875a549a582abd78a431Adam Cohen            setItemPlacementDirty(true);
2252bebf042666cffe52039b875a549a582abd78a431Adam Cohen            animateItemsToSolution(swapSolution, dragView, commit);
2253bebf042666cffe52039b875a549a582abd78a431Adam Cohen
2254bebf042666cffe52039b875a549a582abd78a431Adam Cohen            if (commit) {
2255bebf042666cffe52039b875a549a582abd78a431Adam Cohen                commitTempPlacement();
2256bebf042666cffe52039b875a549a582abd78a431Adam Cohen                completeAndClearReorderHintAnimations();
2257bebf042666cffe52039b875a549a582abd78a431Adam Cohen                setItemPlacementDirty(false);
2258bebf042666cffe52039b875a549a582abd78a431Adam Cohen            } else {
2259bebf042666cffe52039b875a549a582abd78a431Adam Cohen                beginOrAdjustHintAnimations(swapSolution, dragView,
2260bebf042666cffe52039b875a549a582abd78a431Adam Cohen                        REORDER_ANIMATION_DURATION);
2261bebf042666cffe52039b875a549a582abd78a431Adam Cohen            }
2262bebf042666cffe52039b875a549a582abd78a431Adam Cohen            mShortcutsAndWidgets.requestLayout();
2263bebf042666cffe52039b875a549a582abd78a431Adam Cohen        }
2264bebf042666cffe52039b875a549a582abd78a431Adam Cohen        return swapSolution.isSolution;
2265bebf042666cffe52039b875a549a582abd78a431Adam Cohen    }
2266bebf042666cffe52039b875a549a582abd78a431Adam Cohen
2267482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    int[] createArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, int spanY,
2268482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            View dragView, int[] result, int resultSpan[], int mode) {
2269482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // First we determine if things have moved enough to cause a different layout
227047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        result = findNearestArea(pixelX, pixelY, spanX, spanY, result);
2271482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2272482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (resultSpan == null) {
2273482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            resultSpan = new int[2];
2274482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2275482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
227619f3792523fe2d55ea791a9286398a6120920690Adam Cohen        // When we are checking drop validity or actually dropping, we don't recompute the
227719f3792523fe2d55ea791a9286398a6120920690Adam Cohen        // direction vector, since we want the solution to match the preview, and it's possible
227819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        // that the exact position of the item has changed to result in a new reordering outcome.
2279b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen        if ((mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL || mode == MODE_ACCEPT_DROP)
2280b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen               && mPreviousReorderDirection[0] != INVALID_DIRECTION) {
228119f3792523fe2d55ea791a9286398a6120920690Adam Cohen            mDirectionVector[0] = mPreviousReorderDirection[0];
228219f3792523fe2d55ea791a9286398a6120920690Adam Cohen            mDirectionVector[1] = mPreviousReorderDirection[1];
228319f3792523fe2d55ea791a9286398a6120920690Adam Cohen            // We reset this vector after drop
2284b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen            if (mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL) {
2285b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen                mPreviousReorderDirection[0] = INVALID_DIRECTION;
2286b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen                mPreviousReorderDirection[1] = INVALID_DIRECTION;
228719f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
228819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        } else {
228919f3792523fe2d55ea791a9286398a6120920690Adam Cohen            getDirectionVectorForDrop(pixelX, pixelY, spanX, spanY, dragView, mDirectionVector);
229019f3792523fe2d55ea791a9286398a6120920690Adam Cohen            mPreviousReorderDirection[0] = mDirectionVector[0];
229119f3792523fe2d55ea791a9286398a6120920690Adam Cohen            mPreviousReorderDirection[1] = mDirectionVector[1];
229219f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
229319f3792523fe2d55ea791a9286398a6120920690Adam Cohen
2294482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        ItemConfiguration swapSolution = simpleSwap(pixelX, pixelY, minSpanX, minSpanY,
2295482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                 spanX,  spanY, mDirectionVector, dragView,  true,  new ItemConfiguration());
2296482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2297482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // We attempt the approach which doesn't shuffle views at all
2298482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        ItemConfiguration noShuffleSolution = findConfigurationNoShuffle(pixelX, pixelY, minSpanX,
2299482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                minSpanY, spanX, spanY, dragView, new ItemConfiguration());
2300482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2301482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        ItemConfiguration finalSolution = null;
2302482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (swapSolution.isSolution && swapSolution.area() >= noShuffleSolution.area()) {
2303482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            finalSolution = swapSolution;
2304482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        } else if (noShuffleSolution.isSolution) {
2305482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            finalSolution = noShuffleSolution;
2306482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2307482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2308482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        boolean foundSolution = true;
2309482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (!DESTRUCTIVE_REORDER) {
2310482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            setUseTempCoords(true);
2311482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2312482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2313482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (finalSolution != null) {
2314482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            result[0] = finalSolution.dragViewX;
2315482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            result[1] = finalSolution.dragViewY;
2316482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            resultSpan[0] = finalSolution.dragViewSpanX;
2317482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            resultSpan[1] = finalSolution.dragViewSpanY;
2318482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2319482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            // If we're just testing for a possible location (MODE_ACCEPT_DROP), we don't bother
2320482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            // committing anything or animating anything as we just want to determine if a solution
2321482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            // exists
2322482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (mode == MODE_DRAG_OVER || mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL) {
2323482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                if (!DESTRUCTIVE_REORDER) {
2324482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    copySolutionToTempState(finalSolution, dragView);
2325482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                }
2326482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                setItemPlacementDirty(true);
2327482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                animateItemsToSolution(finalSolution, dragView, mode == MODE_ON_DROP);
2328482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
232919f3792523fe2d55ea791a9286398a6120920690Adam Cohen                if (!DESTRUCTIVE_REORDER &&
233019f3792523fe2d55ea791a9286398a6120920690Adam Cohen                        (mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL)) {
2331482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    commitTempPlacement();
233219f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    completeAndClearReorderHintAnimations();
233319f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    setItemPlacementDirty(false);
233419f3792523fe2d55ea791a9286398a6120920690Adam Cohen                } else {
233519f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    beginOrAdjustHintAnimations(finalSolution, dragView,
233619f3792523fe2d55ea791a9286398a6120920690Adam Cohen                            REORDER_ANIMATION_DURATION);
2337482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                }
2338482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
2339482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        } else {
2340482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            foundSolution = false;
2341482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            result[0] = result[1] = resultSpan[0] = resultSpan[1] = -1;
2342482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2343482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2344482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if ((mode == MODE_ON_DROP || !foundSolution) && !DESTRUCTIVE_REORDER) {
2345482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            setUseTempCoords(false);
2346482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2347482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2348a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.requestLayout();
2349482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return result;
2350482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2351482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
235219f3792523fe2d55ea791a9286398a6120920690Adam Cohen    void setItemPlacementDirty(boolean dirty) {
235319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        mItemPlacementDirty = dirty;
2354482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
235519f3792523fe2d55ea791a9286398a6120920690Adam Cohen    boolean isItemPlacementDirty() {
235619f3792523fe2d55ea791a9286398a6120920690Adam Cohen        return mItemPlacementDirty;
2357482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2358482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2359482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private class ItemConfiguration {
23608baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        HashMap<View, CellAndSpan> map = new HashMap<View, CellAndSpan>();
2361482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        boolean isSolution = false;
2362482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        int dragViewX, dragViewY, dragViewSpanX, dragViewSpanY;
2363482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2364482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        int area() {
2365482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            return dragViewSpanX * dragViewSpanY;
2366482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
23678baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen    }
23688baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen
23698baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen    private class CellAndSpan {
23708baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        int x, y;
23718baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        int spanX, spanY;
23728baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen
23738baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        public CellAndSpan(int x, int y, int spanX, int spanY) {
23748baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            this.x = x;
23758baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            this.y = y;
23768baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            this.spanX = spanX;
23778baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            this.spanY = spanY;
2378482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2379482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2380482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2381df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    /**
2382df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * Find a vacant area that will fit the given bounds nearest the requested
2383df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * cell location. Uses Euclidean distance to score multiple vacant areas.
2384df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     *
2385df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param pixelX The X location at which you want to search for a vacant area.
2386df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param pixelY The Y location at which you want to search for a vacant area.
2387df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param spanX Horizontal span of the object.
2388df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param spanY Vertical span of the object.
2389df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param ignoreView Considers space occupied by this view as unoccupied
2390df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param result Previously returned value to possibly recycle.
2391df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @return The X, Y cell of a vacant area that can contain this object,
2392df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     *         nearest the requested location.
2393df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     */
2394df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    int[] findNearestVacantArea(
2395df0353815c629fc678824b07a234b89a1ff94208Adam Cohen            int pixelX, int pixelY, int spanX, int spanY, View ignoreView, int[] result) {
2396df0353815c629fc678824b07a234b89a1ff94208Adam Cohen        return findNearestArea(pixelX, pixelY, spanX, spanY, ignoreView, true, result);
2397df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    }
2398df0353815c629fc678824b07a234b89a1ff94208Adam Cohen
2399df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    /**
2400d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * Find a vacant area that will fit the given bounds nearest the requested
2401d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * cell location. Uses Euclidean distance to score multiple vacant areas.
2402d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *
2403d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param pixelX The X location at which you want to search for a vacant area.
2404d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param pixelY The Y location at which you want to search for a vacant area.
2405d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param minSpanX The minimum horizontal span required
2406d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param minSpanY The minimum vertical span required
2407d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param spanX Horizontal span of the object.
2408d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param spanY Vertical span of the object.
2409d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param ignoreView Considers space occupied by this view as unoccupied
2410d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param result Previously returned value to possibly recycle.
2411d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @return The X, Y cell of a vacant area that can contain this object,
2412d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *         nearest the requested location.
2413d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     */
2414d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    int[] findNearestVacantArea(int pixelX, int pixelY, int minSpanX, int minSpanY,
2415d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            int spanX, int spanY, View ignoreView, int[] result, int[] resultSpan) {
2416482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return findNearestArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, ignoreView, true,
2417482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                result, resultSpan, mOccupied);
2418d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    }
2419d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen
2420d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    /**
2421df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * Find a starting cell position that will fit the given bounds nearest the requested
2422df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * cell location. Uses Euclidean distance to score multiple vacant areas.
2423df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     *
2424df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param pixelX The X location at which you want to search for a vacant area.
2425df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param pixelY The Y location at which you want to search for a vacant area.
2426df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param spanX Horizontal span of the object.
2427df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param spanY Vertical span of the object.
2428df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param ignoreView Considers space occupied by this view as unoccupied
2429df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param result Previously returned value to possibly recycle.
2430df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @return The X, Y cell of a vacant area that can contain this object,
2431df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     *         nearest the requested location.
2432df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     */
2433df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    int[] findNearestArea(
2434df0353815c629fc678824b07a234b89a1ff94208Adam Cohen            int pixelX, int pixelY, int spanX, int spanY, int[] result) {
2435df0353815c629fc678824b07a234b89a1ff94208Adam Cohen        return findNearestArea(pixelX, pixelY, spanX, spanY, null, false, result);
2436df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    }
2437df0353815c629fc678824b07a234b89a1ff94208Adam Cohen
24380280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    boolean existsEmptyCell() {
24390280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        return findCellForSpan(null, 1, 1);
24400280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
24410280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
24420280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    /**
24430280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * Finds the upper-left coordinate of the first rectangle in the grid that can
24440280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * hold a cell of the specified dimensions. If intersectX and intersectY are not -1,
24450280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * then this method will only return coordinates for rectangles that contain the cell
24460280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * (intersectX, intersectY)
24470280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     *
24480280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param cellXY The array that will contain the position of a vacant cell if such a cell
24490280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     *               can be found.
24500280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param spanX The horizontal span of the cell we want to find.
24510280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param spanY The vertical span of the cell we want to find.
24520280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     *
24530280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @return True if a vacant cell of the specified dimension was found, false otherwise.
24540280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     */
24550280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    boolean findCellForSpan(int[] cellXY, int spanX, int spanY) {
2456482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return findCellForSpanThatIntersectsIgnoring(cellXY, spanX, spanY, -1, -1, null, mOccupied);
24570280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
24580280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
24590280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    /**
24600280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * Like above, but ignores any cells occupied by the item "ignoreView"
24610280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     *
24620280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param cellXY The array that will contain the position of a vacant cell if such a cell
24630280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     *               can be found.
24640280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param spanX The horizontal span of the cell we want to find.
24650280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param spanY The vertical span of the cell we want to find.
24660280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param ignoreView The home screen item we should treat as not occupying any space
24670280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @return
24680280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     */
24690280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    boolean findCellForSpanIgnoring(int[] cellXY, int spanX, int spanY, View ignoreView) {
2470482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return findCellForSpanThatIntersectsIgnoring(cellXY, spanX, spanY, -1, -1,
2471482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                ignoreView, mOccupied);
24720280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
24730280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
24740280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    /**
24750280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * Like above, but if intersectX and intersectY are not -1, then this method will try to
24760280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * return coordinates for rectangles that contain the cell [intersectX, intersectY]
24770280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     *
24780280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param spanX The horizontal span of the cell we want to find.
24790280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param spanY The vertical span of the cell we want to find.
24800280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param ignoreView The home screen item we should treat as not occupying any space
24810280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param intersectX The X coordinate of the cell that we should try to overlap
24820280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param intersectX The Y coordinate of the cell that we should try to overlap
24830280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     *
24840280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @return True if a vacant cell of the specified dimension was found, false otherwise.
24850280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     */
24860280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    boolean findCellForSpanThatIntersects(int[] cellXY, int spanX, int spanY,
24870280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            int intersectX, int intersectY) {
24880280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        return findCellForSpanThatIntersectsIgnoring(
2489482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                cellXY, spanX, spanY, intersectX, intersectY, null, mOccupied);
24900280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
24910280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
24920280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    /**
24930280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * The superset of the above two methods
24940280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     */
24950280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    boolean findCellForSpanThatIntersectsIgnoring(int[] cellXY, int spanX, int spanY,
2496482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            int intersectX, int intersectY, View ignoreView, boolean occupied[][]) {
2497c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka        // mark space take by ignoreView as available (method checks if ignoreView is null)
2498482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsAsUnoccupiedForView(ignoreView, occupied);
24990280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
250028750fba6a2d141eb9a1e566718c17236030b815Michael Jurka        boolean foundCell = false;
25010280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        while (true) {
25020280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            int startX = 0;
25030280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            if (intersectX >= 0) {
25040280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                startX = Math.max(startX, intersectX - (spanX - 1));
25050280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            }
25060280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            int endX = mCountX - (spanX - 1);
25070280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            if (intersectX >= 0) {
25080280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                endX = Math.min(endX, intersectX + (spanX - 1) + (spanX == 1 ? 1 : 0));
25090280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            }
25100280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            int startY = 0;
25110280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            if (intersectY >= 0) {
25120280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                startY = Math.max(startY, intersectY - (spanY - 1));
25130280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            }
25140280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            int endY = mCountY - (spanY - 1);
25150280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            if (intersectY >= 0) {
25160280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                endY = Math.min(endY, intersectY + (spanY - 1) + (spanY == 1 ? 1 : 0));
25170280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            }
25180280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
2519bbc60d8e79416e37cbede55c159bf6aaa6c171d5Winson Chung            for (int y = startY; y < endY && !foundCell; y++) {
25200280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                inner:
2521bbc60d8e79416e37cbede55c159bf6aaa6c171d5Winson Chung                for (int x = startX; x < endX; x++) {
25220280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                    for (int i = 0; i < spanX; i++) {
25230280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                        for (int j = 0; j < spanY; j++) {
2524482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                            if (occupied[x + i][y + j]) {
2525bbc60d8e79416e37cbede55c159bf6aaa6c171d5Winson Chung                                // small optimization: we can skip to after the column we just found
25260280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                                // an occupied cell
2527bbc60d8e79416e37cbede55c159bf6aaa6c171d5Winson Chung                                x += i;
25280280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                                continue inner;
25290280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                            }
25300280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                        }
25310280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                    }
25320280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                    if (cellXY != null) {
25330280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                        cellXY[0] = x;
25340280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                        cellXY[1] = y;
25350280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                    }
253628750fba6a2d141eb9a1e566718c17236030b815Michael Jurka                    foundCell = true;
253728750fba6a2d141eb9a1e566718c17236030b815Michael Jurka                    break;
25380280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                }
25390280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            }
25400280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            if (intersectX == -1 && intersectY == -1) {
25410280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                break;
25420280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            } else {
25430280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                // if we failed to find anything, try again but without any requirements of
25440280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                // intersecting
25450280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                intersectX = -1;
25460280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                intersectY = -1;
25470280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                continue;
25480280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            }
25490280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        }
25500280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
2551c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka        // re-mark space taken by ignoreView as occupied
2552482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsAsOccupiedForView(ignoreView, occupied);
255328750fba6a2d141eb9a1e566718c17236030b815Michael Jurka        return foundCell;
25540280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
25550280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
255631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
2557c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung     * A drag event has begun over this layout.
2558c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung     * It may have begun over this layout (in which case onDragChild is called first),
2559c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung     * or it may have begun on another layout.
2560c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung     */
2561c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung    void onDragEnter() {
2562c6cc61d45836e4081920883cc4d448ccb0bb8417Adam Cohen        mDragEnforcer.onDragEnter();
2563c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung        mDragging = true;
2564c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung    }
2565c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung
2566c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung    /**
25670280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * Called when drag has left this CellLayout or has been completed (successfully or not)
25686569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     */
25690280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    void onDragExit() {
2570c6cc61d45836e4081920883cc4d448ccb0bb8417Adam Cohen        mDragEnforcer.onDragExit();
25714be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        // This can actually be called when we aren't in a drag, e.g. when adding a new
25724be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        // item to this layout via the customize drawer.
25734be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        // Guard against that case.
25744be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        if (mDragging) {
25754be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            mDragging = false;
25764be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        }
257708ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy
257808ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy        // Invalidate the drag data
2579d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        mDragCell[0] = mDragCell[1] = -1;
258008ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy        mDragOutlineAnims[mDragOutlineCurrent].animateOut();
258108ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy        mDragOutlineCurrent = (mDragOutlineCurrent + 1) % mDragOutlineAnims.length;
258219f3792523fe2d55ea791a9286398a6120920690Adam Cohen        revertTempState();
258333945b21544bc98381df17726a3537c292d8c985Michael Jurka        setIsDragOverlapping(false);
25846569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    }
25856569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
25866569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    /**
2587aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     * Mark a child as having been dropped.
2588de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy     * At the beginning of the drag operation, the child may have been on another
2589ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy     * screen, but it is re-parented before this method is called.
259031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     *
259131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param child The child that is being dropped
259231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
2593716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    void onDropChild(View child) {
2594d94533d04a5f8f5485f106d10af60169857ea899Romain Guy        if (child != null) {
2595d94533d04a5f8f5485f106d10af60169857ea899Romain Guy            LayoutParams lp = (LayoutParams) child.getLayoutParams();
259684f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy            lp.dropped = true;
2597d94533d04a5f8f5485f106d10af60169857ea899Romain Guy            child.requestLayout();
2598d94533d04a5f8f5485f106d10af60169857ea899Romain Guy        }
259931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
260031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
260131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
260231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * Computes a bounding rectangle for a range of cells
2603aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     *
260431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param cellX X coordinate of upper left corner expressed as a cell position
260531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param cellY Y coordinate of upper left corner expressed as a cell position
2606aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     * @param cellHSpan Width in cells
260731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param cellVSpan Height in cells
26086569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     * @param resultRect Rect into which to put the results
260931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
2610d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    public void cellToRect(int cellX, int cellY, int cellHSpan, int cellVSpan, Rect resultRect) {
261131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        final int cellWidth = mCellWidth;
261231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        final int cellHeight = mCellHeight;
261331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        final int widthGap = mWidthGap;
261431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        final int heightGap = mHeightGap;
2615aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
26164b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int hStartPadding = getPaddingLeft();
26174b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int vStartPadding = getPaddingTop();
2618aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
261931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int width = cellHSpan * cellWidth + ((cellHSpan - 1) * widthGap);
262031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int height = cellVSpan * cellHeight + ((cellVSpan - 1) * heightGap);
262131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
262231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int x = hStartPadding + cellX * (cellWidth + widthGap);
262331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int y = vStartPadding + cellY * (cellHeight + heightGap);
2624aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
26256569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        resultRect.set(x, y, x + width, y + height);
262631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
2627aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
262831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
2629aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     * Computes the required horizontal and vertical cell spans to always
263031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * fit the given rectangle.
2631aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     *
263231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param width Width in pixels
263331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param height Height in pixels
26348f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy     * @param result An array of length 2 in which to store the result (may be null).
263531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
26368f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy    public int[] rectToCell(int width, int height, int[] result) {
26379987a5c45e7d01a780d73b269bdce8d8a5309219Michael Jurka        return rectToCell(getResources(), width, height, result);
26389987a5c45e7d01a780d73b269bdce8d8a5309219Michael Jurka    }
26399987a5c45e7d01a780d73b269bdce8d8a5309219Michael Jurka
26409987a5c45e7d01a780d73b269bdce8d8a5309219Michael Jurka    public static int[] rectToCell(Resources resources, int width, int height, int[] result) {
264131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // Always assume we're working with the smallest span to make sure we
264231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // reserve enough space in both orientations.
264379e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato        int actualWidth = resources.getDimensionPixelSize(R.dimen.workspace_cell_width);
264479e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato        int actualHeight = resources.getDimensionPixelSize(R.dimen.workspace_cell_height);
264531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int smallerSize = Math.min(actualWidth, actualHeight);
264679e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato
264731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // Always round up to next largest cell
264854c725cc294cd43ed0650179bfae64a622547660Winson Chung        int spanX = (int) Math.ceil(width / (float) smallerSize);
264954c725cc294cd43ed0650179bfae64a622547660Winson Chung        int spanY = (int) Math.ceil(height / (float) smallerSize);
265079e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato
26518f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy        if (result == null) {
26528f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy            return new int[] { spanX, spanY };
26538f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy        }
26548f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy        result[0] = spanX;
26558f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy        result[1] = spanY;
26568f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy        return result;
265731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
265831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
2659f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka    public int[] cellSpansToSize(int hSpans, int vSpans) {
2660f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka        int[] size = new int[2];
2661f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka        size[0] = hSpans * mCellWidth + (hSpans - 1) * mWidthGap;
2662f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka        size[1] = vSpans * mCellHeight + (vSpans - 1) * mHeightGap;
2663f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka        return size;
2664f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka    }
2665f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka
266631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
2667047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy     * Calculate the grid spans needed to fit given item
2668047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy     */
2669047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy    public void calculateSpans(ItemInfo info) {
2670047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        final int minWidth;
2671047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        final int minHeight;
2672047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy
2673047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        if (info instanceof LauncherAppWidgetInfo) {
2674047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy            minWidth = ((LauncherAppWidgetInfo) info).minWidth;
2675047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy            minHeight = ((LauncherAppWidgetInfo) info).minHeight;
2676047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        } else if (info instanceof PendingAddWidgetInfo) {
2677047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy            minWidth = ((PendingAddWidgetInfo) info).minWidth;
2678047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy            minHeight = ((PendingAddWidgetInfo) info).minHeight;
2679047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        } else {
2680047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy            // It's not a widget, so it must be 1x1
2681047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy            info.spanX = info.spanY = 1;
2682047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy            return;
2683047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        }
2684047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        int[] spans = rectToCell(minWidth, minHeight, null);
2685047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        info.spanX = spans[0];
2686047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        info.spanY = spans[1];
2687047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy    }
2688047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy
2689047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy    /**
269031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * Find the first vacant cell, if there is one.
269131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     *
269231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param vacant Holds the x and y coordinate of the vacant cell
269331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param spanX Horizontal cell span.
269431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param spanY Vertical cell span.
2695aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     *
269631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @return True if a vacant cell was found
269731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
269831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public boolean getVacantCell(int[] vacant, int spanX, int spanY) {
269931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
27000280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        return findVacantCell(vacant, spanX, spanY, mCountX, mCountY, mOccupied);
270131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
270231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
270331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    static boolean findVacantCell(int[] vacant, int spanX, int spanY,
270431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            int xCount, int yCount, boolean[][] occupied) {
270531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
27062801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        for (int y = 0; y < yCount; y++) {
27072801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            for (int x = 0; x < xCount; x++) {
270831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                boolean available = !occupied[x][y];
270931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectout:            for (int i = x; i < x + spanX - 1 && x < xCount; i++) {
271031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                    for (int j = y; j < y + spanY - 1 && y < yCount; j++) {
271131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                        available = available && !occupied[i][j];
271231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                        if (!available) break out;
271331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                    }
271431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                }
271531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
271631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                if (available) {
271731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                    vacant[0] = x;
271831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                    vacant[1] = y;
271931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                    return true;
272031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                }
272131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            }
272231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
272331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
272431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        return false;
272531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
272631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
27270280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    private void clearOccupiedCells() {
27280280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        for (int x = 0; x < mCountX; x++) {
27290280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            for (int y = 0; y < mCountY; y++) {
27300280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                mOccupied[x][y] = false;
273131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            }
273231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
27330280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
273431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
2735d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    public void onMove(View view, int newCellX, int newCellY, int newSpanX, int newSpanY) {
27360280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        markCellsAsUnoccupiedForView(view);
2737482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsForView(newCellX, newCellY, newSpanX, newSpanY, mOccupied, true);
27380280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
273931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
2740d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    public void markCellsAsOccupiedForView(View view) {
2741482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsAsOccupiedForView(view, mOccupied);
2742482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2743482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public void markCellsAsOccupiedForView(View view, boolean[][] occupied) {
2744a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        if (view == null || view.getParent() != mShortcutsAndWidgets) return;
27450280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        LayoutParams lp = (LayoutParams) view.getLayoutParams();
2746482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, occupied, true);
27470280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
27480280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
2749d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    public void markCellsAsUnoccupiedForView(View view) {
2750482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsAsUnoccupiedForView(view, mOccupied);
2751482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2752482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public void markCellsAsUnoccupiedForView(View view, boolean occupied[][]) {
2753a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        if (view == null || view.getParent() != mShortcutsAndWidgets) return;
27540280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        LayoutParams lp = (LayoutParams) view.getLayoutParams();
2755482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, occupied, false);
27560280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
27570280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
2758482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private void markCellsForView(int cellX, int cellY, int spanX, int spanY, boolean[][] occupied,
2759482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            boolean value) {
2760482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (cellX < 0 || cellY < 0) return;
27610280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        for (int x = cellX; x < cellX + spanX && x < mCountX; x++) {
27620280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            for (int y = cellY; y < cellY + spanY && y < mCountY; y++) {
2763482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                occupied[x][y] = value;
276431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            }
276531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
276631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
276731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
27682801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    public int getDesiredWidth() {
27698b805b17158886035b38261eb611d8641701ae43Michael Jurka        return getPaddingLeft() + getPaddingRight() + (mCountX * mCellWidth) +
27702801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen                (Math.max((mCountX - 1), 0) * mWidthGap);
27712801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    }
27722801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
27732801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    public int getDesiredHeight()  {
27748b805b17158886035b38261eb611d8641701ae43Michael Jurka        return getPaddingTop() + getPaddingBottom() + (mCountY * mCellHeight) +
27752801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen                (Math.max((mCountY - 1), 0) * mHeightGap);
27762801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    }
27772801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
277866d72178af91d455700875635473be942bc90e54Michael Jurka    public boolean isOccupied(int x, int y) {
277966d72178af91d455700875635473be942bc90e54Michael Jurka        if (x < mCountX && y < mCountY) {
278066d72178af91d455700875635473be942bc90e54Michael Jurka            return mOccupied[x][y];
278166d72178af91d455700875635473be942bc90e54Michael Jurka        } else {
278266d72178af91d455700875635473be942bc90e54Michael Jurka            throw new RuntimeException("Position exceeds the bound of this CellLayout");
278366d72178af91d455700875635473be942bc90e54Michael Jurka        }
278466d72178af91d455700875635473be942bc90e54Michael Jurka    }
278566d72178af91d455700875635473be942bc90e54Michael Jurka
278631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
278731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
278831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        return new CellLayout.LayoutParams(getContext(), attrs);
278931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
279031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
279131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
279231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
279331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        return p instanceof CellLayout.LayoutParams;
279431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
279531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
279631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
279731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
279831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        return new CellLayout.LayoutParams(p);
279931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
280031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
2801aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung    public static class CellLayoutAnimationController extends LayoutAnimationController {
2802aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        public CellLayoutAnimationController(Animation animation, float delay) {
2803aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            super(animation, delay);
2804aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        }
2805aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
2806aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        @Override
2807aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        protected long getDelayForView(View view) {
2808aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            return (int) (Math.random() * 150);
2809aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        }
2810aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung    }
2811aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
281231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public static class LayoutParams extends ViewGroup.MarginLayoutParams {
281331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        /**
281431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         * Horizontal location of the item in the grid.
281531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         */
281631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        @ViewDebug.ExportedProperty
281731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public int cellX;
281831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
281931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        /**
282031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         * Vertical location of the item in the grid.
282131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         */
282231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        @ViewDebug.ExportedProperty
282331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public int cellY;
282431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
282531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        /**
2826482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         * Temporary horizontal location of the item in the grid during reorder
2827482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         */
2828482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        public int tmpCellX;
2829482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2830482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        /**
2831482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         * Temporary vertical location of the item in the grid during reorder
2832482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         */
2833482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        public int tmpCellY;
2834482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2835482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        /**
2836482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         * Indicates that the temporary coordinates should be used to layout the items
2837482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         */
2838482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        public boolean useTmpCoords;
2839482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2840482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        /**
284131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         * Number of cells spanned horizontally by the item.
284231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         */
284331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        @ViewDebug.ExportedProperty
284431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public int cellHSpan;
284531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
284631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        /**
284731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         * Number of cells spanned vertically by the item.
284831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         */
284931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        @ViewDebug.ExportedProperty
285031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public int cellVSpan;
2851aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
28521b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen        /**
28531b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen         * Indicates whether the item will set its x, y, width and height parameters freely,
28541b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen         * or whether these will be computed based on cellX, cellY, cellHSpan and cellVSpan.
28551b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen         */
2856d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        public boolean isLockedToGrid = true;
2857d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
2858482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        /**
2859482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         * Indicates whether this item can be reordered. Always true except in the case of the
2860482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         * the AllApps button.
2861482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         */
2862482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        public boolean canReorder = true;
2863482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
286431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // X coordinate of the view in the layout.
286531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        @ViewDebug.ExportedProperty
286631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int x;
286731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // Y coordinate of the view in the layout.
286831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        @ViewDebug.ExportedProperty
286931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int y;
287031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
287184f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy        boolean dropped;
2872fcb9e7144e58614f5ae0e9b272fb7ce040848c67Romain Guy
287331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public LayoutParams(Context c, AttributeSet attrs) {
287431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            super(c, attrs);
287531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            cellHSpan = 1;
287631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            cellVSpan = 1;
287731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
287831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
287931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public LayoutParams(ViewGroup.LayoutParams source) {
288031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            super(source);
288131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            cellHSpan = 1;
288231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            cellVSpan = 1;
288331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
2884aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
2885aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        public LayoutParams(LayoutParams source) {
2886aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            super(source);
2887aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            this.cellX = source.cellX;
2888aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            this.cellY = source.cellY;
2889aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            this.cellHSpan = source.cellHSpan;
2890aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            this.cellVSpan = source.cellVSpan;
2891aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        }
2892aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
289331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public LayoutParams(int cellX, int cellY, int cellHSpan, int cellVSpan) {
28948f19cdd62f6e2be05e3890916eabd11317ae1bc2Romain Guy            super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
289531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            this.cellX = cellX;
289631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            this.cellY = cellY;
289731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            this.cellHSpan = cellHSpan;
289831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            this.cellVSpan = cellVSpan;
289931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
290031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
29017f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public void setup(int cellWidth, int cellHeight, int widthGap, int heightGap) {
2902d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            if (isLockedToGrid) {
2903d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                final int myCellHSpan = cellHSpan;
2904d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                final int myCellVSpan = cellVSpan;
2905482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                final int myCellX = useTmpCoords ? tmpCellX : cellX;
2906482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                final int myCellY = useTmpCoords ? tmpCellY : cellY;
29071b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen
2908d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                width = myCellHSpan * cellWidth + ((myCellHSpan - 1) * widthGap) -
2909d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                        leftMargin - rightMargin;
2910d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                height = myCellVSpan * cellHeight + ((myCellVSpan - 1) * heightGap) -
2911d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                        topMargin - bottomMargin;
2912eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                x = (int) (myCellX * (cellWidth + widthGap) + leftMargin);
2913eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                y = (int) (myCellY * (cellHeight + heightGap) + topMargin);
2914d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            }
2915d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        }
2916d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
2917aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        public String toString() {
2918aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            return "(" + this.cellX + ", " + this.cellY + ")";
2919aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        }
29207f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
29217f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public void setWidth(int width) {
29227f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            this.width = width;
29237f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
29247f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
29257f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public int getWidth() {
29267f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            return width;
29277f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
29287f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
29297f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public void setHeight(int height) {
29307f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            this.height = height;
29317f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
29327f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
29337f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public int getHeight() {
29347f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            return height;
29357f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
29367f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
29377f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public void setX(int x) {
29387f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            this.x = x;
29397f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
29407f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
29417f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public int getX() {
29427f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            return x;
29437f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
29447f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
29457f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public void setY(int y) {
29467f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            this.y = y;
29477f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
29487f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
29497f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public int getY() {
29507f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            return y;
29517f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
295231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
295331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
29540280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    // This class stores info for two purposes:
29550280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    // 1. When dragging items (mDragInfo in Workspace), we store the View, its cellX & cellY,
29560280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    //    its spanX, spanY, and the screen it is on
29570280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    // 2. When long clicking on an empty cell in a CellLayout, we save information about the
29580280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    //    cellX and cellY coordinates and which page was clicked. We then set this as a tag on
29590280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    //    the CellLayout that was long clicked
2960e5fb0f27bca7afb996258a7163c76ca7390d7bffMichael Jurka    static final class CellInfo {
296131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        View cell;
2962a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka        int cellX = -1;
2963a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka        int cellY = -1;
296431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int spanX;
296531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int spanY;
296631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int screen;
29673d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        long container;
296831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
296931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        @Override
297031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public String toString() {
2971aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            return "Cell[view=" + (cell == null ? "null" : cell.getClass())
2972aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung                    + ", x=" + cellX + ", y=" + cellY + "]";
297331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
297431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
2975d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka
2976d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka    public boolean lastDownOnOccupiedCell() {
2977d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka        return mLastDownOnOccupiedCell;
2978d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka    }
297931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project}
2980