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
17325dc23624160689e59fbac708cf6f222b20d025Daniel Sandlerpackage com.android.launcher3;
1831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
194be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onoratoimport android.animation.Animator;
20629758ff081a354e43aa409159211210ee4ee85aMichael Jurkaimport android.animation.AnimatorListenerAdapter;
2150e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keelyimport android.animation.AnimatorSet;
2200397b1d9233409d9d6b233b077ae12d09768ce8Chet Haaseimport android.animation.TimeInterpolator;
23de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroyimport android.animation.ValueAnimator;
24de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroyimport android.animation.ValueAnimator.AnimatorUpdateListener;
25c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohenimport android.annotation.TargetApi;
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;
3431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.graphics.Rect;
35482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohenimport android.graphics.drawable.ColorDrawable;
366569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroyimport android.graphics.drawable.Drawable;
372805e639cdea6ae0051155611d122ed27556e658Sunny Goyalimport android.graphics.drawable.TransitionDrawable;
38c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohenimport android.os.Build;
391462de39f01cec0ba785386532719cb0207dd827Adam Cohenimport android.os.Parcelable;
40c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohenimport android.support.v4.view.ViewCompat;
4131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.util.AttributeSet;
424be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onoratoimport android.util.Log;
431462de39f01cec0ba785386532719cb0207dd827Adam Cohenimport android.util.SparseArray;
4431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.MotionEvent;
4531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.View;
4631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.ViewDebug;
4731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.ViewGroup;
48c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohenimport android.view.accessibility.AccessibilityEvent;
49150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chungimport android.view.animation.DecelerateInterpolator;
5031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
514b6eb269502d05edabf883535a7099da5862de42Sunny Goyalimport com.android.launcher3.BubbleTextView.BubbleTextShadowHandler;
52325dc23624160689e59fbac708cf6f222b20d025Daniel Sandlerimport com.android.launcher3.FolderIcon.FolderRingAnimator;
53e9b651eef1b9f3647eba94f833bff3fc52f5956bSunny Goyalimport com.android.launcher3.accessibility.DragAndDropAccessibilityDelegate;
54e9b651eef1b9f3647eba94f833bff3fc52f5956bSunny Goyalimport com.android.launcher3.accessibility.FolderAccessibilityHelper;
55e9b651eef1b9f3647eba94f833bff3fc52f5956bSunny Goyalimport com.android.launcher3.accessibility.WorkspaceAccessibilityHelper;
56091440a9cb9d4f42406631004aa484cbb79214caAdam Cohenimport com.android.launcher3.util.Thunk;
578e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy
5869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohenimport java.util.ArrayList;
59c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohenimport java.util.Arrays;
60f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohenimport java.util.Collections;
61f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohenimport java.util.Comparator;
62bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohenimport java.util.HashMap;
63d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohenimport java.util.Stack;
64c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen
654b6eb269502d05edabf883535a7099da5862de42Sunny Goyalpublic class CellLayout extends ViewGroup implements BubbleTextShadowHandler {
66e9b651eef1b9f3647eba94f833bff3fc52f5956bSunny Goyal    public static final int WORKSPACE_ACCESSIBILITY_DRAG = 2;
67e9b651eef1b9f3647eba94f833bff3fc52f5956bSunny Goyal    public static final int FOLDER_ACCESSIBILITY_DRAG = 1;
68e9b651eef1b9f3647eba94f833bff3fc52f5956bSunny Goyal
69aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung    static final String TAG = "CellLayout";
70aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
712acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen    private Launcher mLauncher;
72091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen    @Thunk int mCellWidth;
73091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen    @Thunk int mCellHeight;
7411a1a53651924b544513f1f6971a735b18d67539Winson Chung    private int mFixedCellWidth;
7511a1a53651924b544513f1f6971a735b18d67539Winson Chung    private int mFixedCellHeight;
76aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
77091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen    @Thunk int mCountX;
78091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen    @Thunk int mCountY;
7931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
80234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen    private int mOriginalWidthGap;
81234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen    private int mOriginalHeightGap;
82091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen    @Thunk int mWidthGap;
83091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen    @Thunk int mHeightGap;
844b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung    private int mMaxGap;
85917e38851cbc6caffe1f8dade4db452bace522baAdam Cohen    private boolean mDropPending = false;
86c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen    private boolean mIsDragTarget = true;
8731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
88de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy    // These are temporary variables to prevent having to allocate a new object just to
89de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy    // return an (x, y) value from helper functions. Do NOT use them to maintain other state.
90091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen    @Thunk final int[] mTmpPoint = new int[2];
912805e639cdea6ae0051155611d122ed27556e658Sunny Goyal    @Thunk final int[] mTempLocation = new int[2];
926569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
9331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    boolean[][] mOccupied;
94482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    boolean[][] mTmpOccupied;
9531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
96dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    private OnTouchListener mInterceptTouchListener;
97ef044dd380ac3abf354027750efdc16d5d48ac70Mady Mellor    private StylusEventHelper mStylusEventHelper;
98dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka
9969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen    private ArrayList<FolderRingAnimator> mFolderOuterRings = new ArrayList<FolderRingAnimator>();
100c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen    private int[] mFolderLeaveBehindCell = {-1, -1};
10169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
1025f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka    private float mBackgroundAlpha;
103f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen
1042805e639cdea6ae0051155611d122ed27556e658Sunny Goyal    private static final int BACKGROUND_ACTIVATE_DURATION = 120;
1052805e639cdea6ae0051155611d122ed27556e658Sunny Goyal    private final TransitionDrawable mBackground;
1062805e639cdea6ae0051155611d122ed27556e658Sunny Goyal
107f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen    // These values allow a fixed measurement to be set on the CellLayout.
108f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen    private int mFixedWidth = -1;
109f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen    private int mFixedHeight = -1;
110f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen
11133945b21544bc98381df17726a3537c292d8c985Michael Jurka    // If we're actively dragging something over this screen, mIsDragOverlapping is true
11233945b21544bc98381df17726a3537c292d8c985Michael Jurka    private boolean mIsDragOverlapping = false;
1136569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
114150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung    // These arrays are used to implement the drag visualization on x-large screens.
1154be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato    // They are used as circular arrays, indexed by mDragOutlineCurrent.
116091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen    @Thunk Rect[] mDragOutlines = new Rect[4];
117091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen    @Thunk float[] mDragOutlineAlphas = new float[mDragOutlines.length];
1184be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato    private InterruptibleInOutAnimator[] mDragOutlineAnims =
1194be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            new InterruptibleInOutAnimator[mDragOutlines.length];
120150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung
121150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung    // Used as an index into the above 3 arrays; indicates which is the most current value.
1224be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato    private int mDragOutlineCurrent = 0;
1238e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy    private final Paint mDragOutlinePaint = new Paint();
124150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung
1254fe5a37dda8eb1869f9328d94236eb2c23f8109cSunny Goyal    private final ClickShadowView mTouchFeedbackView;
12696864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy
127316490e636aad788fcfbfc2e04dd4f0e145bdd00Sunny Goyal    @Thunk HashMap<CellLayout.LayoutParams, Animator> mReorderAnimators = new HashMap<>();
128316490e636aad788fcfbfc2e04dd4f0e145bdd00Sunny Goyal    @Thunk HashMap<View, ReorderPreviewAnimation> mShakeAnimators = new HashMap<>();
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;
141307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen    private float mHotseatScale = 1f;
1420dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn
143fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen    public static final int MODE_SHOW_REORDER_HINT = 0;
144fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen    public static final int MODE_DRAG_OVER = 1;
145fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen    public static final int MODE_ON_DROP = 2;
146fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen    public static final int MODE_ON_DROP_EXTERNAL = 3;
147fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen    public static final int MODE_ACCEPT_DROP = 4;
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
154fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen    private static final float REORDER_PREVIEW_MAGNITUDE = 0.12f;
15519f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private static final int REORDER_ANIMATION_DURATION = 150;
156091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen    @Thunk float mReorderPreviewAnimationMagnitude;
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;
163482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1642805e639cdea6ae0051155611d122ed27556e658Sunny Goyal    private final Rect mTempRect = new Rect();
1653a6e7f330e680ef718ca7c0921d842efb4d8bbaeWinson Chung
166ca99383daef92fed673de22126875cb485be494fMichael Jurka    private final static Paint sPaint = new Paint();
1678a0bff5e35f63321178bbf777ec24d42544866b3Romain Guy
168c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen    // Related to accessible drag and drop
169e9b651eef1b9f3647eba94f833bff3fc52f5956bSunny Goyal    private DragAndDropAccessibilityDelegate mTouchHelper;
170c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen    private boolean mUseTouchHelper = false;
171c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen
17231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public CellLayout(Context context) {
17331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        this(context, null);
17431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
17531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
17631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public CellLayout(Context context, AttributeSet attrs) {
17731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        this(context, attrs, 0);
17831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
17931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
18031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public CellLayout(Context context, AttributeSet attrs, int defStyle) {
18131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        super(context, attrs, defStyle);
1826569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
1836569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        // A ViewGroup usually does not draw, but CellLayout needs to draw a rectangle to show
1846569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        // the user where a dragged item will land when dropped.
1856569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        setWillNotDraw(false);
186ce3cbd145b4222779abae32869da8dd3c2aefb67Romain Guy        setClipToPadding(false);
1872acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen        mLauncher = (Launcher) context;
188a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka
1892e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen        DeviceProfile grid = mLauncher.getDeviceProfile();
19031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CellLayout, defStyle, 0);
19131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
19211a1a53651924b544513f1f6971a735b18d67539Winson Chung        mCellWidth = mCellHeight = -1;
1935f7099af8573c2229427318acd551b92efae02a3Nilesh Agrawal        mFixedCellWidth = mFixedCellHeight = -1;
1945f8afe6280eae34620067696173e71943e1a30a3Winson Chung        mWidthGap = mOriginalWidthGap = 0;
1955f8afe6280eae34620067696173e71943e1a30a3Winson Chung        mHeightGap = mOriginalHeightGap = 0;
1965f8afe6280eae34620067696173e71943e1a30a3Winson Chung        mMaxGap = Integer.MAX_VALUE;
1972e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen        mCountX = (int) grid.inv.numColumns;
1982e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen        mCountY = (int) grid.inv.numRows;
1990280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        mOccupied = new boolean[mCountX][mCountY];
200482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        mTmpOccupied = new boolean[mCountX][mCountY];
2015b53f29f809a0dad4a1e0717ba610ce737ee0f43Adam Cohen        mPreviousReorderDirection[0] = INVALID_DIRECTION;
2025b53f29f809a0dad4a1e0717ba610ce737ee0f43Adam Cohen        mPreviousReorderDirection[1] = INVALID_DIRECTION;
20331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
20431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        a.recycle();
20531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
20631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        setAlwaysDrawnWithCacheEnabled(false);
20731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
208046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        final Resources res = getResources();
2096e1c0d34bb31cacc24c57c89ab01deaa8985814fWinson Chung        mHotseatScale = (float) grid.hotseatIconSizePx / grid.iconSizePx;
210de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy
2112805e639cdea6ae0051155611d122ed27556e658Sunny Goyal        mBackground = (TransitionDrawable) res.getDrawable(R.drawable.bg_screenpanel);
2122805e639cdea6ae0051155611d122ed27556e658Sunny Goyal        mBackground.setCallback(this);
213e8f1d047b1b788bc9884be2417e7aa0cec7e8ae8Winson Chung        mBackground.setAlpha((int) (mBackgroundAlpha * 255));
214b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung
215fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen        mReorderPreviewAnimationMagnitude = (REORDER_PREVIEW_MAGNITUDE *
2165f8afe6280eae34620067696173e71943e1a30a3Winson Chung                grid.iconSizePx);
21719f3792523fe2d55ea791a9286398a6120920690Adam Cohen
218046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        // Initialize the data structures used for the drag visualization.
219ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy        mEaseOutInterpolator = new DecelerateInterpolator(2.5f); // Quint ease out
220b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung        mDragCell[0] = mDragCell[1] = -1;
2214be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        for (int i = 0; i < mDragOutlines.length; i++) {
222d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            mDragOutlines[i] = new Rect(-1, -1, -1, -1);
223046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        }
224046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy
225046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        // When dragging things around the home screens, we show a green outline of
226046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        // where the item will land. The outlines gradually fade out, leaving a trail
227046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        // behind the drag path.
228046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        // Set up all the animations that are used to implement this fading.
229046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        final int duration = res.getInteger(R.integer.config_dragOutlineFadeTime);
230472b281d5cb4f5660df981a6c912266b9f5703feChet Haase        final float fromAlphaValue = 0;
231472b281d5cb4f5660df981a6c912266b9f5703feChet Haase        final float toAlphaValue = (float)res.getInteger(R.integer.config_dragOutlineMaxAlpha);
2324be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato
2338e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy        Arrays.fill(mDragOutlineAlphas, fromAlphaValue);
2344be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato
2354be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        for (int i = 0; i < mDragOutlineAnims.length; i++) {
236046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy            final InterruptibleInOutAnimator anim =
237f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka                new InterruptibleInOutAnimator(this, duration, fromAlphaValue, toAlphaValue);
238ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy            anim.getAnimator().setInterpolator(mEaseOutInterpolator);
239046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy            final int thisIndex = i;
240472b281d5cb4f5660df981a6c912266b9f5703feChet Haase            anim.getAnimator().addUpdateListener(new AnimatorUpdateListener() {
241de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                public void onAnimationUpdate(ValueAnimator animation) {
2424be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    final Bitmap outline = (Bitmap)anim.getTag();
2434be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato
2444be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    // If an animation is started and then stopped very quickly, we can still
2454be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    // get spurious updates we've cleared the tag. Guard against this.
2464be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    if (outline == null) {
2473a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka                        @SuppressWarnings("all") // suppress dead code warning
2483a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka                        final boolean debug = false;
2493a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka                        if (debug) {
250fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy                            Object val = animation.getAnimatedValue();
251fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy                            Log.d(TAG, "anim " + thisIndex + " update: " + val +
252fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy                                     ", isStopped " + anim.isStopped());
253fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy                        }
2544be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                        // Try to prevent it from continuing to run
2554be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                        animation.cancel();
2564be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    } else {
257472b281d5cb4f5660df981a6c912266b9f5703feChet Haase                        mDragOutlineAlphas[thisIndex] = (Float) animation.getAnimatedValue();
258d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        CellLayout.this.invalidate(mDragOutlines[thisIndex]);
2594be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    }
260de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                }
261de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy            });
2624be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            // The animation holds a reference to the drag outline bitmap as long is it's
2634be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            // running. This way the bitmap can be GCed when the animations are complete.
264472b281d5cb4f5660df981a6c912266b9f5703feChet Haase            anim.getAnimator().addListener(new AnimatorListenerAdapter() {
2653c4c20fbe682cb4b3ef94f09afe0af09171583f3Michael Jurka                @Override
2664be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                public void onAnimationEnd(Animator animation) {
267472b281d5cb4f5660df981a6c912266b9f5703feChet Haase                    if ((Float) ((ValueAnimator) animation).getAnimatedValue() == 0f) {
2684be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                        anim.setTag(null);
2694be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    }
2704be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                }
2714be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            });
2724be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            mDragOutlineAnims[i] = anim;
273de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy        }
274ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy
275a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets = new ShortcutAndWidgetContainer(context);
2762374abfda3e53f84e005df8923170308e4df8c03Adam Cohen        mShortcutsAndWidgets.setCellDimensions(mCellWidth, mCellHeight, mWidthGap, mHeightGap,
2775f8afe6280eae34620067696173e71943e1a30a3Winson Chung                mCountX, mCountY);
2782374abfda3e53f84e005df8923170308e4df8c03Adam Cohen
279ef044dd380ac3abf354027750efdc16d5d48ac70Mady Mellor        mStylusEventHelper = new StylusEventHelper(this);
280ef044dd380ac3abf354027750efdc16d5d48ac70Mady Mellor
2814fe5a37dda8eb1869f9328d94236eb2c23f8109cSunny Goyal        mTouchFeedbackView = new ClickShadowView(context);
2824fe5a37dda8eb1869f9328d94236eb2c23f8109cSunny Goyal        addView(mTouchFeedbackView);
283a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        addView(mShortcutsAndWidgets);
28418014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka    }
28518014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka
286c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
287e9b651eef1b9f3647eba94f833bff3fc52f5956bSunny Goyal    public void enableAccessibleDrag(boolean enable, int dragType) {
288c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen        mUseTouchHelper = enable;
289c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen        if (!enable) {
290c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen            ViewCompat.setAccessibilityDelegate(this, null);
291c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen            setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
292c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen            getShortcutsAndWidgets().setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
293c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen            setOnClickListener(mLauncher);
294c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen        } else {
295e9b651eef1b9f3647eba94f833bff3fc52f5956bSunny Goyal            if (dragType == WORKSPACE_ACCESSIBILITY_DRAG &&
296e9b651eef1b9f3647eba94f833bff3fc52f5956bSunny Goyal                    !(mTouchHelper instanceof WorkspaceAccessibilityHelper)) {
297e9b651eef1b9f3647eba94f833bff3fc52f5956bSunny Goyal                mTouchHelper = new WorkspaceAccessibilityHelper(this);
298e9b651eef1b9f3647eba94f833bff3fc52f5956bSunny Goyal            } else if (dragType == FOLDER_ACCESSIBILITY_DRAG &&
299e9b651eef1b9f3647eba94f833bff3fc52f5956bSunny Goyal                    !(mTouchHelper instanceof FolderAccessibilityHelper)) {
300e9b651eef1b9f3647eba94f833bff3fc52f5956bSunny Goyal                mTouchHelper = new FolderAccessibilityHelper(this);
301e9b651eef1b9f3647eba94f833bff3fc52f5956bSunny Goyal            }
302c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen            ViewCompat.setAccessibilityDelegate(this, mTouchHelper);
303c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen            setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
304c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen            getShortcutsAndWidgets().setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
305c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen            setOnClickListener(mTouchHelper);
306c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen        }
307c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen
308c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen        // Invalidate the accessibility hierarchy
309c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen        if (getParent() != null) {
310c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen            getParent().notifySubtreeAccessibilityStateChanged(
311c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen                    this, this, AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE);
312c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen        }
313c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen    }
314c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen
315c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen    @Override
316c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen    public boolean dispatchHoverEvent(MotionEvent event) {
317c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen        // Always attempt to dispatch hover events to accessibility first.
318c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen        if (mUseTouchHelper && mTouchHelper.dispatchHoverEvent(event)) {
319c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen            return true;
320c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen        }
321c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen        return super.dispatchHoverEvent(event);
322c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen    }
323c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen
324c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen    @Override
325c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen    public boolean onInterceptTouchEvent(MotionEvent ev) {
326c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen        if (mUseTouchHelper ||
327c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen                (mInterceptTouchListener != null && mInterceptTouchListener.onTouch(this, ev))) {
328c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen            return true;
329c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen        }
330c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen        return false;
331c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen    }
332c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen
333ef044dd380ac3abf354027750efdc16d5d48ac70Mady Mellor    @Override
334ef044dd380ac3abf354027750efdc16d5d48ac70Mady Mellor    public boolean onTouchEvent(MotionEvent ev) {
335ef044dd380ac3abf354027750efdc16d5d48ac70Mady Mellor        boolean handled = super.onTouchEvent(ev);
336ef044dd380ac3abf354027750efdc16d5d48ac70Mady Mellor        // Stylus button press on a home screen should not switch between overview mode and
337ef044dd380ac3abf354027750efdc16d5d48ac70Mady Mellor        // the home screen mode, however, once in overview mode stylus button press should be
338ef044dd380ac3abf354027750efdc16d5d48ac70Mady Mellor        // enabled to allow rearranging the different home screens. So check what mode
339ef044dd380ac3abf354027750efdc16d5d48ac70Mady Mellor        // the workspace is in, and only perform stylus button presses while in overview mode.
340ef044dd380ac3abf354027750efdc16d5d48ac70Mady Mellor        if (mLauncher.mWorkspace.isInOverviewMode()
341ef044dd380ac3abf354027750efdc16d5d48ac70Mady Mellor                && mStylusEventHelper.checkAndPerformStylusEvent(ev)) {
342ef044dd380ac3abf354027750efdc16d5d48ac70Mady Mellor            return true;
343ef044dd380ac3abf354027750efdc16d5d48ac70Mady Mellor        }
344ef044dd380ac3abf354027750efdc16d5d48ac70Mady Mellor        return handled;
345ef044dd380ac3abf354027750efdc16d5d48ac70Mady Mellor    }
346ef044dd380ac3abf354027750efdc16d5d48ac70Mady Mellor
34701f2d7fa4b24b21543012060305d693899b4beaaChris Craik    public void enableHardwareLayer(boolean hasLayer) {
34801f2d7fa4b24b21543012060305d693899b4beaaChris Craik        mShortcutsAndWidgets.setLayerType(hasLayer ? LAYER_TYPE_HARDWARE : LAYER_TYPE_NONE, sPaint);
349d51f33a6316c34fc69b8040946ed9a62519bb225Michael Jurka    }
350d51f33a6316c34fc69b8040946ed9a62519bb225Michael Jurka
351d51f33a6316c34fc69b8040946ed9a62519bb225Michael Jurka    public void buildHardwareLayer() {
352d51f33a6316c34fc69b8040946ed9a62519bb225Michael Jurka        mShortcutsAndWidgets.buildLayer();
3532801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    }
3542801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
355307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen    public float getChildrenScale() {
356307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        return mIsHotseat ? mHotseatScale : 1.0f;
357307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen    }
358307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen
3595f8afe6280eae34620067696173e71943e1a30a3Winson Chung    public void setCellDimensions(int width, int height) {
36011a1a53651924b544513f1f6971a735b18d67539Winson Chung        mFixedCellWidth = mCellWidth = width;
36111a1a53651924b544513f1f6971a735b18d67539Winson Chung        mFixedCellHeight = mCellHeight = height;
3625f8afe6280eae34620067696173e71943e1a30a3Winson Chung        mShortcutsAndWidgets.setCellDimensions(mCellWidth, mCellHeight, mWidthGap, mHeightGap,
3635f8afe6280eae34620067696173e71943e1a30a3Winson Chung                mCountX, mCountY);
3645f8afe6280eae34620067696173e71943e1a30a3Winson Chung    }
3655f8afe6280eae34620067696173e71943e1a30a3Winson Chung
3662801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    public void setGridSize(int x, int y) {
3672801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        mCountX = x;
3682801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        mCountY = y;
3692801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        mOccupied = new boolean[mCountX][mCountY];
370482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        mTmpOccupied = new boolean[mCountX][mCountY];
3717fbec10b36818f100b631f3d73fe1ad5360975aaAdam Cohen        mTempRectStack.clear();
3722374abfda3e53f84e005df8923170308e4df8c03Adam Cohen        mShortcutsAndWidgets.setCellDimensions(mCellWidth, mCellHeight, mWidthGap, mHeightGap,
3735f8afe6280eae34620067696173e71943e1a30a3Winson Chung                mCountX, mCountY);
37476fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        requestLayout();
3752801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    }
3762801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
3772374abfda3e53f84e005df8923170308e4df8c03Adam Cohen    // Set whether or not to invert the layout horizontally if the layout is in RTL mode.
3782374abfda3e53f84e005df8923170308e4df8c03Adam Cohen    public void setInvertIfRtl(boolean invert) {
3792374abfda3e53f84e005df8923170308e4df8c03Adam Cohen        mShortcutsAndWidgets.setInvertIfRtl(invert);
3802374abfda3e53f84e005df8923170308e4df8c03Adam Cohen    }
3812374abfda3e53f84e005df8923170308e4df8c03Adam Cohen
382917e38851cbc6caffe1f8dade4db452bace522baAdam Cohen    public void setDropPending(boolean pending) {
383917e38851cbc6caffe1f8dade4db452bace522baAdam Cohen        mDropPending = pending;
384917e38851cbc6caffe1f8dade4db452bace522baAdam Cohen    }
385917e38851cbc6caffe1f8dade4db452bace522baAdam Cohen
386917e38851cbc6caffe1f8dade4db452bace522baAdam Cohen    public boolean isDropPending() {
387917e38851cbc6caffe1f8dade4db452bace522baAdam Cohen        return mDropPending;
388917e38851cbc6caffe1f8dade4db452bace522baAdam Cohen    }
389917e38851cbc6caffe1f8dade4db452bace522baAdam Cohen
3904b6eb269502d05edabf883535a7099da5862de42Sunny Goyal    @Override
3914b6eb269502d05edabf883535a7099da5862de42Sunny Goyal    public void setPressedIcon(BubbleTextView icon, Bitmap background) {
392508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal        if (icon == null || background == null) {
393508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal            mTouchFeedbackView.setBitmap(null);
394508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal            mTouchFeedbackView.animate().cancel();
395508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal        } else {
396508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal            if (mTouchFeedbackView.setBitmap(background)) {
3974fe5a37dda8eb1869f9328d94236eb2c23f8109cSunny Goyal                mTouchFeedbackView.alignWithIconView(icon, mShortcutsAndWidgets);
3984fe5a37dda8eb1869f9328d94236eb2c23f8109cSunny Goyal                mTouchFeedbackView.animateShadow();
399508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal            }
40096864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        }
40196864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy    }
40296864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy
403c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen    void disableDragTarget() {
404c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen        mIsDragTarget = false;
405c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen    }
406c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen
407c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen    boolean isDragTarget() {
408c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen        return mIsDragTarget;
409c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen    }
410c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen
411c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen    void setIsDragOverlapping(boolean isDragOverlapping) {
412c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen        if (mIsDragOverlapping != isDragOverlapping) {
413c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen            mIsDragOverlapping = isDragOverlapping;
4142805e639cdea6ae0051155611d122ed27556e658Sunny Goyal            if (mIsDragOverlapping) {
4152805e639cdea6ae0051155611d122ed27556e658Sunny Goyal                mBackground.startTransition(BACKGROUND_ACTIVATE_DURATION);
4162805e639cdea6ae0051155611d122ed27556e658Sunny Goyal            } else {
417e8f1d047b1b788bc9884be2417e7aa0cec7e8ae8Winson Chung                if (mBackgroundAlpha > 0f) {
418e8f1d047b1b788bc9884be2417e7aa0cec7e8ae8Winson Chung                    mBackground.reverseTransition(BACKGROUND_ACTIVATE_DURATION);
419e8f1d047b1b788bc9884be2417e7aa0cec7e8ae8Winson Chung                } else {
420e8f1d047b1b788bc9884be2417e7aa0cec7e8ae8Winson Chung                    mBackground.resetTransition();
421e8f1d047b1b788bc9884be2417e7aa0cec7e8ae8Winson Chung                }
4222805e639cdea6ae0051155611d122ed27556e658Sunny Goyal            }
423c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen            invalidate();
424c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen        }
425c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen    }
426c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen
42733945b21544bc98381df17726a3537c292d8c985Michael Jurka    boolean getIsDragOverlapping() {
42833945b21544bc98381df17726a3537c292d8c985Michael Jurka        return mIsDragOverlapping;
42933945b21544bc98381df17726a3537c292d8c985Michael Jurka    }
43033945b21544bc98381df17726a3537c292d8c985Michael Jurka
431a6abce8464b57ce91e8f083951ad263370fc2da8Romain Guy    @Override
4321262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy    protected void onDraw(Canvas canvas) {
433057397714327b42c55804624cc06c7761d999f84Sunny Goyal        if (!mIsDragTarget) {
434057397714327b42c55804624cc06c7761d999f84Sunny Goyal            return;
435057397714327b42c55804624cc06c7761d999f84Sunny Goyal        }
436057397714327b42c55804624cc06c7761d999f84Sunny Goyal
4373e7c7634531302271270c8cf418abc959d621cbcMichael Jurka        // When we're large, we are either drawn in a "hover" state (ie when dragging an item to
4383e7c7634531302271270c8cf418abc959d621cbcMichael Jurka        // a neighboring page) or with just a normal background (if backgroundAlpha > 0.0f)
4393e7c7634531302271270c8cf418abc959d621cbcMichael Jurka        // When we're small, we are either drawn normally or in the "accepts drops" state (during
4403e7c7634531302271270c8cf418abc959d621cbcMichael Jurka        // a drag). However, we also drag the mini hover background *over* one of those two
4413e7c7634531302271270c8cf418abc959d621cbcMichael Jurka        // backgrounds
442057397714327b42c55804624cc06c7761d999f84Sunny Goyal        if (mBackgroundAlpha > 0.0f) {
4432805e639cdea6ae0051155611d122ed27556e658Sunny Goyal            mBackground.draw(canvas);
444a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka        }
44531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
4468e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy        final Paint paint = mDragOutlinePaint;
4474be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        for (int i = 0; i < mDragOutlines.length; i++) {
448472b281d5cb4f5660df981a6c912266b9f5703feChet Haase            final float alpha = mDragOutlineAlphas[i];
4494be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            if (alpha > 0) {
450d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                final Rect r = mDragOutlines[i];
4513a6e7f330e680ef718ca7c0921d842efb4d8bbaeWinson Chung                mTempRect.set(r);
4523a6e7f330e680ef718ca7c0921d842efb4d8bbaeWinson Chung                Utilities.scaleRectAboutCenter(mTempRect, getChildrenScale());
4534be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                final Bitmap b = (Bitmap) mDragOutlineAnims[i].getTag();
454472b281d5cb4f5660df981a6c912266b9f5703feChet Haase                paint.setAlpha((int)(alpha + .5f));
4553a6e7f330e680ef718ca7c0921d842efb4d8bbaeWinson Chung                canvas.drawBitmap(b, null, mTempRect, paint);
456150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung            }
4576569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        }
45896864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy
459482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (DEBUG_VISUALIZE_OCCUPIED) {
460482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            int[] pt = new int[2];
461482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            ColorDrawable cd = new ColorDrawable(Color.RED);
462e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen            cd.setBounds(0, 0,  mCellWidth, mCellHeight);
463482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            for (int i = 0; i < mCountX; i++) {
464482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                for (int j = 0; j < mCountY; j++) {
465482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    if (mOccupied[i][j]) {
466482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        cellToPoint(i, j, pt);
467482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        canvas.save();
468482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        canvas.translate(pt[0], pt[1]);
469482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        cd.draw(canvas);
470482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        canvas.restore();
471482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    }
472482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                }
473482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
474482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
475482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
476850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn        int previewOffset = FolderRingAnimator.sPreviewSize;
477850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn
47869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        // The folder outer / inner ring image(s)
4792e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen        DeviceProfile grid = mLauncher.getDeviceProfile();
48069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        for (int i = 0; i < mFolderOuterRings.size(); i++) {
48169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            FolderRingAnimator fra = mFolderOuterRings.get(i);
48269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
4835108bc0fd9f7e30c87c223fbb75f024e271b2103Adam Cohen            Drawable d;
4845108bc0fd9f7e30c87c223fbb75f024e271b2103Adam Cohen            int width, height;
48569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            cellToPoint(fra.mCellX, fra.mCellY, mTempLocation);
4865f8afe6280eae34620067696173e71943e1a30a3Winson Chung            View child = getChildAt(fra.mCellX, fra.mCellY);
487558f1c2ac73c3a0c3c0c316222b6b7f9c76e2501Adam Cohen
48889f9705077c054b541af7da52be832760e2ae2e8Winson Chung            if (child != null) {
489558f1c2ac73c3a0c3c0c316222b6b7f9c76e2501Adam Cohen                int centerX = mTempLocation[0] + mCellWidth / 2;
490558f1c2ac73c3a0c3c0c316222b6b7f9c76e2501Adam Cohen                int centerY = mTempLocation[1] + previewOffset / 2 +
491558f1c2ac73c3a0c3c0c316222b6b7f9c76e2501Adam Cohen                        child.getPaddingTop() + grid.folderBackgroundOffset;
492558f1c2ac73c3a0c3c0c316222b6b7f9c76e2501Adam Cohen
4935108bc0fd9f7e30c87c223fbb75f024e271b2103Adam Cohen                // Draw outer ring, if it exists
4945108bc0fd9f7e30c87c223fbb75f024e271b2103Adam Cohen                if (FolderIcon.HAS_OUTER_RING) {
4955108bc0fd9f7e30c87c223fbb75f024e271b2103Adam Cohen                    d = FolderRingAnimator.sSharedOuterRingDrawable;
4965108bc0fd9f7e30c87c223fbb75f024e271b2103Adam Cohen                    width = (int) (fra.getOuterRingSize() * getChildrenScale());
4975108bc0fd9f7e30c87c223fbb75f024e271b2103Adam Cohen                    height = width;
4985108bc0fd9f7e30c87c223fbb75f024e271b2103Adam Cohen                    canvas.save();
4995108bc0fd9f7e30c87c223fbb75f024e271b2103Adam Cohen                    canvas.translate(centerX - width / 2, centerY - height / 2);
5005108bc0fd9f7e30c87c223fbb75f024e271b2103Adam Cohen                    d.setBounds(0, 0, width, height);
5015108bc0fd9f7e30c87c223fbb75f024e271b2103Adam Cohen                    d.draw(canvas);
5025108bc0fd9f7e30c87c223fbb75f024e271b2103Adam Cohen                    canvas.restore();
5035108bc0fd9f7e30c87c223fbb75f024e271b2103Adam Cohen                }
50489f9705077c054b541af7da52be832760e2ae2e8Winson Chung
50589f9705077c054b541af7da52be832760e2ae2e8Winson Chung                // Draw inner ring
50689f9705077c054b541af7da52be832760e2ae2e8Winson Chung                d = FolderRingAnimator.sSharedInnerRingDrawable;
50789f9705077c054b541af7da52be832760e2ae2e8Winson Chung                width = (int) (fra.getInnerRingSize() * getChildrenScale());
50889f9705077c054b541af7da52be832760e2ae2e8Winson Chung                height = width;
50989f9705077c054b541af7da52be832760e2ae2e8Winson Chung                canvas.save();
51089f9705077c054b541af7da52be832760e2ae2e8Winson Chung                canvas.translate(centerX - width / 2, centerY - width / 2);
51189f9705077c054b541af7da52be832760e2ae2e8Winson Chung                d.setBounds(0, 0, width, height);
51289f9705077c054b541af7da52be832760e2ae2e8Winson Chung                d.draw(canvas);
51389f9705077c054b541af7da52be832760e2ae2e8Winson Chung                canvas.restore();
51489f9705077c054b541af7da52be832760e2ae2e8Winson Chung            }
51569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        }
516c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen
517c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        if (mFolderLeaveBehindCell[0] >= 0 && mFolderLeaveBehindCell[1] >= 0) {
518c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            Drawable d = FolderIcon.sSharedFolderLeaveBehind;
519c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            int width = d.getIntrinsicWidth();
520c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            int height = d.getIntrinsicHeight();
521c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen
522c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            cellToPoint(mFolderLeaveBehindCell[0], mFolderLeaveBehindCell[1], mTempLocation);
5235f8afe6280eae34620067696173e71943e1a30a3Winson Chung            View child = getChildAt(mFolderLeaveBehindCell[0], mFolderLeaveBehindCell[1]);
52489f9705077c054b541af7da52be832760e2ae2e8Winson Chung            if (child != null) {
52589f9705077c054b541af7da52be832760e2ae2e8Winson Chung                int centerX = mTempLocation[0] + mCellWidth / 2;
52689f9705077c054b541af7da52be832760e2ae2e8Winson Chung                int centerY = mTempLocation[1] + previewOffset / 2 +
52789f9705077c054b541af7da52be832760e2ae2e8Winson Chung                        child.getPaddingTop() + grid.folderBackgroundOffset;
52889f9705077c054b541af7da52be832760e2ae2e8Winson Chung
52989f9705077c054b541af7da52be832760e2ae2e8Winson Chung                canvas.save();
53089f9705077c054b541af7da52be832760e2ae2e8Winson Chung                canvas.translate(centerX - width / 2, centerY - width / 2);
53189f9705077c054b541af7da52be832760e2ae2e8Winson Chung                d.setBounds(0, 0, width, height);
53289f9705077c054b541af7da52be832760e2ae2e8Winson Chung                d.draw(canvas);
53389f9705077c054b541af7da52be832760e2ae2e8Winson Chung                canvas.restore();
53489f9705077c054b541af7da52be832760e2ae2e8Winson Chung            }
535c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        }
53669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen    }
53769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
53869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen    public void showFolderAccept(FolderRingAnimator fra) {
53969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        mFolderOuterRings.add(fra);
54069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen    }
54169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
54269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen    public void hideFolderAccept(FolderRingAnimator fra) {
54369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        if (mFolderOuterRings.contains(fra)) {
54469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            mFolderOuterRings.remove(fra);
54569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        }
54669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        invalidate();
5476569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    }
5486569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
549c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen    public void setFolderLeaveBehindCell(int x, int y) {
550c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        mFolderLeaveBehindCell[0] = x;
551c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        mFolderLeaveBehindCell[1] = y;
552c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        invalidate();
553c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen    }
554c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen
555c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen    public void clearFolderLeaveBehind() {
556c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        mFolderLeaveBehindCell[0] = -1;
557c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        mFolderLeaveBehindCell[1] = -1;
558c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        invalidate();
559c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen    }
560c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen
5616569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    @Override
562e6235dd225404239b55c459245543f3302326112Michael Jurka    public boolean shouldDelayChildPressedState() {
563e6235dd225404239b55c459245543f3302326112Michael Jurka        return false;
564e6235dd225404239b55c459245543f3302326112Michael Jurka    }
565e6235dd225404239b55c459245543f3302326112Michael Jurka
5661462de39f01cec0ba785386532719cb0207dd827Adam Cohen    public void restoreInstanceState(SparseArray<Parcelable> states) {
56733a152fa4958b5c0b8c4b2f3857d62809862d15fSunny Goyal        try {
56833a152fa4958b5c0b8c4b2f3857d62809862d15fSunny Goyal            dispatchRestoreInstanceState(states);
56933a152fa4958b5c0b8c4b2f3857d62809862d15fSunny Goyal        } catch (IllegalArgumentException ex) {
57033a152fa4958b5c0b8c4b2f3857d62809862d15fSunny Goyal            if (LauncherAppState.isDogfoodBuild()) {
57133a152fa4958b5c0b8c4b2f3857d62809862d15fSunny Goyal                throw ex;
57233a152fa4958b5c0b8c4b2f3857d62809862d15fSunny Goyal            }
57333a152fa4958b5c0b8c4b2f3857d62809862d15fSunny Goyal            // Mismatched viewId / viewType preventing restore. Skip restore on production builds.
57433a152fa4958b5c0b8c4b2f3857d62809862d15fSunny Goyal            Log.e(TAG, "Ignoring an error while restoring a view instance state", ex);
57533a152fa4958b5c0b8c4b2f3857d62809862d15fSunny Goyal        }
5761462de39f01cec0ba785386532719cb0207dd827Adam Cohen    }
5771462de39f01cec0ba785386532719cb0207dd827Adam Cohen
578e6235dd225404239b55c459245543f3302326112Michael Jurka    @Override
57983f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey    public void cancelLongPress() {
58083f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey        super.cancelLongPress();
58183f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey
58283f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey        // Cancel long press for all children
58383f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey        final int count = getChildCount();
58483f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey        for (int i = 0; i < count; i++) {
58583f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey            final View child = getChildAt(i);
58683f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey            child.cancelLongPress();
58783f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey        }
58883f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey    }
58983f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey
590dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    public void setOnInterceptTouchListener(View.OnTouchListener listener) {
591dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka        mInterceptTouchListener = listener;
592dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    }
593dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka
594ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song    public int getCountX() {
595d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        return mCountX;
59631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
59731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
598ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song    public int getCountY() {
599d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        return mCountY;
60031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
60131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
6020dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn    public void setIsHotseat(boolean isHotseat) {
6030dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn        mIsHotseat = isHotseat;
6045f8afe6280eae34620067696173e71943e1a30a3Winson Chung        mShortcutsAndWidgets.setIsHotseat(isHotseat);
6050dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn    }
6060dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn
607e9b651eef1b9f3647eba94f833bff3fc52f5956bSunny Goyal    public boolean isHotseat() {
608e9b651eef1b9f3647eba94f833bff3fc52f5956bSunny Goyal        return mIsHotseat;
609e9b651eef1b9f3647eba94f833bff3fc52f5956bSunny Goyal    }
610e9b651eef1b9f3647eba94f833bff3fc52f5956bSunny Goyal
6110dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn    public boolean addViewToCellLayout(View child, int index, int childId, LayoutParams params,
612f7a29e83f06909b378dba39c83a522375682710aSunny Goyal            boolean markCells) {
613aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        final LayoutParams lp = params;
614aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
615de38e42fe89fd7490221427908cd97c51da21b44Andrew Flynn        // Hotseat icons - remove text
6160dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn        if (child instanceof BubbleTextView) {
6170dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn            BubbleTextView bubbleChild = (BubbleTextView) child;
6185f8afe6280eae34620067696173e71943e1a30a3Winson Chung            bubbleChild.setTextVisibility(!mIsHotseat);
6190dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn        }
6200dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn
621307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        child.setScaleX(getChildrenScale());
622307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen        child.setScaleY(getChildrenScale());
623307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen
62431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // Generate an id for each view, this assumes we have at most 256x256 cells
62531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // per workspace screen
626d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        if (lp.cellX >= 0 && lp.cellX <= mCountX - 1 && lp.cellY >= 0 && lp.cellY <= mCountY - 1) {
627aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            // If the horizontal or vertical span is set to -1, it is taken to
628aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            // mean that it spans the extent of the CellLayout
629d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen            if (lp.cellHSpan < 0) lp.cellHSpan = mCountX;
630d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen            if (lp.cellVSpan < 0) lp.cellVSpan = mCountY;
631aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
632aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            child.setId(childId);
633f7a29e83f06909b378dba39c83a522375682710aSunny Goyal            mShortcutsAndWidgets.addView(child, index, lp);
634dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka
635f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka            if (markCells) markCellsAsOccupiedForView(child);
6360280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
637aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            return true;
638aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        }
639aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        return false;
64031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
6413e7c7634531302271270c8cf418abc959d621cbcMichael Jurka
64231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
6430280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public void removeAllViews() {
6440280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        clearOccupiedCells();
645a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.removeAllViews();
6460280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
6470280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
6480280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    @Override
6490280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public void removeAllViewsInLayout() {
650a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        if (mShortcutsAndWidgets.getChildCount() > 0) {
6517cfc2825c3a1029f962d2fc387ae2eaa85b51798Michael Jurka            clearOccupiedCells();
652a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            mShortcutsAndWidgets.removeAllViewsInLayout();
6537cfc2825c3a1029f962d2fc387ae2eaa85b51798Michael Jurka        }
6540280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
6550280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
6560280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    @Override
6570280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public void removeView(View view) {
6580280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        markCellsAsUnoccupiedForView(view);
659a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.removeView(view);
6600280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
6610280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
6620280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    @Override
6630280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public void removeViewAt(int index) {
664a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        markCellsAsUnoccupiedForView(mShortcutsAndWidgets.getChildAt(index));
665a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.removeViewAt(index);
6660280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
6670280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
6680280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    @Override
6690280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public void removeViewInLayout(View view) {
6700280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        markCellsAsUnoccupiedForView(view);
671a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.removeViewInLayout(view);
6720280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
6730280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
6740280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    @Override
6750280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public void removeViews(int start, int count) {
6760280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        for (int i = start; i < start + count; i++) {
677a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            markCellsAsUnoccupiedForView(mShortcutsAndWidgets.getChildAt(i));
6780280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        }
679a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.removeViews(start, count);
6800280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
6810280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
6820280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    @Override
6830280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public void removeViewsInLayout(int start, int count) {
6840280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        for (int i = start; i < start + count; i++) {
685a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            markCellsAsUnoccupiedForView(mShortcutsAndWidgets.getChildAt(i));
6860280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        }
687a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.removeViewsInLayout(start, count);
688abded66084680bb31cc7ea403c88f44f79a3c884Michael Jurka    }
689abded66084680bb31cc7ea403c88f44f79a3c884Michael Jurka
6906569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    /**
691aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     * Given a point, return the cell that strictly encloses that point
69231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param x X coordinate of the point
69331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param y Y coordinate of the point
69431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param result Array of 2 ints to hold the x and y coordinate of the cell
69531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
696e9b651eef1b9f3647eba94f833bff3fc52f5956bSunny Goyal    public void pointToCellExact(int x, int y, int[] result) {
6974b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int hStartPadding = getPaddingLeft();
6984b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int vStartPadding = getPaddingTop();
69931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
70031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        result[0] = (x - hStartPadding) / (mCellWidth + mWidthGap);
70131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        result[1] = (y - vStartPadding) / (mCellHeight + mHeightGap);
70231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
703d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        final int xAxis = mCountX;
704d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        final int yAxis = mCountY;
70531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
70631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        if (result[0] < 0) result[0] = 0;
70731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        if (result[0] >= xAxis) result[0] = xAxis - 1;
70831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        if (result[1] < 0) result[1] = 0;
70931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        if (result[1] >= yAxis) result[1] = yAxis - 1;
71031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
711aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
71231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
71331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * Given a point, return the cell that most closely encloses that point
71431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param x X coordinate of the point
71531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param y Y coordinate of the point
71631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param result Array of 2 ints to hold the x and y coordinate of the cell
71731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
71831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    void pointToCellRounded(int x, int y, int[] result) {
71931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        pointToCellExact(x + (mCellWidth / 2), y + (mCellHeight / 2), result);
72031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
72131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
72231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
72331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * Given a cell coordinate, return the point that represents the upper left corner of that cell
724aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     *
725aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     * @param cellX X coordinate of the cell
72631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param cellY Y coordinate of the cell
727aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     *
72831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param result Array of 2 ints to hold the x and y coordinate of the point
72931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
73031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    void cellToPoint(int cellX, int cellY, int[] result) {
7314b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int hStartPadding = getPaddingLeft();
7324b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int vStartPadding = getPaddingTop();
73331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
73431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        result[0] = hStartPadding + cellX * (mCellWidth + mWidthGap);
73531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        result[1] = vStartPadding + cellY * (mCellHeight + mHeightGap);
73631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
73731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
738e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen    /**
739482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * Given a cell coordinate, return the point that represents the center of the cell
740e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen     *
741e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen     * @param cellX X coordinate of the cell
742e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen     * @param cellY Y coordinate of the cell
743e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen     *
744e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen     * @param result Array of 2 ints to hold the x and y coordinate of the point
745e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen     */
746e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen    void cellToCenterPoint(int cellX, int cellY, int[] result) {
74747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        regionToCenterPoint(cellX, cellY, 1, 1, result);
74847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    }
74947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
75047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    /**
75147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * Given a cell coordinate and span return the point that represents the center of the regio
75247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     *
75347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param cellX X coordinate of the cell
75447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param cellY Y coordinate of the cell
75547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     *
75647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param result Array of 2 ints to hold the x and y coordinate of the point
75747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     */
75847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    void regionToCenterPoint(int cellX, int cellY, int spanX, int spanY, int[] result) {
7594b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int hStartPadding = getPaddingLeft();
7604b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int vStartPadding = getPaddingTop();
76147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        result[0] = hStartPadding + cellX * (mCellWidth + mWidthGap) +
76247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                (spanX * mCellWidth + (spanX - 1) * mWidthGap) / 2;
76347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        result[1] = vStartPadding + cellY * (mCellHeight + mHeightGap) +
76447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                (spanY * mCellHeight + (spanY - 1) * mHeightGap) / 2;
765e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen    }
766e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen
76719f3792523fe2d55ea791a9286398a6120920690Adam Cohen     /**
76819f3792523fe2d55ea791a9286398a6120920690Adam Cohen     * Given a cell coordinate and span fills out a corresponding pixel rect
76919f3792523fe2d55ea791a9286398a6120920690Adam Cohen     *
77019f3792523fe2d55ea791a9286398a6120920690Adam Cohen     * @param cellX X coordinate of the cell
77119f3792523fe2d55ea791a9286398a6120920690Adam Cohen     * @param cellY Y coordinate of the cell
77219f3792523fe2d55ea791a9286398a6120920690Adam Cohen     * @param result Rect in which to write the result
77319f3792523fe2d55ea791a9286398a6120920690Adam Cohen     */
77419f3792523fe2d55ea791a9286398a6120920690Adam Cohen     void regionToRect(int cellX, int cellY, int spanX, int spanY, Rect result) {
77519f3792523fe2d55ea791a9286398a6120920690Adam Cohen        final int hStartPadding = getPaddingLeft();
77619f3792523fe2d55ea791a9286398a6120920690Adam Cohen        final int vStartPadding = getPaddingTop();
77719f3792523fe2d55ea791a9286398a6120920690Adam Cohen        final int left = hStartPadding + cellX * (mCellWidth + mWidthGap);
77819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        final int top = vStartPadding + cellY * (mCellHeight + mHeightGap);
77919f3792523fe2d55ea791a9286398a6120920690Adam Cohen        result.set(left, top, left + (spanX * mCellWidth + (spanX - 1) * mWidthGap),
78019f3792523fe2d55ea791a9286398a6120920690Adam Cohen                top + (spanY * mCellHeight + (spanY - 1) * mHeightGap));
78119f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
78219f3792523fe2d55ea791a9286398a6120920690Adam Cohen
783482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public float getDistanceFromCell(float x, float y, int[] cell) {
784482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        cellToCenterPoint(cell[0], cell[1], mTmpPoint);
785f7a29e83f06909b378dba39c83a522375682710aSunny Goyal        return (float) Math.hypot(x - mTmpPoint[0], y - mTmpPoint[1]);
786482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
787482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
78884f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy    int getCellWidth() {
78984f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy        return mCellWidth;
79084f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy    }
79184f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy
79284f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy    int getCellHeight() {
79384f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy        return mCellHeight;
79484f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy    }
79584f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy
796d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    int getWidthGap() {
797d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        return mWidthGap;
798d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    }
799d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
800d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    int getHeightGap() {
801d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        return mHeightGap;
802d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    }
803d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
804f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen    public void setFixedSize(int width, int height) {
805f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen        mFixedWidth = width;
806f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen        mFixedHeight = height;
807f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen    }
808f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen
80931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
81031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
8115f8afe6280eae34620067696173e71943e1a30a3Winson Chung        int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
81231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
8135f8afe6280eae34620067696173e71943e1a30a3Winson Chung        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
8145f8afe6280eae34620067696173e71943e1a30a3Winson Chung        int heightSize =  MeasureSpec.getSize(heightMeasureSpec);
8152d75f125f4e8bb5358dfdb63096d0493488ac2e5Winson Chung        int childWidthSize = widthSize - (getPaddingLeft() + getPaddingRight());
8162d75f125f4e8bb5358dfdb63096d0493488ac2e5Winson Chung        int childHeightSize = heightSize - (getPaddingTop() + getPaddingBottom());
81711a1a53651924b544513f1f6971a735b18d67539Winson Chung        if (mFixedCellWidth < 0 || mFixedCellHeight < 0) {
818c6205603efe1f2987caf96504c87d720a25b5a94Sunny Goyal            int cw = DeviceProfile.calculateCellWidth(childWidthSize, mCountX);
819c6205603efe1f2987caf96504c87d720a25b5a94Sunny Goyal            int ch = DeviceProfile.calculateCellHeight(childHeightSize, mCountY);
82011a1a53651924b544513f1f6971a735b18d67539Winson Chung            if (cw != mCellWidth || ch != mCellHeight) {
82111a1a53651924b544513f1f6971a735b18d67539Winson Chung                mCellWidth = cw;
82211a1a53651924b544513f1f6971a735b18d67539Winson Chung                mCellHeight = ch;
82311a1a53651924b544513f1f6971a735b18d67539Winson Chung                mShortcutsAndWidgets.setCellDimensions(mCellWidth, mCellHeight, mWidthGap,
82411a1a53651924b544513f1f6971a735b18d67539Winson Chung                        mHeightGap, mCountX, mCountY);
82511a1a53651924b544513f1f6971a735b18d67539Winson Chung            }
8265f8afe6280eae34620067696173e71943e1a30a3Winson Chung        }
827aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
8282d75f125f4e8bb5358dfdb63096d0493488ac2e5Winson Chung        int newWidth = childWidthSize;
8292d75f125f4e8bb5358dfdb63096d0493488ac2e5Winson Chung        int newHeight = childHeightSize;
830f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen        if (mFixedWidth > 0 && mFixedHeight > 0) {
831f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen            newWidth = mFixedWidth;
832f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen            newHeight = mFixedHeight;
833f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen        } else if (widthSpecMode == MeasureSpec.UNSPECIFIED || heightSpecMode == MeasureSpec.UNSPECIFIED) {
83431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            throw new RuntimeException("CellLayout cannot have UNSPECIFIED dimensions");
83531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
83631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
837d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        int numWidthGaps = mCountX - 1;
838d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        int numHeightGaps = mCountY - 1;
839d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen
840234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen        if (mOriginalWidthGap < 0 || mOriginalHeightGap < 0) {
8412d75f125f4e8bb5358dfdb63096d0493488ac2e5Winson Chung            int hSpace = childWidthSize;
8422d75f125f4e8bb5358dfdb63096d0493488ac2e5Winson Chung            int vSpace = childHeightSize;
843f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            int hFreeSpace = hSpace - (mCountX * mCellWidth);
844f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            int vFreeSpace = vSpace - (mCountY * mCellHeight);
8454b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung            mWidthGap = Math.min(mMaxGap, numWidthGaps > 0 ? (hFreeSpace / numWidthGaps) : 0);
8464b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung            mHeightGap = Math.min(mMaxGap,numHeightGaps > 0 ? (vFreeSpace / numHeightGaps) : 0);
8475f8afe6280eae34620067696173e71943e1a30a3Winson Chung            mShortcutsAndWidgets.setCellDimensions(mCellWidth, mCellHeight, mWidthGap,
8485f8afe6280eae34620067696173e71943e1a30a3Winson Chung                    mHeightGap, mCountX, mCountY);
849234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen        } else {
850234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen            mWidthGap = mOriginalWidthGap;
851234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen            mHeightGap = mOriginalHeightGap;
852ece7f5b3b55cab646941123e03589241a61678e2Winson Chung        }
8534fe5a37dda8eb1869f9328d94236eb2c23f8109cSunny Goyal
8544fe5a37dda8eb1869f9328d94236eb2c23f8109cSunny Goyal        // Make the feedback view large enough to hold the blur bitmap.
8554fe5a37dda8eb1869f9328d94236eb2c23f8109cSunny Goyal        mTouchFeedbackView.measure(
8564fe5a37dda8eb1869f9328d94236eb2c23f8109cSunny Goyal                MeasureSpec.makeMeasureSpec(mCellWidth + mTouchFeedbackView.getExtraSize(),
8574fe5a37dda8eb1869f9328d94236eb2c23f8109cSunny Goyal                        MeasureSpec.EXACTLY),
8584fe5a37dda8eb1869f9328d94236eb2c23f8109cSunny Goyal                MeasureSpec.makeMeasureSpec(mCellHeight + mTouchFeedbackView.getExtraSize(),
8594fe5a37dda8eb1869f9328d94236eb2c23f8109cSunny Goyal                        MeasureSpec.EXACTLY));
8604fe5a37dda8eb1869f9328d94236eb2c23f8109cSunny Goyal
8614fe5a37dda8eb1869f9328d94236eb2c23f8109cSunny Goyal        mShortcutsAndWidgets.measure(
8624fe5a37dda8eb1869f9328d94236eb2c23f8109cSunny Goyal                MeasureSpec.makeMeasureSpec(newWidth, MeasureSpec.EXACTLY),
8634fe5a37dda8eb1869f9328d94236eb2c23f8109cSunny Goyal                MeasureSpec.makeMeasureSpec(newHeight, MeasureSpec.EXACTLY));
8644fe5a37dda8eb1869f9328d94236eb2c23f8109cSunny Goyal
8654fe5a37dda8eb1869f9328d94236eb2c23f8109cSunny Goyal        int maxWidth = mShortcutsAndWidgets.getMeasuredWidth();
8664fe5a37dda8eb1869f9328d94236eb2c23f8109cSunny Goyal        int maxHeight = mShortcutsAndWidgets.getMeasuredHeight();
8672d75f125f4e8bb5358dfdb63096d0493488ac2e5Winson Chung        if (mFixedWidth > 0 && mFixedHeight > 0) {
8682d75f125f4e8bb5358dfdb63096d0493488ac2e5Winson Chung            setMeasuredDimension(maxWidth, maxHeight);
8692d75f125f4e8bb5358dfdb63096d0493488ac2e5Winson Chung        } else {
8702d75f125f4e8bb5358dfdb63096d0493488ac2e5Winson Chung            setMeasuredDimension(widthSize, heightSize);
8712d75f125f4e8bb5358dfdb63096d0493488ac2e5Winson Chung        }
87231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
87331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
87431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
87528750fba6a2d141eb9a1e566718c17236030b815Michael Jurka    protected void onLayout(boolean changed, int l, int t, int r, int b) {
87638848ca3a9527e62eef1816770d25e7382cc4e4eWinson Chung        int offset = getMeasuredWidth() - getPaddingLeft() - getPaddingRight() -
87738848ca3a9527e62eef1816770d25e7382cc4e4eWinson Chung                (mCountX * mCellWidth);
87838848ca3a9527e62eef1816770d25e7382cc4e4eWinson Chung        int left = getPaddingLeft() + (int) Math.ceil(offset / 2f);
87938848ca3a9527e62eef1816770d25e7382cc4e4eWinson Chung        int top = getPaddingTop();
8804fe5a37dda8eb1869f9328d94236eb2c23f8109cSunny Goyal
8814fe5a37dda8eb1869f9328d94236eb2c23f8109cSunny Goyal        mTouchFeedbackView.layout(left, top,
8824fe5a37dda8eb1869f9328d94236eb2c23f8109cSunny Goyal                left + mTouchFeedbackView.getMeasuredWidth(),
8834fe5a37dda8eb1869f9328d94236eb2c23f8109cSunny Goyal                top + mTouchFeedbackView.getMeasuredHeight());
8844fe5a37dda8eb1869f9328d94236eb2c23f8109cSunny Goyal        mShortcutsAndWidgets.layout(left, top,
8854fe5a37dda8eb1869f9328d94236eb2c23f8109cSunny Goyal                left + r - l,
8864fe5a37dda8eb1869f9328d94236eb2c23f8109cSunny Goyal                top + b - t);
88731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
88831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
88931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
890dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
891dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka        super.onSizeChanged(w, h, oldw, oldh);
89282a9bd2c03645494cb0965abc03a9a18823e07e5Winson Chung
89382a9bd2c03645494cb0965abc03a9a18823e07e5Winson Chung        // Expand the background drawing bounds by the padding baked into the background drawable
8942805e639cdea6ae0051155611d122ed27556e658Sunny Goyal        mBackground.getPadding(mTempRect);
8952805e639cdea6ae0051155611d122ed27556e658Sunny Goyal        mBackground.setBounds(-mTempRect.left, -mTempRect.top,
8962805e639cdea6ae0051155611d122ed27556e658Sunny Goyal                w + mTempRect.right, h + mTempRect.bottom);
897dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    }
898dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka
899dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    @Override
90031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    protected void setChildrenDrawingCacheEnabled(boolean enabled) {
901a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.setChildrenDrawingCacheEnabled(enabled);
90231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
90331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
90431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
90531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    protected void setChildrenDrawnWithCacheEnabled(boolean enabled) {
906a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.setChildrenDrawnWithCacheEnabled(enabled);
90731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
90831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
9095f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka    public float getBackgroundAlpha() {
9105f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka        return mBackgroundAlpha;
911dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    }
912dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka
9135f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka    public void setBackgroundAlpha(float alpha) {
914afaa05014e0bf3ed1192f9ddec2af4283bc50248Michael Jurka        if (mBackgroundAlpha != alpha) {
915afaa05014e0bf3ed1192f9ddec2af4283bc50248Michael Jurka            mBackgroundAlpha = alpha;
9162805e639cdea6ae0051155611d122ed27556e658Sunny Goyal            mBackground.setAlpha((int) (mBackgroundAlpha * 255));
917afaa05014e0bf3ed1192f9ddec2af4283bc50248Michael Jurka        }
918dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    }
919dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka
9202805e639cdea6ae0051155611d122ed27556e658Sunny Goyal    @Override
9212805e639cdea6ae0051155611d122ed27556e658Sunny Goyal    protected boolean verifyDrawable(Drawable who) {
9222805e639cdea6ae0051155611d122ed27556e658Sunny Goyal        return super.verifyDrawable(who) || (mIsDragTarget && who == mBackground);
9232805e639cdea6ae0051155611d122ed27556e658Sunny Goyal    }
9242805e639cdea6ae0051155611d122ed27556e658Sunny Goyal
925a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka    public void setShortcutAndWidgetAlpha(float alpha) {
92602b508110484906118c277368d570a707604ec9cSunny Goyal        mShortcutsAndWidgets.setAlpha(alpha);
927dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    }
928dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka
929a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka    public ShortcutAndWidgetContainer getShortcutsAndWidgets() {
930dcbcc86353e9ed52daac87f292aece667cd0ac71Sunny Goyal        return mShortcutsAndWidgets;
931a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka    }
932a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka
933440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy    public View getChildAt(int x, int y) {
934a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        return mShortcutsAndWidgets.getChildAt(x, y);
935440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy    }
936440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy
93776fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    public boolean animateChildToPosition(final View child, int cellX, int cellY, int duration,
938482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            int delay, boolean permanent, boolean adjustOccupied) {
939a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        ShortcutAndWidgetContainer clc = getShortcutsAndWidgets();
940482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        boolean[][] occupied = mOccupied;
941482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (!permanent) {
942482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            occupied = mTmpOccupied;
943482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
944482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
94519f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if (clc.indexOfChild(child) != -1) {
946bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
947bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            final ItemInfo info = (ItemInfo) child.getTag();
948bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen
949bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            // We cancel any existing animations
950bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            if (mReorderAnimators.containsKey(lp)) {
951bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                mReorderAnimators.get(lp).cancel();
952bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                mReorderAnimators.remove(lp);
953bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            }
954bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen
955482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            final int oldX = lp.x;
956482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            final int oldY = lp.y;
957482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (adjustOccupied) {
958482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                occupied[lp.cellX][lp.cellY] = false;
959482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                occupied[cellX][cellY] = true;
960482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
961bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            lp.isLockedToGrid = true;
962482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (permanent) {
963482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                lp.cellX = info.cellX = cellX;
964482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                lp.cellY = info.cellY = cellY;
965482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            } else {
966482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                lp.tmpCellX = cellX;
967482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                lp.tmpCellY = cellY;
968482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
969bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            clc.setupLp(lp);
970bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            lp.isLockedToGrid = false;
971482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            final int newX = lp.x;
972482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            final int newY = lp.y;
973bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen
97476fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen            lp.x = oldX;
97576fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen            lp.y = oldY;
97676fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
977482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            // Exit early if we're not actually moving the view
978482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (oldX == newX && oldY == newY) {
979482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                lp.isLockedToGrid = true;
980482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                return true;
981482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
982482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
983f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka            ValueAnimator va = LauncherAnimUtils.ofFloat(child, 0f, 1f);
984482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            va.setDuration(duration);
985482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            mReorderAnimators.put(lp, va);
986482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
987482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            va.addUpdateListener(new AnimatorUpdateListener() {
988482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                @Override
989bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                public void onAnimationUpdate(ValueAnimator animation) {
990482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    float r = ((Float) animation.getAnimatedValue()).floatValue();
99119f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    lp.x = (int) ((1 - r) * oldX + r * newX);
99219f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    lp.y = (int) ((1 - r) * oldY + r * newY);
9936b8a02d63a5d9cab8209381993e37db6a6afb753Adam Cohen                    child.requestLayout();
994bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                }
995bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            });
996482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            va.addListener(new AnimatorListenerAdapter() {
997bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                boolean cancelled = false;
998bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                public void onAnimationEnd(Animator animation) {
999bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    // If the animation was cancelled, it means that another animation
1000bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    // has interrupted this one, and we don't want to lock the item into
1001bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    // place just yet.
1002bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    if (!cancelled) {
1003bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                        lp.isLockedToGrid = true;
1004482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        child.requestLayout();
1005bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    }
1006bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    if (mReorderAnimators.containsKey(lp)) {
1007bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                        mReorderAnimators.remove(lp);
1008bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    }
1009bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                }
1010bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                public void onAnimationCancel(Animator animation) {
1011bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    cancelled = true;
1012bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                }
1013bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            });
1014482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            va.setStartDelay(delay);
1015482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            va.start();
1016bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            return true;
1017bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        }
1018bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        return false;
1019bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    }
1020bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen
1021482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    void visualizeDropLocation(View v, Bitmap dragOutline, int originX, int originY, int cellX,
1022482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            int cellY, int spanX, int spanY, boolean resize, Point dragOffset, Rect dragRegion) {
102308ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy        final int oldDragCellX = mDragCell[0];
102408ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy        final int oldDragCellY = mDragCell[1];
1025482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
10262801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        if (dragOutline == null && v == null) {
10272801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            return;
10282801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        }
10292801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
1030482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (cellX != oldDragCellX || cellY != oldDragCellY) {
1031482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            mDragCell[0] = cellX;
1032482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            mDragCell[1] = cellY;
10336569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy            // Find the top left corner of the rect the object will occupy
1034de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy            final int[] topLeft = mTmpPoint;
1035482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            cellToPoint(cellX, cellY, topLeft);
1036de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy
10374be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            int left = topLeft[0];
10384be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            int top = topLeft[1];
10396569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
1040b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung            if (v != null && dragOffset == null) {
104199e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                // When drawing the drag outline, it did not account for margin offsets
104299e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                // added by the view's parent.
104399e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                MarginLayoutParams lp = (MarginLayoutParams) v.getLayoutParams();
104499e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                left += lp.leftMargin;
104599e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                top += lp.topMargin;
104699e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen
104799e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                // Offsets due to the size difference between the View and the dragOutline.
104899e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                // There is a size difference to account for the outer blur, which may lie
104999e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                // outside the bounds of the view.
1050a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung                top += (v.getHeight() - dragOutline.getHeight()) / 2;
1051ae915cecd36af4973061a1cb0b58c5be1be699a0Adam Cohen                // We center about the x axis
1052ae915cecd36af4973061a1cb0b58c5be1be699a0Adam Cohen                left += ((mCellWidth * spanX) + ((spanX - 1) * mWidthGap)
1053ae915cecd36af4973061a1cb0b58c5be1be699a0Adam Cohen                        - dragOutline.getWidth()) / 2;
10546639687cd67bab1aeef2a75e5c6bc458b20dc082Adam Cohen            } else {
1055b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                if (dragOffset != null && dragRegion != null) {
1056b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                    // Center the drag region *horizontally* in the cell and apply a drag
1057b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                    // outline offset
1058b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                    left += dragOffset.x + ((mCellWidth * spanX) + ((spanX - 1) * mWidthGap)
1059b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                             - dragRegion.width()) / 2;
106069737c3e49ff3edc42899609fdbc96e356f8638eWinson Chung                    int cHeight = getShortcutsAndWidgets().getCellContentHeight();
106169737c3e49ff3edc42899609fdbc96e356f8638eWinson Chung                    int cellPaddingY = (int) Math.max(0, ((mCellHeight - cHeight) / 2f));
106269737c3e49ff3edc42899609fdbc96e356f8638eWinson Chung                    top += dragOffset.y + cellPaddingY;
1063b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                } else {
1064b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                    // Center the drag outline in the cell
1065b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                    left += ((mCellWidth * spanX) + ((spanX - 1) * mWidthGap)
1066b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                            - dragOutline.getWidth()) / 2;
1067b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                    top += ((mCellHeight * spanY) + ((spanY - 1) * mHeightGap)
1068b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                            - dragOutline.getHeight()) / 2;
1069b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                }
1070a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung            }
10714be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            final int oldIndex = mDragOutlineCurrent;
107208ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy            mDragOutlineAnims[oldIndex].animateOut();
107308ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy            mDragOutlineCurrent = (oldIndex + 1) % mDragOutlines.length;
1074d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            Rect r = mDragOutlines[mDragOutlineCurrent];
1075d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            r.set(left, top, left + dragOutline.getWidth(), top + dragOutline.getHeight());
1076d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            if (resize) {
1077482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                cellToRect(cellX, cellY, spanX, spanY, r);
1078d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            }
1079150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung
108008ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy            mDragOutlineAnims[mDragOutlineCurrent].setTag(dragOutline);
108108ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy            mDragOutlineAnims[mDragOutlineCurrent].animateIn();
10826569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        }
10836569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    }
10846569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
1085e0310965022e7a1adb7ad489505d404186608689Adam Cohen    public void clearDragOutlines() {
1086e0310965022e7a1adb7ad489505d404186608689Adam Cohen        final int oldIndex = mDragOutlineCurrent;
1087e0310965022e7a1adb7ad489505d404186608689Adam Cohen        mDragOutlineAnims[oldIndex].animateOut();
1088d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        mDragCell[0] = mDragCell[1] = -1;
1089e0310965022e7a1adb7ad489505d404186608689Adam Cohen    }
1090e0310965022e7a1adb7ad489505d404186608689Adam Cohen
109131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
109270864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey     * Find a vacant area that will fit the given bounds nearest the requested
109370864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey     * cell location. Uses Euclidean distance to score multiple vacant areas.
1094aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     *
109551afc022fa76c79f0d1ece470ddc126c08fea8a4Romain Guy     * @param pixelX The X location at which you want to search for a vacant area.
109651afc022fa76c79f0d1ece470ddc126c08fea8a4Romain Guy     * @param pixelY The Y location at which you want to search for a vacant area.
109770864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey     * @param spanX Horizontal span of the object.
109870864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey     * @param spanY Vertical span of the object.
1099de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy     * @param result Array in which to place the result, or null (in which case a new array will
1100de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy     *        be allocated)
110170864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey     * @return The X, Y cell of a vacant area that can contain this object,
110270864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey     *         nearest the requested location.
110331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
1104f7a29e83f06909b378dba39c83a522375682710aSunny Goyal    int[] findNearestVacantArea(int pixelX, int pixelY, int spanX, int spanY, int[] result) {
1105f7a29e83f06909b378dba39c83a522375682710aSunny Goyal        return findNearestVacantArea(pixelX, pixelY, spanX, spanY, spanX, spanY, result, null);
11066a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka    }
1107aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
11086a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka    /**
11096a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     * Find a vacant area that will fit the given bounds nearest the requested
11106a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     * cell location. Uses Euclidean distance to score multiple vacant areas.
11116a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     *
11126a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     * @param pixelX The X location at which you want to search for a vacant area.
11136a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     * @param pixelY The Y location at which you want to search for a vacant area.
1114d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param minSpanX The minimum horizontal span required
1115d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param minSpanY The minimum vertical span required
1116d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param spanX Horizontal span of the object.
1117d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param spanY Vertical span of the object.
1118d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param result Array in which to place the result, or null (in which case a new array will
1119d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *        be allocated)
1120d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @return The X, Y cell of a vacant area that can contain this object,
1121d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *         nearest the requested location.
1122d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     */
1123d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    int[] findNearestVacantArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX,
1124d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            int spanY, int[] result, int[] resultSpan) {
1125f7a29e83f06909b378dba39c83a522375682710aSunny Goyal        return findNearestArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, true,
1126d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                result, resultSpan);
1127d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    }
1128d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen
1129d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    private final Stack<Rect> mTempRectStack = new Stack<Rect>();
1130d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    private void lazyInitTempRectStack() {
1131d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        if (mTempRectStack.isEmpty()) {
1132d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            for (int i = 0; i < mCountX * mCountY; i++) {
1133d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                mTempRectStack.push(new Rect());
1134d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            }
1135d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        }
1136d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    }
1137482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1138d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    private void recycleTempRects(Stack<Rect> used) {
1139d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        while (!used.isEmpty()) {
1140d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            mTempRectStack.push(used.pop());
1141d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        }
1142d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    }
1143d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen
1144d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    /**
1145d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * Find a vacant area that will fit the given bounds nearest the requested
1146d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * cell location. Uses Euclidean distance to score multiple vacant areas.
1147d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *
1148d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param pixelX The X location at which you want to search for a vacant area.
1149d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param pixelY The Y location at which you want to search for a vacant area.
1150d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param minSpanX The minimum horizontal span required
1151d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param minSpanY The minimum vertical span required
1152d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param spanX Horizontal span of the object.
1153d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param spanY Vertical span of the object.
1154d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param ignoreOccupied If true, the result can be an occupied cell
1155d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param result Array in which to place the result, or null (in which case a new array will
1156d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *        be allocated)
1157d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @return The X, Y cell of a vacant area that can contain this object,
1158d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *         nearest the requested location.
1159d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     */
1160f7a29e83f06909b378dba39c83a522375682710aSunny Goyal    private int[] findNearestArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX,
1161f7a29e83f06909b378dba39c83a522375682710aSunny Goyal            int spanY, boolean ignoreOccupied, int[] result, int[] resultSpan) {
1162d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        lazyInitTempRectStack();
1163c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka
1164e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        // For items with a spanX / spanY > 1, the passed in point (pixelX, pixelY) corresponds
1165e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        // to the center of the item, but we are searching based on the top-left cell, so
1166e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        // we translate the point over to correspond to the top-left.
1167e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        pixelX -= (mCellWidth + mWidthGap) * (spanX - 1) / 2f;
1168e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        pixelY -= (mCellHeight + mHeightGap) * (spanY - 1) / 2f;
1169e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen
117070864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey        // Keep track of best-scoring drop area
1171de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy        final int[] bestXY = result != null ? result : new int[2];
117270864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey        double bestDistance = Double.MAX_VALUE;
1173d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        final Rect bestRect = new Rect(-1, -1, -1, -1);
1174d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        final Stack<Rect> validRegions = new Stack<Rect>();
1175aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
1176de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy        final int countX = mCountX;
1177de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy        final int countY = mCountY;
1178de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy
1179d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        if (minSpanX <= 0 || minSpanY <= 0 || spanX <= 0 || spanY <= 0 ||
1180d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                spanX < minSpanX || spanY < minSpanY) {
1181d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            return bestXY;
1182d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        }
1183d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen
1184d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        for (int y = 0; y < countY - (minSpanY - 1); y++) {
1185c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka            inner:
1186d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            for (int x = 0; x < countX - (minSpanX - 1); x++) {
1187d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                int ySize = -1;
1188d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                int xSize = -1;
1189df0353815c629fc678824b07a234b89a1ff94208Adam Cohen                if (ignoreOccupied) {
1190d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    // First, let's see if this thing fits anywhere
1191d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    for (int i = 0; i < minSpanX; i++) {
1192d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        for (int j = 0; j < minSpanY; j++) {
1193f7a29e83f06909b378dba39c83a522375682710aSunny Goyal                            if (mOccupied[x + i][y + j]) {
1194df0353815c629fc678824b07a234b89a1ff94208Adam Cohen                                continue inner;
1195df0353815c629fc678824b07a234b89a1ff94208Adam Cohen                            }
1196c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                        }
1197c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                    }
1198d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    xSize = minSpanX;
1199d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    ySize = minSpanY;
1200d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen
1201d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    // We know that the item will fit at _some_ acceptable size, now let's see
1202d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    // how big we can make it. We'll alternate between incrementing x and y spans
1203d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    // until we hit a limit.
1204d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    boolean incX = true;
1205d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    boolean hitMaxX = xSize >= spanX;
1206d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    boolean hitMaxY = ySize >= spanY;
1207d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    while (!(hitMaxX && hitMaxY)) {
1208d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        if (incX && !hitMaxX) {
1209d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            for (int j = 0; j < ySize; j++) {
1210f7a29e83f06909b378dba39c83a522375682710aSunny Goyal                                if (x + xSize > countX -1 || mOccupied[x + xSize][y + j]) {
1211d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                    // We can't move out horizontally
1212d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                    hitMaxX = true;
1213d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                }
1214d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            }
1215d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            if (!hitMaxX) {
1216d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                xSize++;
1217d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            }
1218d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        } else if (!hitMaxY) {
1219d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            for (int i = 0; i < xSize; i++) {
1220f7a29e83f06909b378dba39c83a522375682710aSunny Goyal                                if (y + ySize > countY - 1 || mOccupied[x + i][y + ySize]) {
1221d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                    // We can't move out vertically
1222d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                    hitMaxY = true;
1223d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                }
1224d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            }
1225d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            if (!hitMaxY) {
1226d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                ySize++;
1227d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            }
1228d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        }
1229d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        hitMaxX |= xSize >= spanX;
1230d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        hitMaxY |= ySize >= spanY;
1231d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        incX = !incX;
1232d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    }
1233d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    incX = true;
1234d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    hitMaxX = xSize >= spanX;
1235d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    hitMaxY = ySize >= spanY;
1236c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                }
12372805e639cdea6ae0051155611d122ed27556e658Sunny Goyal                final int[] cellXY = mTmpPoint;
1238e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen                cellToCenterPoint(x, y, cellXY);
1239c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka
1240d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                // We verify that the current rect is not a sub-rect of any of our previous
1241d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                // candidates. In this case, the current rect is disqualified in favour of the
1242d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                // containing rect.
1243d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                Rect currentRect = mTempRectStack.pop();
1244d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                currentRect.set(x, y, x + xSize, y + ySize);
1245d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                boolean contained = false;
1246d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                for (Rect r : validRegions) {
1247d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    if (r.contains(currentRect)) {
1248d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        contained = true;
1249d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        break;
1250d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    }
1251d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                }
1252d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                validRegions.push(currentRect);
1253f7a29e83f06909b378dba39c83a522375682710aSunny Goyal                double distance = Math.hypot(cellXY[0] - pixelX,  cellXY[1] - pixelY);
1254482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1255d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                if ((distance <= bestDistance && !contained) ||
1256d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        currentRect.contains(bestRect)) {
1257c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                    bestDistance = distance;
1258c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                    bestXY[0] = x;
1259c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                    bestXY[1] = y;
1260d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    if (resultSpan != null) {
1261d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        resultSpan[0] = xSize;
1262d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        resultSpan[1] = ySize;
1263d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    }
1264d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    bestRect.set(currentRect);
1265c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                }
126631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            }
126731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
126831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
1269c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        // Return -1, -1 if no suitable location found
1270c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        if (bestDistance == Double.MAX_VALUE) {
1271c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            bestXY[0] = -1;
1272c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            bestXY[1] = -1;
127370864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey        }
1274d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        recycleTempRects(validRegions);
1275c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        return bestXY;
127631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
1277aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
1278482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     /**
1279482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * Find a vacant area that will fit the given bounds nearest the requested
1280482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * cell location, and will also weigh in a suggested direction vector of the
1281482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * desired location. This method computers distance based on unit grid distances,
1282482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * not pixel distances.
1283482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     *
128447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param cellX The X cell nearest to which you want to search for a vacant area.
128547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param cellY The Y cell nearest which you want to search for a vacant area.
1286482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * @param spanX Horizontal span of the object.
1287482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * @param spanY Vertical span of the object.
128847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param direction The favored direction in which the views should move from x, y
128947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param exactDirectionOnly If this parameter is true, then only solutions where the direction
129047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     *        matches exactly. Otherwise we find the best matching direction.
129147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param occoupied The array which represents which cells in the CellLayout are occupied
129247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param blockOccupied The array which represents which cells in the specified block (cellX,
12935f8afe6280eae34620067696173e71943e1a30a3Winson Chung     *        cellY, spanX, spanY) are occupied. This is used when try to move a group of views.
1294482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * @param result Array in which to place the result, or null (in which case a new array will
1295482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     *        be allocated)
1296482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * @return The X, Y cell of a vacant area that can contain this object,
1297482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     *         nearest the requested location.
1298482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     */
1299482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private int[] findNearestArea(int cellX, int cellY, int spanX, int spanY, int[] direction,
130047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            boolean[][] occupied, boolean blockOccupied[][], int[] result) {
1301482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // Keep track of best-scoring drop area
1302482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        final int[] bestXY = result != null ? result : new int[2];
1303482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        float bestDistance = Float.MAX_VALUE;
1304482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        int bestDirectionScore = Integer.MIN_VALUE;
1305482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1306482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        final int countX = mCountX;
1307482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        final int countY = mCountY;
1308482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1309482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int y = 0; y < countY - (spanY - 1); y++) {
1310482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            inner:
1311482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            for (int x = 0; x < countX - (spanX - 1); x++) {
1312482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                // First, let's see if this thing fits anywhere
1313482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                for (int i = 0; i < spanX; i++) {
1314482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    for (int j = 0; j < spanY; j++) {
131547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        if (occupied[x + i][y + j] && (blockOccupied == null || blockOccupied[i][j])) {
1316482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                            continue inner;
1317482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        }
1318482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    }
1319482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                }
1320482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1321f7a29e83f06909b378dba39c83a522375682710aSunny Goyal                float distance = (float) Math.hypot(x - cellX, y - cellY);
1322482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                int[] curDirection = mTmpPoint;
132347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                computeDirectionVector(x - cellX, y - cellY, curDirection);
132447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                // The direction score is just the dot product of the two candidate direction
132547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                // and that passed in.
1326482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                int curDirectionScore = direction[0] * curDirection[0] +
1327482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        direction[1] * curDirection[1];
132847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                boolean exactDirectionOnly = false;
132947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                boolean directionMatches = direction[0] == curDirection[0] &&
133047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        direction[0] == curDirection[0];
133147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                if ((directionMatches || !exactDirectionOnly) &&
133247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        Float.compare(distance,  bestDistance) < 0 || (Float.compare(distance,
1333482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        bestDistance) == 0 && curDirectionScore > bestDirectionScore)) {
1334482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    bestDistance = distance;
1335482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    bestDirectionScore = curDirectionScore;
1336482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    bestXY[0] = x;
1337482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    bestXY[1] = y;
1338482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                }
1339482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1340482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1341482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1342482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // Return -1, -1 if no suitable location found
1343482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (bestDistance == Float.MAX_VALUE) {
1344482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            bestXY[0] = -1;
1345482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            bestXY[1] = -1;
1346482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1347482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return bestXY;
1348482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1349482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1350482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private boolean addViewToTempLocation(View v, Rect rectOccupiedByPotentialDrop,
13518baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            int[] direction, ItemConfiguration currentState) {
13528baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        CellAndSpan c = currentState.map.get(v);
1353482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        boolean success = false;
13548baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, false);
1355482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsForRect(rectOccupiedByPotentialDrop, mTmpOccupied, true);
1356482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
13578baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        findNearestArea(c.x, c.y, c.spanX, c.spanY, direction, mTmpOccupied, null, mTempLocation);
1358482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1359482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (mTempLocation[0] >= 0 && mTempLocation[1] >= 0) {
13608baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            c.x = mTempLocation[0];
13618baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            c.y = mTempLocation[1];
1362482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            success = true;
1363482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
13648baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, true);
1365482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return success;
1366482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1367482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1368f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen    /**
1369f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen     * This helper class defines a cluster of views. It helps with defining complex edges
1370f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen     * of the cluster and determining how those edges interact with other views. The edges
1371f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen     * essentially define a fine-grained boundary around the cluster of views -- like a more
1372f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen     * precise version of a bounding box.
1373f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen     */
1374f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen    private class ViewCluster {
1375f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        final static int LEFT = 0;
1376f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        final static int TOP = 1;
1377f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        final static int RIGHT = 2;
1378f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        final static int BOTTOM = 3;
1379f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen
1380f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        ArrayList<View> views;
1381f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        ItemConfiguration config;
1382f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        Rect boundingRect = new Rect();
1383f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen
1384f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        int[] leftEdge = new int[mCountY];
1385f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        int[] rightEdge = new int[mCountY];
1386f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        int[] topEdge = new int[mCountX];
1387f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        int[] bottomEdge = new int[mCountX];
1388f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        boolean leftEdgeDirty, rightEdgeDirty, topEdgeDirty, bottomEdgeDirty, boundingRectDirty;
138947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
1390f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        @SuppressWarnings("unchecked")
1391f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        public ViewCluster(ArrayList<View> views, ItemConfiguration config) {
1392f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            this.views = (ArrayList<View>) views.clone();
1393f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            this.config = config;
1394f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            resetEdges();
1395f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        }
139647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
1397f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        void resetEdges() {
1398f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            for (int i = 0; i < mCountX; i++) {
1399f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                topEdge[i] = -1;
1400f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                bottomEdge[i] = -1;
1401f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            }
1402f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            for (int i = 0; i < mCountY; i++) {
1403f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                leftEdge[i] = -1;
1404f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                rightEdge[i] = -1;
1405f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            }
1406f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            leftEdgeDirty = true;
1407f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            rightEdgeDirty = true;
1408f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            bottomEdgeDirty = true;
1409f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            topEdgeDirty = true;
1410f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            boundingRectDirty = true;
1411f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        }
1412f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen
1413f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        void computeEdge(int which, int[] edge) {
1414f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            int count = views.size();
1415f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            for (int i = 0; i < count; i++) {
1416f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                CellAndSpan cs = config.map.get(views.get(i));
1417f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                switch (which) {
1418f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                    case LEFT:
1419f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                        int left = cs.x;
1420f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                        for (int j = cs.y; j < cs.y + cs.spanY; j++) {
1421f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                            if (left < edge[j] || edge[j] < 0) {
1422f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                                edge[j] = left;
1423f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                            }
1424f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                        }
1425f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                        break;
1426f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                    case RIGHT:
1427f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                        int right = cs.x + cs.spanX;
1428f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                        for (int j = cs.y; j < cs.y + cs.spanY; j++) {
1429f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                            if (right > edge[j]) {
1430f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                                edge[j] = right;
1431f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                            }
1432f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                        }
1433f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                        break;
1434f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                    case TOP:
1435f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                        int top = cs.y;
1436f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                        for (int j = cs.x; j < cs.x + cs.spanX; j++) {
1437f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                            if (top < edge[j] || edge[j] < 0) {
1438f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                                edge[j] = top;
1439f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                            }
1440f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                        }
1441f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                        break;
1442f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                    case BOTTOM:
1443f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                        int bottom = cs.y + cs.spanY;
1444f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                        for (int j = cs.x; j < cs.x + cs.spanX; j++) {
1445f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                            if (bottom > edge[j]) {
1446f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                                edge[j] = bottom;
1447f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                            }
1448f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                        }
1449f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                        break;
1450f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                }
1451f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            }
145247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
145347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
1454f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        boolean isViewTouchingEdge(View v, int whichEdge) {
1455f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            CellAndSpan cs = config.map.get(v);
145647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
1457f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            int[] edge = getEdge(whichEdge);
1458f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen
1459f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            switch (whichEdge) {
1460f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                case LEFT:
1461f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                    for (int i = cs.y; i < cs.y + cs.spanY; i++) {
1462f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                        if (edge[i] == cs.x + cs.spanX) {
1463f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                            return true;
146447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        }
146547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    }
1466f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                    break;
1467f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                case RIGHT:
1468f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                    for (int i = cs.y; i < cs.y + cs.spanY; i++) {
1469f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                        if (edge[i] == cs.x) {
1470f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                            return true;
1471f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                        }
1472f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                    }
1473f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                    break;
1474f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                case TOP:
1475f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                    for (int i = cs.x; i < cs.x + cs.spanX; i++) {
1476f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                        if (edge[i] == cs.y + cs.spanY) {
1477f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                            return true;
1478f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                        }
1479f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                    }
1480f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                    break;
1481f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                case BOTTOM:
1482f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                    for (int i = cs.x; i < cs.x + cs.spanX; i++) {
1483f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                        if (edge[i] == cs.y) {
1484f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                            return true;
1485f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                        }
1486f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                    }
1487f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                    break;
1488f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            }
1489f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            return false;
1490f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        }
1491f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen
1492f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        void shift(int whichEdge, int delta) {
1493f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            for (View v: views) {
1494f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                CellAndSpan c = config.map.get(v);
1495f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                switch (whichEdge) {
1496f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                    case LEFT:
1497f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                        c.x -= delta;
1498f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                        break;
1499f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                    case RIGHT:
1500f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                        c.x += delta;
1501f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                        break;
1502f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                    case TOP:
1503f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                        c.y -= delta;
1504f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                        break;
1505f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                    case BOTTOM:
1506f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                    default:
1507f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                        c.y += delta;
1508f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                        break;
1509f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                }
1510f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            }
1511f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            resetEdges();
1512f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        }
1513f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen
1514f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        public void addView(View v) {
1515f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            views.add(v);
1516f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            resetEdges();
1517f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        }
1518f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen
1519f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        public Rect getBoundingRect() {
1520f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            if (boundingRectDirty) {
1521f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                boolean first = true;
1522f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                for (View v: views) {
1523f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                    CellAndSpan c = config.map.get(v);
1524f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                    if (first) {
1525f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                        boundingRect.set(c.x, c.y, c.x + c.spanX, c.y + c.spanY);
1526f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                        first = false;
1527f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                    } else {
1528a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen                        boundingRect.union(c.x, c.y, c.x + c.spanX, c.y + c.spanY);
1529a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen                    }
153047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                }
153147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            }
1532f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            return boundingRect;
1533f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        }
1534f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen
1535f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        public int[] getEdge(int which) {
1536f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            switch (which) {
1537f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                case LEFT:
1538f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                    return getLeftEdge();
1539f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                case RIGHT:
1540f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                    return getRightEdge();
1541f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                case TOP:
1542f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                    return getTopEdge();
1543f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                case BOTTOM:
1544f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                default:
1545f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                    return getBottomEdge();
1546f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            }
1547f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        }
1548f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen
1549f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        public int[] getLeftEdge() {
1550f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            if (leftEdgeDirty) {
1551f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                computeEdge(LEFT, leftEdge);
1552f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            }
1553f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            return leftEdge;
1554f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        }
1555f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen
1556f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        public int[] getRightEdge() {
1557f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            if (rightEdgeDirty) {
1558f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                computeEdge(RIGHT, rightEdge);
1559f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            }
1560f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            return rightEdge;
1561f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        }
1562f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen
1563f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        public int[] getTopEdge() {
1564f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            if (topEdgeDirty) {
1565f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                computeEdge(TOP, topEdge);
1566f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            }
1567f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            return topEdge;
1568f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        }
1569f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen
1570f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        public int[] getBottomEdge() {
1571f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            if (bottomEdgeDirty) {
1572f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                computeEdge(BOTTOM, bottomEdge);
1573f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            }
1574f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            return bottomEdge;
1575f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        }
1576f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen
1577f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        PositionComparator comparator = new PositionComparator();
1578f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        class PositionComparator implements Comparator<View> {
1579f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            int whichEdge = 0;
1580f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            public int compare(View left, View right) {
1581f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                CellAndSpan l = config.map.get(left);
1582f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                CellAndSpan r = config.map.get(right);
1583f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                switch (whichEdge) {
1584f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                    case LEFT:
1585f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                        return (r.x + r.spanX) - (l.x + l.spanX);
1586f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                    case RIGHT:
1587f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                        return l.x - r.x;
1588f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                    case TOP:
1589f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                        return (r.y + r.spanY) - (l.y + l.spanY);
1590f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                    case BOTTOM:
1591f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                    default:
1592f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                        return l.y - r.y;
1593f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                }
1594f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            }
1595f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        }
1596f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen
1597f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        public void sortConfigurationForEdgePush(int edge) {
1598f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            comparator.whichEdge = edge;
1599f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            Collections.sort(config.sortedViews, comparator);
160047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
160147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    }
160247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
1603f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen    private boolean pushViewsToTempLocation(ArrayList<View> views, Rect rectOccupiedByPotentialDrop,
1604f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            int[] direction, View dragView, ItemConfiguration currentState) {
1605f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen
1606f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        ViewCluster cluster = new ViewCluster(views, currentState);
1607f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        Rect clusterRect = cluster.getBoundingRect();
1608f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        int whichEdge;
1609f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        int pushDistance;
1610f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        boolean fail = false;
1611e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen
1612f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        // Determine the edge of the cluster that will be leading the push and how far
1613f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        // the cluster must be shifted.
1614f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        if (direction[0] < 0) {
1615f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            whichEdge = ViewCluster.LEFT;
1616f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            pushDistance = clusterRect.right - rectOccupiedByPotentialDrop.left;
1617e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen        } else if (direction[0] > 0) {
1618f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            whichEdge = ViewCluster.RIGHT;
1619f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            pushDistance = rectOccupiedByPotentialDrop.right - clusterRect.left;
1620f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        } else if (direction[1] < 0) {
1621f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            whichEdge = ViewCluster.TOP;
1622f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            pushDistance = clusterRect.bottom - rectOccupiedByPotentialDrop.top;
1623f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        } else {
1624f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            whichEdge = ViewCluster.BOTTOM;
1625f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            pushDistance = rectOccupiedByPotentialDrop.bottom - clusterRect.top;
1626f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        }
1627f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen
1628f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        // Break early for invalid push distance.
1629f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        if (pushDistance <= 0) {
1630f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            return false;
1631f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        }
1632f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen
1633f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        // Mark the occupied state as false for the group of views we want to move.
1634f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        for (View v: views) {
1635f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            CellAndSpan c = currentState.map.get(v);
1636f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, false);
1637f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        }
1638f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen
1639f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        // We save the current configuration -- if we fail to find a solution we will revert
1640f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        // to the initial state. The process of finding a solution modifies the configuration
1641f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        // in place, hence the need for revert in the failure case.
1642f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        currentState.save();
1643f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen
1644f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        // The pushing algorithm is simplified by considering the views in the order in which
1645f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        // they would be pushed by the cluster. For example, if the cluster is leading with its
1646f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        // left edge, we consider sort the views by their right edge, from right to left.
1647f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        cluster.sortConfigurationForEdgePush(whichEdge);
1648f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen
1649f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        while (pushDistance > 0 && !fail) {
1650f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            for (View v: currentState.sortedViews) {
1651f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                // For each view that isn't in the cluster, we see if the leading edge of the
1652f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                // cluster is contacting the edge of that view. If so, we add that view to the
1653f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                // cluster.
1654f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                if (!cluster.views.contains(v) && v != dragView) {
1655f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                    if (cluster.isViewTouchingEdge(v, whichEdge)) {
1656f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                        LayoutParams lp = (LayoutParams) v.getLayoutParams();
1657f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                        if (!lp.canReorder) {
1658f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                            // The push solution includes the all apps button, this is not viable.
1659f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                            fail = true;
1660f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                            break;
1661f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                        }
1662f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                        cluster.addView(v);
1663f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                        CellAndSpan c = currentState.map.get(v);
1664f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen
1665f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                        // Adding view to cluster, mark it as not occupied.
1666f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                        markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, false);
1667f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                    }
1668f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                }
1669f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            }
1670f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            pushDistance--;
1671f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen
1672f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            // The cluster has been completed, now we move the whole thing over in the appropriate
1673f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            // direction.
1674f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            cluster.shift(whichEdge, 1);
1675e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen        }
1676e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen
1677f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        boolean foundSolution = false;
1678f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        clusterRect = cluster.getBoundingRect();
1679f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen
1680f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        // Due to the nature of the algorithm, the only check required to verify a valid solution
1681f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        // is to ensure that completed shifted cluster lies completely within the cell layout.
1682f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        if (!fail && clusterRect.left >= 0 && clusterRect.right <= mCountX && clusterRect.top >= 0 &&
1683f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                clusterRect.bottom <= mCountY) {
1684f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            foundSolution = true;
1685f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        } else {
1686f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            currentState.restore();
1687f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        }
1688e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen
1689f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        // In either case, we set the occupied array as marked for the location of the views
1690f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        for (View v: cluster.views) {
1691f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            CellAndSpan c = currentState.map.get(v);
1692f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, true);
1693e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen        }
1694f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen
1695f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        return foundSolution;
1696e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen    }
1697e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen
16988baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen    private boolean addViewsToTempLocation(ArrayList<View> views, Rect rectOccupiedByPotentialDrop,
1699f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            int[] direction, View dragView, ItemConfiguration currentState) {
170047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        if (views.size() == 0) return true;
170147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
170247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        boolean success = false;
170347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        Rect boundingRect = null;
17048baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // We construct a rect which represents the entire group of views passed in
170547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        for (View v: views) {
17068baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = currentState.map.get(v);
170747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            if (boundingRect == null) {
17088baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                boundingRect = new Rect(c.x, c.y, c.x + c.spanX, c.y + c.spanY);
170947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            } else {
17108baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                boundingRect.union(c.x, c.y, c.x + c.spanX, c.y + c.spanY);
171147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            }
171247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
171347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
17148baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // Mark the occupied state as false for the group of views we want to move.
1715f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        for (View v: views) {
17168baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = currentState.map.get(v);
17178baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, false);
171847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
171947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
172047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        boolean[][] blockOccupied = new boolean[boundingRect.width()][boundingRect.height()];
172147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        int top = boundingRect.top;
172247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        int left = boundingRect.left;
17238baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // We mark more precisely which parts of the bounding rect are truly occupied, allowing
1724a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen        // for interlocking.
1725f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        for (View v: views) {
17268baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = currentState.map.get(v);
17278baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            markCellsForView(c.x - left, c.y - top, c.spanX, c.spanY, blockOccupied, true);
172847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
172947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
173047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        markCellsForRect(rectOccupiedByPotentialDrop, mTmpOccupied, true);
173147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
1732f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        findNearestArea(boundingRect.left, boundingRect.top, boundingRect.width(),
1733f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                boundingRect.height(), direction, mTmpOccupied, blockOccupied, mTempLocation);
173447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
17358baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // If we successfuly found a location by pushing the block of views, we commit it
173647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        if (mTempLocation[0] >= 0 && mTempLocation[1] >= 0) {
17378baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            int deltaX = mTempLocation[0] - boundingRect.left;
17388baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            int deltaY = mTempLocation[1] - boundingRect.top;
1739f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            for (View v: views) {
17408baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                CellAndSpan c = currentState.map.get(v);
17418baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                c.x += deltaX;
17428baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                c.y += deltaY;
174347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            }
174447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            success = true;
174547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
1746482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
17478baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // In either case, we set the occupied array as marked for the location of the views
1748f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        for (View v: views) {
17498baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = currentState.map.get(v);
17508baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, true);
1751482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1752482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return success;
1753482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1754482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1755482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private void markCellsForRect(Rect r, boolean[][] occupied, boolean value) {
1756482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsForView(r.left, r.top, r.width(), r.height(), occupied, value);
1757482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1758482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
17594abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen    // This method tries to find a reordering solution which satisfies the push mechanic by trying
17604abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen    // to push items in each of the cardinal directions, in an order based on the direction vector
17614abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen    // passed.
17624abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen    private boolean attemptPushInDirection(ArrayList<View> intersectingViews, Rect occupied,
17634abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            int[] direction, View ignoreView, ItemConfiguration solution) {
17644abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen        if ((Math.abs(direction[0]) + Math.abs(direction[1])) > 1) {
17655f8afe6280eae34620067696173e71943e1a30a3Winson Chung            // If the direction vector has two non-zero components, we try pushing
17664abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            // separately in each of the components.
17674abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            int temp = direction[1];
17684abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            direction[1] = 0;
1769f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen
1770f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            if (pushViewsToTempLocation(intersectingViews, occupied, direction,
17714abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen                    ignoreView, solution)) {
17724abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen                return true;
17734abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            }
17744abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            direction[1] = temp;
17754abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            temp = direction[0];
17764abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            direction[0] = 0;
1777f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen
1778f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            if (pushViewsToTempLocation(intersectingViews, occupied, direction,
17794abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen                    ignoreView, solution)) {
17804abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen                return true;
17814abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            }
17824abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            // Revert the direction
17834abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            direction[0] = temp;
17844abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen
17854abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            // Now we try pushing in each component of the opposite direction
17864abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            direction[0] *= -1;
17874abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            direction[1] *= -1;
17884abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            temp = direction[1];
17894abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            direction[1] = 0;
1790f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            if (pushViewsToTempLocation(intersectingViews, occupied, direction,
17914abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen                    ignoreView, solution)) {
17924abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen                return true;
17934abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            }
17944abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen
17954abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            direction[1] = temp;
17964abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            temp = direction[0];
17974abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            direction[0] = 0;
1798f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            if (pushViewsToTempLocation(intersectingViews, occupied, direction,
17994abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen                    ignoreView, solution)) {
18004abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen                return true;
18014abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            }
18024abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            // revert the direction
18034abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            direction[0] = temp;
18044abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            direction[0] *= -1;
18054abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            direction[1] *= -1;
18065f8afe6280eae34620067696173e71943e1a30a3Winson Chung
18074abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen        } else {
18084abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            // If the direction vector has a single non-zero component, we push first in the
18094abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            // direction of the vector
1810f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            if (pushViewsToTempLocation(intersectingViews, occupied, direction,
18114abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen                    ignoreView, solution)) {
18124abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen                return true;
18134abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            }
18144abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            // Then we try the opposite direction
18154abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            direction[0] *= -1;
18164abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            direction[1] *= -1;
1817f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            if (pushViewsToTempLocation(intersectingViews, occupied, direction,
18184abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen                    ignoreView, solution)) {
18194abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen                return true;
18204abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            }
18214abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            // Switch the direction back
18224abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            direction[0] *= -1;
18234abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            direction[1] *= -1;
18245f8afe6280eae34620067696173e71943e1a30a3Winson Chung
18255f8afe6280eae34620067696173e71943e1a30a3Winson Chung            // If we have failed to find a push solution with the above, then we try
18264abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            // to find a solution by pushing along the perpendicular axis.
18274abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen
18284abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            // Swap the components
18294abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            int temp = direction[1];
18304abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            direction[1] = direction[0];
18314abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            direction[0] = temp;
1832f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            if (pushViewsToTempLocation(intersectingViews, occupied, direction,
18334abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen                    ignoreView, solution)) {
18344abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen                return true;
18354abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            }
18364abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen
18374abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            // Then we try the opposite direction
18384abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            direction[0] *= -1;
18394abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            direction[1] *= -1;
1840f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            if (pushViewsToTempLocation(intersectingViews, occupied, direction,
18414abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen                    ignoreView, solution)) {
18424abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen                return true;
18434abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            }
18444abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            // Switch the direction back
18454abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            direction[0] *= -1;
18464abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            direction[1] *= -1;
18474abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen
18484abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            // Swap the components back
18494abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            temp = direction[1];
18504abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            direction[1] = direction[0];
18514abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen            direction[0] = temp;
18524abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen        }
18534abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen        return false;
18544abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen    }
18554abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen
1856482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private boolean rearrangementExists(int cellX, int cellY, int spanX, int spanY, int[] direction,
18578baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            View ignoreView, ItemConfiguration solution) {
1858e3e03bcd313ba8060f2832b6a16dea6fd6d532eaWinson Chung        // Return early if get invalid cell positions
1859e3e03bcd313ba8060f2832b6a16dea6fd6d532eaWinson Chung        if (cellX < 0 || cellY < 0) return false;
1860482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
18618baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        mIntersectingViews.clear();
1862482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        mOccupiedRect.set(cellX, cellY, cellX + spanX, cellY + spanY);
1863482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
18648baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // Mark the desired location of the view currently being dragged.
1865482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (ignoreView != null) {
18668baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = solution.map.get(ignoreView);
186719f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (c != null) {
186819f3792523fe2d55ea791a9286398a6120920690Adam Cohen                c.x = cellX;
186919f3792523fe2d55ea791a9286398a6120920690Adam Cohen                c.y = cellY;
187019f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
1871482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1872482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        Rect r0 = new Rect(cellX, cellY, cellX + spanX, cellY + spanY);
1873482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        Rect r1 = new Rect();
18748baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        for (View child: solution.map.keySet()) {
1875482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (child == ignoreView) continue;
18768baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = solution.map.get(child);
1877482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
18788baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            r1.set(c.x, c.y, c.x + c.spanX, c.y + c.spanY);
1879482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (Rect.intersects(r0, r1)) {
1880482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                if (!lp.canReorder) {
1881482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    return false;
1882482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                }
1883482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                mIntersectingViews.add(child);
1884482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1885482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
188647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
1887fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen        solution.intersectingViews = new ArrayList<View>(mIntersectingViews);
1888fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen
18895f8afe6280eae34620067696173e71943e1a30a3Winson Chung        // First we try to find a solution which respects the push mechanic. That is,
18904abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen        // we try to find a solution such that no displaced item travels through another item
18914abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen        // without also displacing that item.
18924abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen        if (attemptPushInDirection(mIntersectingViews, mOccupiedRect, direction, ignoreView,
189319f3792523fe2d55ea791a9286398a6120920690Adam Cohen                solution)) {
189447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            return true;
189547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
189647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
18974abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen        // Next we try moving the views as a block, but without requiring the push mechanic.
1898f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        if (addViewsToTempLocation(mIntersectingViews, mOccupiedRect, direction, ignoreView,
189919f3792523fe2d55ea791a9286398a6120920690Adam Cohen                solution)) {
1900482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            return true;
1901482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
190247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
1903482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // Ok, they couldn't move as a block, let's move them individually
1904482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (View v : mIntersectingViews) {
19058baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            if (!addViewToTempLocation(v, mOccupiedRect, direction, solution)) {
1906482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                return false;
1907482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1908482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1909482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return true;
1910482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1911482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1912482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    /*
1913482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * Returns a pair (x, y), where x,y are in {-1, 0, 1} corresponding to vector between
1914482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * the provided point and the provided cell
1915482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     */
191647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    private void computeDirectionVector(float deltaX, float deltaY, int[] result) {
1917482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        double angle = Math.atan(((float) deltaY) / deltaX);
1918482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1919482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        result[0] = 0;
1920482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        result[1] = 0;
1921482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (Math.abs(Math.cos(angle)) > 0.5f) {
1922482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            result[0] = (int) Math.signum(deltaX);
1923482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1924482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (Math.abs(Math.sin(angle)) > 0.5f) {
1925482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            result[1] = (int) Math.signum(deltaY);
1926482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1927482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1928482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
19298baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen    private void copyOccupiedArray(boolean[][] occupied) {
19308baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        for (int i = 0; i < mCountX; i++) {
19318baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            for (int j = 0; j < mCountY; j++) {
19328baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                occupied[i][j] = mOccupied[i][j];
19338baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            }
19348baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        }
19358baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen    }
19368baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen
1937f7a29e83f06909b378dba39c83a522375682710aSunny Goyal    private ItemConfiguration findReorderSolution(int pixelX, int pixelY, int minSpanX, int minSpanY,
1938fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen            int spanX, int spanY, int[] direction, View dragView, boolean decX,
1939fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen            ItemConfiguration solution) {
19408baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // Copy the current state into the solution. This solution will be manipulated as necessary.
19418baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        copyCurrentStateToSolution(solution, false);
19428baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // Copy the current occupied array into the temporary occupied array. This array will be
19438baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // manipulated as necessary to find a solution.
19448baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        copyOccupiedArray(mTmpOccupied);
1945482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1946482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // We find the nearest cell into which we would place the dragged item, assuming there's
1947482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // nothing in its way.
1948482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        int result[] = new int[2];
1949482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        result = findNearestArea(pixelX, pixelY, spanX, spanY, result);
1950482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1951482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        boolean success = false;
1952482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // First we try the exact nearest position of the item being dragged,
1953482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // we will then want to try to move this around to other neighbouring positions
19548baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        success = rearrangementExists(result[0], result[1], spanX, spanY, direction, dragView,
19558baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                solution);
1956482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1957482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (!success) {
1958482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            // We try shrinking the widget down to size in an alternating pattern, shrink 1 in
1959482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            // x, then 1 in y etc.
1960482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (spanX > minSpanX && (minSpanY == spanY || decX)) {
1961fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen                return findReorderSolution(pixelX, pixelY, minSpanX, minSpanY, spanX - 1, spanY,
1962fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen                        direction, dragView, false, solution);
1963482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            } else if (spanY > minSpanY) {
1964fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen                return findReorderSolution(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY - 1,
1965fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen                        direction, dragView, true, solution);
1966482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1967482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.isSolution = false;
1968482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        } else {
1969482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.isSolution = true;
1970482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewX = result[0];
1971482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewY = result[1];
1972482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewSpanX = spanX;
1973482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewSpanY = spanY;
1974482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1975482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return solution;
1976482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1977482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1978482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private void copyCurrentStateToSolution(ItemConfiguration solution, boolean temp) {
1979a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        int childCount = mShortcutsAndWidgets.getChildCount();
1980482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < childCount; i++) {
1981a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            View child = mShortcutsAndWidgets.getChildAt(i);
1982482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
19838baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c;
1984482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (temp) {
19858baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                c = new CellAndSpan(lp.tmpCellX, lp.tmpCellY, lp.cellHSpan, lp.cellVSpan);
1986482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            } else {
19878baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                c = new CellAndSpan(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan);
1988482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1989f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            solution.add(child, c);
1990482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1991482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1992482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1993482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private void copySolutionToTempState(ItemConfiguration solution, View dragView) {
1994482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < mCountX; i++) {
1995482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            for (int j = 0; j < mCountY; j++) {
1996482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                mTmpOccupied[i][j] = false;
1997482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1998482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1999482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2000a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        int childCount = mShortcutsAndWidgets.getChildCount();
2001482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < childCount; i++) {
2002a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            View child = mShortcutsAndWidgets.getChildAt(i);
2003482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (child == dragView) continue;
2004482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
20058baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = solution.map.get(child);
20068baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            if (c != null) {
20078baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                lp.tmpCellX = c.x;
20088baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                lp.tmpCellY = c.y;
20098baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                lp.cellHSpan = c.spanX;
20108baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                lp.cellVSpan = c.spanY;
20118baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, true);
2012482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
2013482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2014482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsForView(solution.dragViewX, solution.dragViewY, solution.dragViewSpanX,
2015482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                solution.dragViewSpanY, mTmpOccupied, true);
2016482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2017482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2018482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private void animateItemsToSolution(ItemConfiguration solution, View dragView, boolean
2019482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            commitDragView) {
2020482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2021482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        boolean[][] occupied = DESTRUCTIVE_REORDER ? mOccupied : mTmpOccupied;
2022482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < mCountX; i++) {
2023482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            for (int j = 0; j < mCountY; j++) {
2024482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                occupied[i][j] = false;
2025482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
2026482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2027482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2028a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        int childCount = mShortcutsAndWidgets.getChildCount();
2029482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < childCount; i++) {
2030a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            View child = mShortcutsAndWidgets.getChildAt(i);
2031482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (child == dragView) continue;
20328baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = solution.map.get(child);
20338baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            if (c != null) {
203419f3792523fe2d55ea791a9286398a6120920690Adam Cohen                animateChildToPosition(child, c.x, c.y, REORDER_ANIMATION_DURATION, 0,
203519f3792523fe2d55ea791a9286398a6120920690Adam Cohen                        DESTRUCTIVE_REORDER, false);
20368baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                markCellsForView(c.x, c.y, c.spanX, c.spanY, occupied, true);
2037482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
2038482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2039482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (commitDragView) {
2040482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            markCellsForView(solution.dragViewX, solution.dragViewY, solution.dragViewSpanX,
2041482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    solution.dragViewSpanY, occupied, true);
2042482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2043482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2044482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2045fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen
2046fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen    // This method starts or changes the reorder preview animations
2047fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen    private void beginOrAdjustReorderPreviewAnimations(ItemConfiguration solution,
2048fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen            View dragView, int delay, int mode) {
204919f3792523fe2d55ea791a9286398a6120920690Adam Cohen        int childCount = mShortcutsAndWidgets.getChildCount();
205019f3792523fe2d55ea791a9286398a6120920690Adam Cohen        for (int i = 0; i < childCount; i++) {
205119f3792523fe2d55ea791a9286398a6120920690Adam Cohen            View child = mShortcutsAndWidgets.getChildAt(i);
205219f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (child == dragView) continue;
205319f3792523fe2d55ea791a9286398a6120920690Adam Cohen            CellAndSpan c = solution.map.get(child);
2054fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen            boolean skip = mode == ReorderPreviewAnimation.MODE_HINT && solution.intersectingViews
2055fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen                    != null && !solution.intersectingViews.contains(child);
2056fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen
205719f3792523fe2d55ea791a9286398a6120920690Adam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
2058fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen            if (c != null && !skip) {
2059fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen                ReorderPreviewAnimation rha = new ReorderPreviewAnimation(child, mode, lp.cellX,
2060fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen                        lp.cellY, c.x, c.y, c.spanX, c.spanY);
2061d024f9845a0974ab525baad085f316031cd5a742Adam Cohen                rha.animate();
206219f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
206319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
206419f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
206519f3792523fe2d55ea791a9286398a6120920690Adam Cohen
2066fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen    // Class which represents the reorder preview animations. These animations show that an item is
206719f3792523fe2d55ea791a9286398a6120920690Adam Cohen    // in a temporary state, and hint at where the item will return to.
2068fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen    class ReorderPreviewAnimation {
206919f3792523fe2d55ea791a9286398a6120920690Adam Cohen        View child;
2070d024f9845a0974ab525baad085f316031cd5a742Adam Cohen        float finalDeltaX;
2071d024f9845a0974ab525baad085f316031cd5a742Adam Cohen        float finalDeltaY;
2072d024f9845a0974ab525baad085f316031cd5a742Adam Cohen        float initDeltaX;
2073d024f9845a0974ab525baad085f316031cd5a742Adam Cohen        float initDeltaY;
2074d024f9845a0974ab525baad085f316031cd5a742Adam Cohen        float finalScale;
2075d024f9845a0974ab525baad085f316031cd5a742Adam Cohen        float initScale;
2076fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen        int mode;
2077fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen        boolean repeating = false;
2078fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen        private static final int PREVIEW_DURATION = 300;
2079fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen        private static final int HINT_DURATION = Workspace.REORDER_TIMEOUT;
2080fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen
2081fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen        public static final int MODE_HINT = 0;
2082fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen        public static final int MODE_PREVIEW = 1;
2083fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen
2084e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen        Animator a;
208519f3792523fe2d55ea791a9286398a6120920690Adam Cohen
2086fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen        public ReorderPreviewAnimation(View child, int mode, int cellX0, int cellY0, int cellX1,
2087fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen                int cellY1, int spanX, int spanY) {
208819f3792523fe2d55ea791a9286398a6120920690Adam Cohen            regionToCenterPoint(cellX0, cellY0, spanX, spanY, mTmpPoint);
208919f3792523fe2d55ea791a9286398a6120920690Adam Cohen            final int x0 = mTmpPoint[0];
209019f3792523fe2d55ea791a9286398a6120920690Adam Cohen            final int y0 = mTmpPoint[1];
209119f3792523fe2d55ea791a9286398a6120920690Adam Cohen            regionToCenterPoint(cellX1, cellY1, spanX, spanY, mTmpPoint);
209219f3792523fe2d55ea791a9286398a6120920690Adam Cohen            final int x1 = mTmpPoint[0];
209319f3792523fe2d55ea791a9286398a6120920690Adam Cohen            final int y1 = mTmpPoint[1];
209419f3792523fe2d55ea791a9286398a6120920690Adam Cohen            final int dX = x1 - x0;
209519f3792523fe2d55ea791a9286398a6120920690Adam Cohen            final int dY = y1 - y0;
2096d024f9845a0974ab525baad085f316031cd5a742Adam Cohen            finalDeltaX = 0;
2097d024f9845a0974ab525baad085f316031cd5a742Adam Cohen            finalDeltaY = 0;
2098fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen            int dir = mode == MODE_HINT ? -1 : 1;
209919f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (dX == dY && dX == 0) {
210019f3792523fe2d55ea791a9286398a6120920690Adam Cohen            } else {
210119f3792523fe2d55ea791a9286398a6120920690Adam Cohen                if (dY == 0) {
2102fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen                    finalDeltaX = - dir * Math.signum(dX) * mReorderPreviewAnimationMagnitude;
210319f3792523fe2d55ea791a9286398a6120920690Adam Cohen                } else if (dX == 0) {
2104fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen                    finalDeltaY = - dir * Math.signum(dY) * mReorderPreviewAnimationMagnitude;
210519f3792523fe2d55ea791a9286398a6120920690Adam Cohen                } else {
210619f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    double angle = Math.atan( (float) (dY) / dX);
2107fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen                    finalDeltaX = (int) (- dir * Math.signum(dX) *
2108fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen                            Math.abs(Math.cos(angle) * mReorderPreviewAnimationMagnitude));
2109fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen                    finalDeltaY = (int) (- dir * Math.signum(dY) *
2110fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen                            Math.abs(Math.sin(angle) * mReorderPreviewAnimationMagnitude));
211119f3792523fe2d55ea791a9286398a6120920690Adam Cohen                }
211219f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
2113fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen            this.mode = mode;
2114d024f9845a0974ab525baad085f316031cd5a742Adam Cohen            initDeltaX = child.getTranslationX();
2115d024f9845a0974ab525baad085f316031cd5a742Adam Cohen            initDeltaY = child.getTranslationY();
2116307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen            finalScale = getChildrenScale() - 4.0f / child.getWidth();
2117d024f9845a0974ab525baad085f316031cd5a742Adam Cohen            initScale = child.getScaleX();
211819f3792523fe2d55ea791a9286398a6120920690Adam Cohen            this.child = child;
211919f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
212019f3792523fe2d55ea791a9286398a6120920690Adam Cohen
2121d024f9845a0974ab525baad085f316031cd5a742Adam Cohen        void animate() {
212219f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (mShakeAnimators.containsKey(child)) {
2123fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen                ReorderPreviewAnimation oldAnimation = mShakeAnimators.get(child);
2124d024f9845a0974ab525baad085f316031cd5a742Adam Cohen                oldAnimation.cancel();
212519f3792523fe2d55ea791a9286398a6120920690Adam Cohen                mShakeAnimators.remove(child);
2126e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen                if (finalDeltaX == 0 && finalDeltaY == 0) {
2127e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen                    completeAnimationImmediately();
2128e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen                    return;
2129e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen                }
213019f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
2131d024f9845a0974ab525baad085f316031cd5a742Adam Cohen            if (finalDeltaX == 0 && finalDeltaY == 0) {
213219f3792523fe2d55ea791a9286398a6120920690Adam Cohen                return;
213319f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
2134f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka            ValueAnimator va = LauncherAnimUtils.ofFloat(child, 0f, 1f);
2135e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen            a = va;
213619f3792523fe2d55ea791a9286398a6120920690Adam Cohen            va.setRepeatMode(ValueAnimator.REVERSE);
213719f3792523fe2d55ea791a9286398a6120920690Adam Cohen            va.setRepeatCount(ValueAnimator.INFINITE);
2138fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen            va.setDuration(mode == MODE_HINT ? HINT_DURATION : PREVIEW_DURATION);
2139d024f9845a0974ab525baad085f316031cd5a742Adam Cohen            va.setStartDelay((int) (Math.random() * 60));
214019f3792523fe2d55ea791a9286398a6120920690Adam Cohen            va.addUpdateListener(new AnimatorUpdateListener() {
214119f3792523fe2d55ea791a9286398a6120920690Adam Cohen                @Override
214219f3792523fe2d55ea791a9286398a6120920690Adam Cohen                public void onAnimationUpdate(ValueAnimator animation) {
214319f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    float r = ((Float) animation.getAnimatedValue()).floatValue();
2144fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen                    float r1 = (mode == MODE_HINT && repeating) ? 1.0f : r;
2145fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen                    float x = r1 * finalDeltaX + (1 - r1) * initDeltaX;
2146fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen                    float y = r1 * finalDeltaY + (1 - r1) * initDeltaY;
214719f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    child.setTranslationX(x);
214819f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    child.setTranslationY(y);
2149d024f9845a0974ab525baad085f316031cd5a742Adam Cohen                    float s = r * finalScale + (1 - r) * initScale;
215050e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely                    child.setScaleX(s);
215150e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely                    child.setScaleY(s);
215219f3792523fe2d55ea791a9286398a6120920690Adam Cohen                }
215319f3792523fe2d55ea791a9286398a6120920690Adam Cohen            });
215419f3792523fe2d55ea791a9286398a6120920690Adam Cohen            va.addListener(new AnimatorListenerAdapter() {
215519f3792523fe2d55ea791a9286398a6120920690Adam Cohen                public void onAnimationRepeat(Animator animation) {
215619f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    // We make sure to end only after a full period
2157d024f9845a0974ab525baad085f316031cd5a742Adam Cohen                    initDeltaX = 0;
2158d024f9845a0974ab525baad085f316031cd5a742Adam Cohen                    initDeltaY = 0;
2159307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen                    initScale = getChildrenScale();
2160fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen                    repeating = true;
216119f3792523fe2d55ea791a9286398a6120920690Adam Cohen                }
216219f3792523fe2d55ea791a9286398a6120920690Adam Cohen            });
216319f3792523fe2d55ea791a9286398a6120920690Adam Cohen            mShakeAnimators.put(child, this);
216419f3792523fe2d55ea791a9286398a6120920690Adam Cohen            va.start();
216519f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
216619f3792523fe2d55ea791a9286398a6120920690Adam Cohen
2167d024f9845a0974ab525baad085f316031cd5a742Adam Cohen        private void cancel() {
2168e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen            if (a != null) {
2169e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen                a.cancel();
2170e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen            }
217119f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
2172e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen
2173091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen        @Thunk void completeAnimationImmediately() {
2174e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen            if (a != null) {
2175e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen                a.cancel();
2176e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen            }
217750e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely
21782ecf995e0d2d55eb71d03f7230ca87270872d1a3Michael Jurka            AnimatorSet s = LauncherAnimUtils.createAnimatorSet();
2179e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen            a = s;
218050e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely            s.playTogether(
2181307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen                LauncherAnimUtils.ofFloat(child, "scaleX", getChildrenScale()),
2182307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen                LauncherAnimUtils.ofFloat(child, "scaleY", getChildrenScale()),
21832ecf995e0d2d55eb71d03f7230ca87270872d1a3Michael Jurka                LauncherAnimUtils.ofFloat(child, "translationX", 0f),
21842ecf995e0d2d55eb71d03f7230ca87270872d1a3Michael Jurka                LauncherAnimUtils.ofFloat(child, "translationY", 0f)
218550e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely            );
218650e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely            s.setDuration(REORDER_ANIMATION_DURATION);
218750e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely            s.setInterpolator(new android.view.animation.DecelerateInterpolator(1.5f));
218850e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely            s.start();
218950e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely        }
219019f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
219119f3792523fe2d55ea791a9286398a6120920690Adam Cohen
2192fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen    private void completeAndClearReorderPreviewAnimations() {
2193fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen        for (ReorderPreviewAnimation a: mShakeAnimators.values()) {
219450e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely            a.completeAnimationImmediately();
219519f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
219619f3792523fe2d55ea791a9286398a6120920690Adam Cohen        mShakeAnimators.clear();
219719f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
219819f3792523fe2d55ea791a9286398a6120920690Adam Cohen
2199482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private void commitTempPlacement() {
2200482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < mCountX; i++) {
2201482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            for (int j = 0; j < mCountY; j++) {
2202482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                mOccupied[i][j] = mTmpOccupied[i][j];
2203482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
2204482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2205a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        int childCount = mShortcutsAndWidgets.getChildCount();
2206482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < childCount; i++) {
2207ea889a294be004f4b1c21e9b874f9e63abfb8bd6Adam Cohen            View child = mShortcutsAndWidgets.getChildAt(i);
2208ea889a294be004f4b1c21e9b874f9e63abfb8bd6Adam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
2209ea889a294be004f4b1c21e9b874f9e63abfb8bd6Adam Cohen            ItemInfo info = (ItemInfo) child.getTag();
22102acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen            // We do a null check here because the item info can be null in the case of the
22112acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen            // AllApps button in the hotseat.
22122acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen            if (info != null) {
2213487f7dd3059621527eb439d7d51d34e00293f9b1Adam Cohen                if (info.cellX != lp.tmpCellX || info.cellY != lp.tmpCellY ||
2214487f7dd3059621527eb439d7d51d34e00293f9b1Adam Cohen                        info.spanX != lp.cellHSpan || info.spanY != lp.cellVSpan) {
2215487f7dd3059621527eb439d7d51d34e00293f9b1Adam Cohen                    info.requiresDbUpdate = true;
2216487f7dd3059621527eb439d7d51d34e00293f9b1Adam Cohen                }
22172acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen                info.cellX = lp.cellX = lp.tmpCellX;
22182acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen                info.cellY = lp.cellY = lp.tmpCellY;
2219bebf042666cffe52039b875a549a582abd78a431Adam Cohen                info.spanX = lp.cellHSpan;
2220bebf042666cffe52039b875a549a582abd78a431Adam Cohen                info.spanY = lp.cellVSpan;
22212acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen            }
2222482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
22232acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen        mLauncher.getWorkspace().updateItemLocationsInDatabase(this);
2224482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2225482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2226f7a29e83f06909b378dba39c83a522375682710aSunny Goyal    private void setUseTempCoords(boolean useTempCoords) {
2227a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        int childCount = mShortcutsAndWidgets.getChildCount();
2228482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < childCount; i++) {
2229a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            LayoutParams lp = (LayoutParams) mShortcutsAndWidgets.getChildAt(i).getLayoutParams();
2230482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            lp.useTmpCoords = useTempCoords;
2231482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2232482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2233482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2234f7a29e83f06909b378dba39c83a522375682710aSunny Goyal    private ItemConfiguration findConfigurationNoShuffle(int pixelX, int pixelY, int minSpanX, int minSpanY,
2235482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            int spanX, int spanY, View dragView, ItemConfiguration solution) {
2236482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        int[] result = new int[2];
2237482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        int[] resultSpan = new int[2];
2238f7a29e83f06909b378dba39c83a522375682710aSunny Goyal        findNearestVacantArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, result,
2239482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                resultSpan);
2240482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (result[0] >= 0 && result[1] >= 0) {
2241482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            copyCurrentStateToSolution(solution, false);
2242482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewX = result[0];
2243482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewY = result[1];
2244482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewSpanX = resultSpan[0];
2245482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewSpanY = resultSpan[1];
2246482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.isSolution = true;
2247482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        } else {
2248482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.isSolution = false;
2249482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2250482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return solution;
2251482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2252482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2253482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public void prepareChildForDrag(View child) {
2254482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsAsUnoccupiedForView(child);
2255482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2256482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
225719f3792523fe2d55ea791a9286398a6120920690Adam Cohen    /* This seems like it should be obvious and straight-forward, but when the direction vector
225819f3792523fe2d55ea791a9286398a6120920690Adam Cohen    needs to match with the notion of the dragView pushing other views, we have to employ
225919f3792523fe2d55ea791a9286398a6120920690Adam Cohen    a slightly more subtle notion of the direction vector. The question is what two points is
226019f3792523fe2d55ea791a9286398a6120920690Adam Cohen    the vector between? The center of the dragView and its desired destination? Not quite, as
226119f3792523fe2d55ea791a9286398a6120920690Adam Cohen    this doesn't necessarily coincide with the interaction of the dragView and items occupying
226219f3792523fe2d55ea791a9286398a6120920690Adam Cohen    those cells. Instead we use some heuristics to often lock the vector to up, down, left
226319f3792523fe2d55ea791a9286398a6120920690Adam Cohen    or right, which helps make pushing feel right.
226419f3792523fe2d55ea791a9286398a6120920690Adam Cohen    */
226519f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private void getDirectionVectorForDrop(int dragViewCenterX, int dragViewCenterY, int spanX,
226619f3792523fe2d55ea791a9286398a6120920690Adam Cohen            int spanY, View dragView, int[] resultDirection) {
226719f3792523fe2d55ea791a9286398a6120920690Adam Cohen        int[] targetDestination = new int[2];
226819f3792523fe2d55ea791a9286398a6120920690Adam Cohen
226919f3792523fe2d55ea791a9286398a6120920690Adam Cohen        findNearestArea(dragViewCenterX, dragViewCenterY, spanX, spanY, targetDestination);
227019f3792523fe2d55ea791a9286398a6120920690Adam Cohen        Rect dragRect = new Rect();
227119f3792523fe2d55ea791a9286398a6120920690Adam Cohen        regionToRect(targetDestination[0], targetDestination[1], spanX, spanY, dragRect);
227219f3792523fe2d55ea791a9286398a6120920690Adam Cohen        dragRect.offset(dragViewCenterX - dragRect.centerX(), dragViewCenterY - dragRect.centerY());
227319f3792523fe2d55ea791a9286398a6120920690Adam Cohen
227419f3792523fe2d55ea791a9286398a6120920690Adam Cohen        Rect dropRegionRect = new Rect();
227519f3792523fe2d55ea791a9286398a6120920690Adam Cohen        getViewsIntersectingRegion(targetDestination[0], targetDestination[1], spanX, spanY,
227619f3792523fe2d55ea791a9286398a6120920690Adam Cohen                dragView, dropRegionRect, mIntersectingViews);
227719f3792523fe2d55ea791a9286398a6120920690Adam Cohen
227819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        int dropRegionSpanX = dropRegionRect.width();
227919f3792523fe2d55ea791a9286398a6120920690Adam Cohen        int dropRegionSpanY = dropRegionRect.height();
228019f3792523fe2d55ea791a9286398a6120920690Adam Cohen
228119f3792523fe2d55ea791a9286398a6120920690Adam Cohen        regionToRect(dropRegionRect.left, dropRegionRect.top, dropRegionRect.width(),
228219f3792523fe2d55ea791a9286398a6120920690Adam Cohen                dropRegionRect.height(), dropRegionRect);
228319f3792523fe2d55ea791a9286398a6120920690Adam Cohen
228419f3792523fe2d55ea791a9286398a6120920690Adam Cohen        int deltaX = (dropRegionRect.centerX() - dragViewCenterX) / spanX;
228519f3792523fe2d55ea791a9286398a6120920690Adam Cohen        int deltaY = (dropRegionRect.centerY() - dragViewCenterY) / spanY;
228619f3792523fe2d55ea791a9286398a6120920690Adam Cohen
228719f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if (dropRegionSpanX == mCountX || spanX == mCountX) {
228819f3792523fe2d55ea791a9286398a6120920690Adam Cohen            deltaX = 0;
228919f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
229019f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if (dropRegionSpanY == mCountY || spanY == mCountY) {
229119f3792523fe2d55ea791a9286398a6120920690Adam Cohen            deltaY = 0;
229219f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
229319f3792523fe2d55ea791a9286398a6120920690Adam Cohen
229419f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if (deltaX == 0 && deltaY == 0) {
229519f3792523fe2d55ea791a9286398a6120920690Adam Cohen            // No idea what to do, give a random direction.
229619f3792523fe2d55ea791a9286398a6120920690Adam Cohen            resultDirection[0] = 1;
229719f3792523fe2d55ea791a9286398a6120920690Adam Cohen            resultDirection[1] = 0;
229819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        } else {
229919f3792523fe2d55ea791a9286398a6120920690Adam Cohen            computeDirectionVector(deltaX, deltaY, resultDirection);
230019f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
230119f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
230219f3792523fe2d55ea791a9286398a6120920690Adam Cohen
230319f3792523fe2d55ea791a9286398a6120920690Adam Cohen    // For a given cell and span, fetch the set of views intersecting the region.
230419f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private void getViewsIntersectingRegion(int cellX, int cellY, int spanX, int spanY,
230519f3792523fe2d55ea791a9286398a6120920690Adam Cohen            View dragView, Rect boundingRect, ArrayList<View> intersectingViews) {
230619f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if (boundingRect != null) {
230719f3792523fe2d55ea791a9286398a6120920690Adam Cohen            boundingRect.set(cellX, cellY, cellX + spanX, cellY + spanY);
230819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
230919f3792523fe2d55ea791a9286398a6120920690Adam Cohen        intersectingViews.clear();
231019f3792523fe2d55ea791a9286398a6120920690Adam Cohen        Rect r0 = new Rect(cellX, cellY, cellX + spanX, cellY + spanY);
231119f3792523fe2d55ea791a9286398a6120920690Adam Cohen        Rect r1 = new Rect();
231219f3792523fe2d55ea791a9286398a6120920690Adam Cohen        final int count = mShortcutsAndWidgets.getChildCount();
231319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        for (int i = 0; i < count; i++) {
231419f3792523fe2d55ea791a9286398a6120920690Adam Cohen            View child = mShortcutsAndWidgets.getChildAt(i);
231519f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (child == dragView) continue;
231619f3792523fe2d55ea791a9286398a6120920690Adam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
231719f3792523fe2d55ea791a9286398a6120920690Adam Cohen            r1.set(lp.cellX, lp.cellY, lp.cellX + lp.cellHSpan, lp.cellY + lp.cellVSpan);
231819f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (Rect.intersects(r0, r1)) {
231919f3792523fe2d55ea791a9286398a6120920690Adam Cohen                mIntersectingViews.add(child);
232019f3792523fe2d55ea791a9286398a6120920690Adam Cohen                if (boundingRect != null) {
232119f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    boundingRect.union(r1);
232219f3792523fe2d55ea791a9286398a6120920690Adam Cohen                }
232319f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
232419f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
232519f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
232619f3792523fe2d55ea791a9286398a6120920690Adam Cohen
232719f3792523fe2d55ea791a9286398a6120920690Adam Cohen    boolean isNearestDropLocationOccupied(int pixelX, int pixelY, int spanX, int spanY,
232819f3792523fe2d55ea791a9286398a6120920690Adam Cohen            View dragView, int[] result) {
232919f3792523fe2d55ea791a9286398a6120920690Adam Cohen        result = findNearestArea(pixelX, pixelY, spanX, spanY, result);
233019f3792523fe2d55ea791a9286398a6120920690Adam Cohen        getViewsIntersectingRegion(result[0], result[1], spanX, spanY, dragView, null,
233119f3792523fe2d55ea791a9286398a6120920690Adam Cohen                mIntersectingViews);
233219f3792523fe2d55ea791a9286398a6120920690Adam Cohen        return !mIntersectingViews.isEmpty();
233319f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
233419f3792523fe2d55ea791a9286398a6120920690Adam Cohen
233519f3792523fe2d55ea791a9286398a6120920690Adam Cohen    void revertTempState() {
2336fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen        completeAndClearReorderPreviewAnimations();
2337fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen        if (isItemPlacementDirty() && !DESTRUCTIVE_REORDER) {
2338fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen            final int count = mShortcutsAndWidgets.getChildCount();
2339fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen            for (int i = 0; i < count; i++) {
2340fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen                View child = mShortcutsAndWidgets.getChildAt(i);
2341fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen                LayoutParams lp = (LayoutParams) child.getLayoutParams();
2342fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen                if (lp.tmpCellX != lp.cellX || lp.tmpCellY != lp.cellY) {
2343fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen                    lp.tmpCellX = lp.cellX;
2344fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen                    lp.tmpCellY = lp.cellY;
2345fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen                    animateChildToPosition(child, lp.cellX, lp.cellY, REORDER_ANIMATION_DURATION,
2346fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen                            0, false, false);
2347fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen                }
234819f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
2349fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen            setItemPlacementDirty(false);
235019f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
235119f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
235219f3792523fe2d55ea791a9286398a6120920690Adam Cohen
2353bebf042666cffe52039b875a549a582abd78a431Adam Cohen    boolean createAreaForResize(int cellX, int cellY, int spanX, int spanY,
2354bebf042666cffe52039b875a549a582abd78a431Adam Cohen            View dragView, int[] direction, boolean commit) {
2355bebf042666cffe52039b875a549a582abd78a431Adam Cohen        int[] pixelXY = new int[2];
2356bebf042666cffe52039b875a549a582abd78a431Adam Cohen        regionToCenterPoint(cellX, cellY, spanX, spanY, pixelXY);
2357bebf042666cffe52039b875a549a582abd78a431Adam Cohen
2358bebf042666cffe52039b875a549a582abd78a431Adam Cohen        // First we determine if things have moved enough to cause a different layout
2359fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen        ItemConfiguration swapSolution = findReorderSolution(pixelXY[0], pixelXY[1], spanX, spanY,
2360bebf042666cffe52039b875a549a582abd78a431Adam Cohen                 spanX,  spanY, direction, dragView,  true,  new ItemConfiguration());
2361bebf042666cffe52039b875a549a582abd78a431Adam Cohen
2362bebf042666cffe52039b875a549a582abd78a431Adam Cohen        setUseTempCoords(true);
2363bebf042666cffe52039b875a549a582abd78a431Adam Cohen        if (swapSolution != null && swapSolution.isSolution) {
2364bebf042666cffe52039b875a549a582abd78a431Adam Cohen            // If we're just testing for a possible location (MODE_ACCEPT_DROP), we don't bother
2365bebf042666cffe52039b875a549a582abd78a431Adam Cohen            // committing anything or animating anything as we just want to determine if a solution
2366bebf042666cffe52039b875a549a582abd78a431Adam Cohen            // exists
2367bebf042666cffe52039b875a549a582abd78a431Adam Cohen            copySolutionToTempState(swapSolution, dragView);
2368bebf042666cffe52039b875a549a582abd78a431Adam Cohen            setItemPlacementDirty(true);
2369bebf042666cffe52039b875a549a582abd78a431Adam Cohen            animateItemsToSolution(swapSolution, dragView, commit);
2370bebf042666cffe52039b875a549a582abd78a431Adam Cohen
2371bebf042666cffe52039b875a549a582abd78a431Adam Cohen            if (commit) {
2372bebf042666cffe52039b875a549a582abd78a431Adam Cohen                commitTempPlacement();
2373fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen                completeAndClearReorderPreviewAnimations();
2374bebf042666cffe52039b875a549a582abd78a431Adam Cohen                setItemPlacementDirty(false);
2375bebf042666cffe52039b875a549a582abd78a431Adam Cohen            } else {
2376fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen                beginOrAdjustReorderPreviewAnimations(swapSolution, dragView,
2377fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen                        REORDER_ANIMATION_DURATION, ReorderPreviewAnimation.MODE_PREVIEW);
2378bebf042666cffe52039b875a549a582abd78a431Adam Cohen            }
2379bebf042666cffe52039b875a549a582abd78a431Adam Cohen            mShortcutsAndWidgets.requestLayout();
2380bebf042666cffe52039b875a549a582abd78a431Adam Cohen        }
2381bebf042666cffe52039b875a549a582abd78a431Adam Cohen        return swapSolution.isSolution;
2382bebf042666cffe52039b875a549a582abd78a431Adam Cohen    }
2383bebf042666cffe52039b875a549a582abd78a431Adam Cohen
2384fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen    int[] performReorder(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, int spanY,
2385482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            View dragView, int[] result, int resultSpan[], int mode) {
2386482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // First we determine if things have moved enough to cause a different layout
238747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        result = findNearestArea(pixelX, pixelY, spanX, spanY, result);
2388482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2389482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (resultSpan == null) {
2390482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            resultSpan = new int[2];
2391482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2392482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
239319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        // When we are checking drop validity or actually dropping, we don't recompute the
239419f3792523fe2d55ea791a9286398a6120920690Adam Cohen        // direction vector, since we want the solution to match the preview, and it's possible
239519f3792523fe2d55ea791a9286398a6120920690Adam Cohen        // that the exact position of the item has changed to result in a new reordering outcome.
2396b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen        if ((mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL || mode == MODE_ACCEPT_DROP)
2397b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen               && mPreviousReorderDirection[0] != INVALID_DIRECTION) {
239819f3792523fe2d55ea791a9286398a6120920690Adam Cohen            mDirectionVector[0] = mPreviousReorderDirection[0];
239919f3792523fe2d55ea791a9286398a6120920690Adam Cohen            mDirectionVector[1] = mPreviousReorderDirection[1];
240019f3792523fe2d55ea791a9286398a6120920690Adam Cohen            // We reset this vector after drop
2401b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen            if (mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL) {
2402b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen                mPreviousReorderDirection[0] = INVALID_DIRECTION;
2403b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen                mPreviousReorderDirection[1] = INVALID_DIRECTION;
240419f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
240519f3792523fe2d55ea791a9286398a6120920690Adam Cohen        } else {
240619f3792523fe2d55ea791a9286398a6120920690Adam Cohen            getDirectionVectorForDrop(pixelX, pixelY, spanX, spanY, dragView, mDirectionVector);
240719f3792523fe2d55ea791a9286398a6120920690Adam Cohen            mPreviousReorderDirection[0] = mDirectionVector[0];
240819f3792523fe2d55ea791a9286398a6120920690Adam Cohen            mPreviousReorderDirection[1] = mDirectionVector[1];
240919f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
241019f3792523fe2d55ea791a9286398a6120920690Adam Cohen
2411fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen        // Find a solution involving pushing / displacing any items in the way
2412fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen        ItemConfiguration swapSolution = findReorderSolution(pixelX, pixelY, minSpanX, minSpanY,
2413482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                 spanX,  spanY, mDirectionVector, dragView,  true,  new ItemConfiguration());
2414482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2415482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // We attempt the approach which doesn't shuffle views at all
2416482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        ItemConfiguration noShuffleSolution = findConfigurationNoShuffle(pixelX, pixelY, minSpanX,
2417482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                minSpanY, spanX, spanY, dragView, new ItemConfiguration());
2418482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2419482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        ItemConfiguration finalSolution = null;
2420fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen
2421fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen        // If the reorder solution requires resizing (shrinking) the item being dropped, we instead
2422fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen        // favor a solution in which the item is not resized, but
2423482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (swapSolution.isSolution && swapSolution.area() >= noShuffleSolution.area()) {
2424482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            finalSolution = swapSolution;
2425482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        } else if (noShuffleSolution.isSolution) {
2426482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            finalSolution = noShuffleSolution;
2427482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2428482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2429fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen        if (mode == MODE_SHOW_REORDER_HINT) {
2430fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen            if (finalSolution != null) {
2431fe69287b97d16c8941ab9463e4868fca45ad8152Adam Cohen                beginOrAdjustReorderPreviewAnimations(finalSolution, dragView, 0,
2432fe69287b97d16c8941ab9463e4868fca45ad8152Adam Cohen                        ReorderPreviewAnimation.MODE_HINT);
2433fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen                result[0] = finalSolution.dragViewX;
2434fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen                result[1] = finalSolution.dragViewY;
2435fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen                resultSpan[0] = finalSolution.dragViewSpanX;
2436fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen                resultSpan[1] = finalSolution.dragViewSpanY;
2437fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen            } else {
2438fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen                result[0] = result[1] = resultSpan[0] = resultSpan[1] = -1;
2439fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen            }
2440fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen            return result;
2441fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen        }
2442fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen
2443482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        boolean foundSolution = true;
2444482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (!DESTRUCTIVE_REORDER) {
2445482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            setUseTempCoords(true);
2446482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2447482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2448482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (finalSolution != null) {
2449482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            result[0] = finalSolution.dragViewX;
2450482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            result[1] = finalSolution.dragViewY;
2451482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            resultSpan[0] = finalSolution.dragViewSpanX;
2452482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            resultSpan[1] = finalSolution.dragViewSpanY;
2453482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2454482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            // If we're just testing for a possible location (MODE_ACCEPT_DROP), we don't bother
2455482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            // committing anything or animating anything as we just want to determine if a solution
2456482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            // exists
2457482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (mode == MODE_DRAG_OVER || mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL) {
2458482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                if (!DESTRUCTIVE_REORDER) {
2459482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    copySolutionToTempState(finalSolution, dragView);
2460482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                }
2461482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                setItemPlacementDirty(true);
2462482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                animateItemsToSolution(finalSolution, dragView, mode == MODE_ON_DROP);
2463482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
246419f3792523fe2d55ea791a9286398a6120920690Adam Cohen                if (!DESTRUCTIVE_REORDER &&
246519f3792523fe2d55ea791a9286398a6120920690Adam Cohen                        (mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL)) {
2466482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    commitTempPlacement();
2467fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen                    completeAndClearReorderPreviewAnimations();
246819f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    setItemPlacementDirty(false);
246919f3792523fe2d55ea791a9286398a6120920690Adam Cohen                } else {
2470fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen                    beginOrAdjustReorderPreviewAnimations(finalSolution, dragView,
2471fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen                            REORDER_ANIMATION_DURATION,  ReorderPreviewAnimation.MODE_PREVIEW);
2472482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                }
2473482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
2474482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        } else {
2475482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            foundSolution = false;
2476482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            result[0] = result[1] = resultSpan[0] = resultSpan[1] = -1;
2477482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2478482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2479482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if ((mode == MODE_ON_DROP || !foundSolution) && !DESTRUCTIVE_REORDER) {
2480482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            setUseTempCoords(false);
2481482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2482482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2483a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.requestLayout();
2484482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return result;
2485482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2486482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
248719f3792523fe2d55ea791a9286398a6120920690Adam Cohen    void setItemPlacementDirty(boolean dirty) {
248819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        mItemPlacementDirty = dirty;
2489482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
249019f3792523fe2d55ea791a9286398a6120920690Adam Cohen    boolean isItemPlacementDirty() {
249119f3792523fe2d55ea791a9286398a6120920690Adam Cohen        return mItemPlacementDirty;
2492482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2493482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2494091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen    @Thunk class ItemConfiguration {
24958baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        HashMap<View, CellAndSpan> map = new HashMap<View, CellAndSpan>();
2496f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        private HashMap<View, CellAndSpan> savedMap = new HashMap<View, CellAndSpan>();
2497f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        ArrayList<View> sortedViews = new ArrayList<View>();
2498fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen        ArrayList<View> intersectingViews;
2499482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        boolean isSolution = false;
2500482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        int dragViewX, dragViewY, dragViewSpanX, dragViewSpanY;
2501482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2502f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        void save() {
2503f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            // Copy current state into savedMap
2504f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            for (View v: map.keySet()) {
2505f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                map.get(v).copy(savedMap.get(v));
2506f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            }
2507f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        }
2508f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen
2509f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        void restore() {
2510f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            // Restore current state from savedMap
2511f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            for (View v: savedMap.keySet()) {
2512f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen                savedMap.get(v).copy(map.get(v));
2513f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            }
2514f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        }
2515f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen
2516f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        void add(View v, CellAndSpan cs) {
2517f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            map.put(v, cs);
2518f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            savedMap.put(v, new CellAndSpan());
2519f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            sortedViews.add(v);
2520f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        }
2521f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen
2522482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        int area() {
2523482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            return dragViewSpanX * dragViewSpanY;
2524482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
25258baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen    }
25268baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen
25278baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen    private class CellAndSpan {
25288baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        int x, y;
25298baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        int spanX, spanY;
25308baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen
2531f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        public CellAndSpan() {
2532f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        }
2533f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen
2534f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        public void copy(CellAndSpan copy) {
2535f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            copy.x = x;
2536f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            copy.y = y;
2537f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            copy.spanX = spanX;
2538f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            copy.spanY = spanY;
2539f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        }
2540f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen
25418baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        public CellAndSpan(int x, int y, int spanX, int spanY) {
25428baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            this.x = x;
25438baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            this.y = y;
25448baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            this.spanX = spanX;
25458baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            this.spanY = spanY;
2546482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2547f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen
2548f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        public String toString() {
2549f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen            return "(" + x + ", " + y + ": " + spanX + ", " + spanY + ")";
2550f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen        }
2551f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen
2552482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2553482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2554df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    /**
2555df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * Find a starting cell position that will fit the given bounds nearest the requested
2556df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * cell location. Uses Euclidean distance to score multiple vacant areas.
2557df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     *
2558df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param pixelX The X location at which you want to search for a vacant area.
2559df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param pixelY The Y location at which you want to search for a vacant area.
2560df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param spanX Horizontal span of the object.
2561df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param spanY Vertical span of the object.
2562df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param ignoreView Considers space occupied by this view as unoccupied
2563df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param result Previously returned value to possibly recycle.
2564df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @return The X, Y cell of a vacant area that can contain this object,
2565df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     *         nearest the requested location.
2566df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     */
2567f7a29e83f06909b378dba39c83a522375682710aSunny Goyal    int[] findNearestArea(int pixelX, int pixelY, int spanX, int spanY, int[] result) {
2568f7a29e83f06909b378dba39c83a522375682710aSunny Goyal        return findNearestArea(pixelX, pixelY, spanX, spanY, spanX, spanY, false, result, null);
2569df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    }
2570df0353815c629fc678824b07a234b89a1ff94208Adam Cohen
25710280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    boolean existsEmptyCell() {
25720280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        return findCellForSpan(null, 1, 1);
25730280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
25740280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
25750280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    /**
25760280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * Finds the upper-left coordinate of the first rectangle in the grid that can
25770280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * hold a cell of the specified dimensions. If intersectX and intersectY are not -1,
25780280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * then this method will only return coordinates for rectangles that contain the cell
25790280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * (intersectX, intersectY)
25800280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     *
25810280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param cellXY The array that will contain the position of a vacant cell if such a cell
25820280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     *               can be found.
25830280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param spanX The horizontal span of the cell we want to find.
25840280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param spanY The vertical span of the cell we want to find.
25850280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     *
25860280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @return True if a vacant cell of the specified dimension was found, false otherwise.
25870280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     */
25883f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song    public boolean findCellForSpan(int[] cellXY, int spanX, int spanY) {
258928750fba6a2d141eb9a1e566718c17236030b815Michael Jurka        boolean foundCell = false;
2590f7a29e83f06909b378dba39c83a522375682710aSunny Goyal        final int endX = mCountX - (spanX - 1);
2591f7a29e83f06909b378dba39c83a522375682710aSunny Goyal        final int endY = mCountY - (spanY - 1);
2592f7a29e83f06909b378dba39c83a522375682710aSunny Goyal
2593f7a29e83f06909b378dba39c83a522375682710aSunny Goyal        for (int y = 0; y < endY && !foundCell; y++) {
2594f7a29e83f06909b378dba39c83a522375682710aSunny Goyal            inner:
2595f7a29e83f06909b378dba39c83a522375682710aSunny Goyal            for (int x = 0; x < endX; x++) {
2596f7a29e83f06909b378dba39c83a522375682710aSunny Goyal                for (int i = 0; i < spanX; i++) {
2597f7a29e83f06909b378dba39c83a522375682710aSunny Goyal                    for (int j = 0; j < spanY; j++) {
2598f7a29e83f06909b378dba39c83a522375682710aSunny Goyal                        if (mOccupied[x + i][y + j]) {
2599f7a29e83f06909b378dba39c83a522375682710aSunny Goyal                            // small optimization: we can skip to after the column we just found
2600f7a29e83f06909b378dba39c83a522375682710aSunny Goyal                            // an occupied cell
2601f7a29e83f06909b378dba39c83a522375682710aSunny Goyal                            x += i;
2602f7a29e83f06909b378dba39c83a522375682710aSunny Goyal                            continue inner;
26030280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                        }
26040280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                    }
26050280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                }
2606f7a29e83f06909b378dba39c83a522375682710aSunny Goyal                if (cellXY != null) {
2607f7a29e83f06909b378dba39c83a522375682710aSunny Goyal                    cellXY[0] = x;
2608f7a29e83f06909b378dba39c83a522375682710aSunny Goyal                    cellXY[1] = y;
2609f7a29e83f06909b378dba39c83a522375682710aSunny Goyal                }
2610f7a29e83f06909b378dba39c83a522375682710aSunny Goyal                foundCell = true;
26110280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                break;
26120280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            }
26130280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        }
26140280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
261528750fba6a2d141eb9a1e566718c17236030b815Michael Jurka        return foundCell;
26160280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
26170280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
261831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
2619c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung     * A drag event has begun over this layout.
2620c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung     * It may have begun over this layout (in which case onDragChild is called first),
2621c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung     * or it may have begun on another layout.
2622c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung     */
2623c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung    void onDragEnter() {
2624c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung        mDragging = true;
2625c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung    }
2626c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung
2627c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung    /**
26280280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * Called when drag has left this CellLayout or has been completed (successfully or not)
26296569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     */
26300280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    void onDragExit() {
26314be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        // This can actually be called when we aren't in a drag, e.g. when adding a new
26324be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        // item to this layout via the customize drawer.
26334be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        // Guard against that case.
26344be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        if (mDragging) {
26354be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            mDragging = false;
26364be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        }
263708ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy
263808ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy        // Invalidate the drag data
2639d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        mDragCell[0] = mDragCell[1] = -1;
264008ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy        mDragOutlineAnims[mDragOutlineCurrent].animateOut();
264108ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy        mDragOutlineCurrent = (mDragOutlineCurrent + 1) % mDragOutlineAnims.length;
264219f3792523fe2d55ea791a9286398a6120920690Adam Cohen        revertTempState();
264333945b21544bc98381df17726a3537c292d8c985Michael Jurka        setIsDragOverlapping(false);
26446569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    }
26456569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
26466569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    /**
2647aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     * Mark a child as having been dropped.
2648de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy     * At the beginning of the drag operation, the child may have been on another
2649ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy     * screen, but it is re-parented before this method is called.
265031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     *
265131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param child The child that is being dropped
265231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
2653716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    void onDropChild(View child) {
2654d94533d04a5f8f5485f106d10af60169857ea899Romain Guy        if (child != null) {
2655d94533d04a5f8f5485f106d10af60169857ea899Romain Guy            LayoutParams lp = (LayoutParams) child.getLayoutParams();
265684f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy            lp.dropped = true;
2657d94533d04a5f8f5485f106d10af60169857ea899Romain Guy            child.requestLayout();
2658d94533d04a5f8f5485f106d10af60169857ea899Romain Guy        }
265931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
266031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
266131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
266231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * Computes a bounding rectangle for a range of cells
2663aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     *
266431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param cellX X coordinate of upper left corner expressed as a cell position
266531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param cellY Y coordinate of upper left corner expressed as a cell position
2666aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     * @param cellHSpan Width in cells
266731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param cellVSpan Height in cells
26686569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     * @param resultRect Rect into which to put the results
266931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
2670d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    public void cellToRect(int cellX, int cellY, int cellHSpan, int cellVSpan, Rect resultRect) {
267131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        final int cellWidth = mCellWidth;
267231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        final int cellHeight = mCellHeight;
267331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        final int widthGap = mWidthGap;
267431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        final int heightGap = mHeightGap;
2675aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
26764b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int hStartPadding = getPaddingLeft();
26774b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int vStartPadding = getPaddingTop();
2678aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
267931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int width = cellHSpan * cellWidth + ((cellHSpan - 1) * widthGap);
268031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int height = cellVSpan * cellHeight + ((cellVSpan - 1) * heightGap);
268131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
268231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int x = hStartPadding + cellX * (cellWidth + widthGap);
268331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int y = vStartPadding + cellY * (cellHeight + heightGap);
2684aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
26856569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        resultRect.set(x, y, x + width, y + height);
268631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
2687aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
26880280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    private void clearOccupiedCells() {
26890280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        for (int x = 0; x < mCountX; x++) {
26900280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            for (int y = 0; y < mCountY; y++) {
26910280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                mOccupied[x][y] = false;
269231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            }
269331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
26940280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
269531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
2696d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    public void markCellsAsOccupiedForView(View view) {
2697a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        if (view == null || view.getParent() != mShortcutsAndWidgets) return;
26980280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        LayoutParams lp = (LayoutParams) view.getLayoutParams();
2699f7a29e83f06909b378dba39c83a522375682710aSunny Goyal        markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, mOccupied, true);
27000280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
27010280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
2702d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    public void markCellsAsUnoccupiedForView(View view) {
2703a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        if (view == null || view.getParent() != mShortcutsAndWidgets) return;
27040280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        LayoutParams lp = (LayoutParams) view.getLayoutParams();
2705f7a29e83f06909b378dba39c83a522375682710aSunny Goyal        markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, mOccupied, false);
27060280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
27070280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
2708482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private void markCellsForView(int cellX, int cellY, int spanX, int spanY, boolean[][] occupied,
2709482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            boolean value) {
2710482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (cellX < 0 || cellY < 0) return;
27110280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        for (int x = cellX; x < cellX + spanX && x < mCountX; x++) {
27120280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            for (int y = cellY; y < cellY + spanY && y < mCountY; y++) {
2713482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                occupied[x][y] = value;
271431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            }
271531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
271631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
271731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
27182801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    public int getDesiredWidth() {
27198b805b17158886035b38261eb611d8641701ae43Michael Jurka        return getPaddingLeft() + getPaddingRight() + (mCountX * mCellWidth) +
27202801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen                (Math.max((mCountX - 1), 0) * mWidthGap);
27212801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    }
27222801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
27232801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    public int getDesiredHeight()  {
27248b805b17158886035b38261eb611d8641701ae43Michael Jurka        return getPaddingTop() + getPaddingBottom() + (mCountY * mCellHeight) +
27252801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen                (Math.max((mCountY - 1), 0) * mHeightGap);
27262801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    }
27272801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
272866d72178af91d455700875635473be942bc90e54Michael Jurka    public boolean isOccupied(int x, int y) {
272966d72178af91d455700875635473be942bc90e54Michael Jurka        if (x < mCountX && y < mCountY) {
273066d72178af91d455700875635473be942bc90e54Michael Jurka            return mOccupied[x][y];
273166d72178af91d455700875635473be942bc90e54Michael Jurka        } else {
273266d72178af91d455700875635473be942bc90e54Michael Jurka            throw new RuntimeException("Position exceeds the bound of this CellLayout");
273366d72178af91d455700875635473be942bc90e54Michael Jurka        }
273466d72178af91d455700875635473be942bc90e54Michael Jurka    }
273566d72178af91d455700875635473be942bc90e54Michael Jurka
273631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
273731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
273831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        return new CellLayout.LayoutParams(getContext(), attrs);
273931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
274031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
274131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
274231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
274331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        return p instanceof CellLayout.LayoutParams;
274431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
274531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
274631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
274731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
274831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        return new CellLayout.LayoutParams(p);
274931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
275031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
275131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public static class LayoutParams extends ViewGroup.MarginLayoutParams {
275231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        /**
275331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         * Horizontal location of the item in the grid.
275431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         */
275531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        @ViewDebug.ExportedProperty
275631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public int cellX;
275731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
275831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        /**
275931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         * Vertical location of the item in the grid.
276031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         */
276131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        @ViewDebug.ExportedProperty
276231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public int cellY;
276331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
276431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        /**
2765482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         * Temporary horizontal location of the item in the grid during reorder
2766482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         */
2767482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        public int tmpCellX;
2768482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2769482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        /**
2770482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         * Temporary vertical location of the item in the grid during reorder
2771482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         */
2772482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        public int tmpCellY;
2773482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2774482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        /**
2775482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         * Indicates that the temporary coordinates should be used to layout the items
2776482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         */
2777482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        public boolean useTmpCoords;
2778482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2779482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        /**
278031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         * Number of cells spanned horizontally by the item.
278131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         */
278231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        @ViewDebug.ExportedProperty
278331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public int cellHSpan;
278431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
278531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        /**
278631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         * Number of cells spanned vertically by the item.
278731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         */
278831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        @ViewDebug.ExportedProperty
278931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public int cellVSpan;
2790aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
27911b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen        /**
27921b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen         * Indicates whether the item will set its x, y, width and height parameters freely,
27931b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen         * or whether these will be computed based on cellX, cellY, cellHSpan and cellVSpan.
27941b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen         */
2795d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        public boolean isLockedToGrid = true;
2796d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
2797482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        /**
2798ec40b2b90c649be3b513af2ba174db56b54b64f6Adam Cohen         * Indicates that this item should use the full extents of its parent.
2799ec40b2b90c649be3b513af2ba174db56b54b64f6Adam Cohen         */
2800ec40b2b90c649be3b513af2ba174db56b54b64f6Adam Cohen        public boolean isFullscreen = false;
2801ec40b2b90c649be3b513af2ba174db56b54b64f6Adam Cohen
2802ec40b2b90c649be3b513af2ba174db56b54b64f6Adam Cohen        /**
2803482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         * Indicates whether this item can be reordered. Always true except in the case of the
2804482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         * the AllApps button.
2805482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         */
2806482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        public boolean canReorder = true;
2807482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
280831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // X coordinate of the view in the layout.
280931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        @ViewDebug.ExportedProperty
281031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int x;
281131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // Y coordinate of the view in the layout.
281231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        @ViewDebug.ExportedProperty
281331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int y;
281431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
281584f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy        boolean dropped;
2816fcb9e7144e58614f5ae0e9b272fb7ce040848c67Romain Guy
281731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public LayoutParams(Context c, AttributeSet attrs) {
281831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            super(c, attrs);
281931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            cellHSpan = 1;
282031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            cellVSpan = 1;
282131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
282231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
282331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public LayoutParams(ViewGroup.LayoutParams source) {
282431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            super(source);
282531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            cellHSpan = 1;
282631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            cellVSpan = 1;
282731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
2828aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
2829aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        public LayoutParams(LayoutParams source) {
2830aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            super(source);
2831aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            this.cellX = source.cellX;
2832aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            this.cellY = source.cellY;
2833aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            this.cellHSpan = source.cellHSpan;
2834aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            this.cellVSpan = source.cellVSpan;
2835aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        }
2836aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
283731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public LayoutParams(int cellX, int cellY, int cellHSpan, int cellVSpan) {
28388f19cdd62f6e2be05e3890916eabd11317ae1bc2Romain Guy            super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
283931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            this.cellX = cellX;
284031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            this.cellY = cellY;
284131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            this.cellHSpan = cellHSpan;
284231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            this.cellVSpan = cellVSpan;
284331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
284431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
28452374abfda3e53f84e005df8923170308e4df8c03Adam Cohen        public void setup(int cellWidth, int cellHeight, int widthGap, int heightGap,
28462374abfda3e53f84e005df8923170308e4df8c03Adam Cohen                boolean invertHorizontally, int colCount) {
2847d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            if (isLockedToGrid) {
2848d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                final int myCellHSpan = cellHSpan;
2849d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                final int myCellVSpan = cellVSpan;
28502374abfda3e53f84e005df8923170308e4df8c03Adam Cohen                int myCellX = useTmpCoords ? tmpCellX : cellX;
28512374abfda3e53f84e005df8923170308e4df8c03Adam Cohen                int myCellY = useTmpCoords ? tmpCellY : cellY;
28522374abfda3e53f84e005df8923170308e4df8c03Adam Cohen
28532374abfda3e53f84e005df8923170308e4df8c03Adam Cohen                if (invertHorizontally) {
28542374abfda3e53f84e005df8923170308e4df8c03Adam Cohen                    myCellX = colCount - myCellX - cellHSpan;
28552374abfda3e53f84e005df8923170308e4df8c03Adam Cohen                }
28561b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen
2857d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                width = myCellHSpan * cellWidth + ((myCellHSpan - 1) * widthGap) -
2858d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                        leftMargin - rightMargin;
2859d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                height = myCellVSpan * cellHeight + ((myCellVSpan - 1) * heightGap) -
2860d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                        topMargin - bottomMargin;
2861eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                x = (int) (myCellX * (cellWidth + widthGap) + leftMargin);
2862eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                y = (int) (myCellY * (cellHeight + heightGap) + topMargin);
2863d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            }
2864d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        }
2865d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
2866aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        public String toString() {
2867aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            return "(" + this.cellX + ", " + this.cellY + ")";
2868aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        }
28697f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
28707f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public void setWidth(int width) {
28717f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            this.width = width;
28727f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
28737f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
28747f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public int getWidth() {
28757f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            return width;
28767f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
28777f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
28787f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public void setHeight(int height) {
28797f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            this.height = height;
28807f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
28817f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
28827f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public int getHeight() {
28837f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            return height;
28847f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
28857f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
28867f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public void setX(int x) {
28877f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            this.x = x;
28887f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
28897f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
28907f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public int getX() {
28917f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            return x;
28927f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
28937f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
28947f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public void setY(int y) {
28957f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            this.y = y;
28967f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
28977f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
28987f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public int getY() {
28997f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            return y;
29007f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
290131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
290231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
29030280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    // This class stores info for two purposes:
29040280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    // 1. When dragging items (mDragInfo in Workspace), we store the View, its cellX & cellY,
29050280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    //    its spanX, spanY, and the screen it is on
29060280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    // 2. When long clicking on an empty cell in a CellLayout, we save information about the
29070280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    //    cellX and cellY coordinates and which page was clicked. We then set this as a tag on
29080280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    //    the CellLayout that was long clicked
290983a8f042adda926489494dff217c15ab696139b4Sunny Goyal    public static final class CellInfo {
291031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        View cell;
2911a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka        int cellX = -1;
2912a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka        int cellY = -1;
291331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int spanX;
291431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int spanY;
2915dcd297f05a866e07090d6e2af8fb4b15f28cb555Adam Cohen        long screenId;
29163d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        long container;
291731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
291883a8f042adda926489494dff217c15ab696139b4Sunny Goyal        public CellInfo(View v, ItemInfo info) {
2919e0aaa0d3de0eedf5501fee762e0d8279a9e3bc3cAdam Cohen            cell = v;
2920e0aaa0d3de0eedf5501fee762e0d8279a9e3bc3cAdam Cohen            cellX = info.cellX;
2921e0aaa0d3de0eedf5501fee762e0d8279a9e3bc3cAdam Cohen            cellY = info.cellY;
2922e0aaa0d3de0eedf5501fee762e0d8279a9e3bc3cAdam Cohen            spanX = info.spanX;
2923e0aaa0d3de0eedf5501fee762e0d8279a9e3bc3cAdam Cohen            spanY = info.spanY;
2924e0aaa0d3de0eedf5501fee762e0d8279a9e3bc3cAdam Cohen            screenId = info.screenId;
2925e0aaa0d3de0eedf5501fee762e0d8279a9e3bc3cAdam Cohen            container = info.container;
2926e0aaa0d3de0eedf5501fee762e0d8279a9e3bc3cAdam Cohen        }
2927e0aaa0d3de0eedf5501fee762e0d8279a9e3bc3cAdam Cohen
292831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        @Override
292931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public String toString() {
2930aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            return "Cell[view=" + (cell == null ? "null" : cell.getClass())
2931aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung                    + ", x=" + cellX + ", y=" + cellY + "]";
293231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
293331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
2934d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka
2935a911672f45900fc0ed746e0d84c43c6e5ad89b6aSunny Goyal    public boolean findVacantCell(int spanX, int spanY, int[] outXY) {
2936a911672f45900fc0ed746e0d84c43c6e5ad89b6aSunny Goyal        return Utilities.findVacantCell(outXY, spanX, spanY, mCountX, mCountY, mOccupied);
2937a911672f45900fc0ed746e0d84c43c6e5ad89b6aSunny Goyal    }
29389ca9c1316da8382c1f663973072731033b5e533aSunny Goyal
29399ca9c1316da8382c1f663973072731033b5e533aSunny Goyal    public boolean isRegionVacant(int x, int y, int spanX, int spanY) {
29409ca9c1316da8382c1f663973072731033b5e533aSunny Goyal        int x2 = x + spanX - 1;
29419ca9c1316da8382c1f663973072731033b5e533aSunny Goyal        int y2 = y + spanY - 1;
29429ca9c1316da8382c1f663973072731033b5e533aSunny Goyal        if (x < 0 || y < 0 || x2 >= mCountX || y2 >= mCountY) {
29439ca9c1316da8382c1f663973072731033b5e533aSunny Goyal            return false;
29449ca9c1316da8382c1f663973072731033b5e533aSunny Goyal        }
29459ca9c1316da8382c1f663973072731033b5e533aSunny Goyal        for (int i = x; i <= x2; i++) {
29469ca9c1316da8382c1f663973072731033b5e533aSunny Goyal            for (int j = y; j <= y2; j++) {
29479ca9c1316da8382c1f663973072731033b5e533aSunny Goyal                if (mOccupied[i][j]) {
29489ca9c1316da8382c1f663973072731033b5e533aSunny Goyal                    return false;
29499ca9c1316da8382c1f663973072731033b5e533aSunny Goyal                }
29509ca9c1316da8382c1f663973072731033b5e533aSunny Goyal            }
29519ca9c1316da8382c1f663973072731033b5e533aSunny Goyal        }
29529ca9c1316da8382c1f663973072731033b5e533aSunny Goyal
29539ca9c1316da8382c1f663973072731033b5e533aSunny Goyal        return true;
29549ca9c1316da8382c1f663973072731033b5e533aSunny Goyal    }
295531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project}
2956