CellLayout.java revision a3d30adbfd4f013260f1f5ba3a56bc9bb4a11717
131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project/*
231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project *
431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * you may not use this file except in compliance with the License.
631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * You may obtain a copy of the License at
731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project *
831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project *
1031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
1131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
1231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * See the License for the specific language governing permissions and
1431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * limitations under the License.
1531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */
1631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
17a5902524d4403885eb4c50360bf3465c6be796efJoe Onoratopackage com.android.launcher2;
1831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
194be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onoratoimport android.animation.Animator;
204be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onoratoimport android.animation.AnimatorListenerAdapter;
2100397b1d9233409d9d6b233b077ae12d09768ce8Chet Haaseimport android.animation.TimeInterpolator;
22de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroyimport android.animation.ValueAnimator;
23de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroyimport android.animation.ValueAnimator.AnimatorUpdateListener;
2431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.content.Context;
2579e56263dbcbe85dc434df372bc6e6730aa13477Joe Onoratoimport android.content.res.Resources;
26aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chungimport android.content.res.TypedArray;
274be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onoratoimport android.graphics.Bitmap;
28aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chungimport android.graphics.Canvas;
290dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynnimport android.graphics.Color;
304be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onoratoimport android.graphics.Paint;
31de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroyimport android.graphics.Point;
32de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroyimport android.graphics.PointF;
33b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohenimport android.graphics.PorterDuff;
34b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohenimport android.graphics.PorterDuffXfermode;
3531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.graphics.Rect;
36482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohenimport android.graphics.drawable.ColorDrawable;
376569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroyimport android.graphics.drawable.Drawable;
38b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohenimport android.graphics.drawable.NinePatchDrawable;
3931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.util.AttributeSet;
404be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onoratoimport android.util.Log;
4131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.MotionEvent;
4231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.View;
4331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.ViewDebug;
4431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.ViewGroup;
45aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chungimport android.view.animation.Animation;
46150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chungimport android.view.animation.DecelerateInterpolator;
47aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chungimport android.view.animation.LayoutAnimationController;
4831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
496639687cd67bab1aeef2a75e5c6bc458b20dc082Adam Cohenimport com.android.launcher.R;
5069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohenimport com.android.launcher2.FolderIcon.FolderRingAnimator;
518e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy
5269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohenimport java.util.ArrayList;
53c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohenimport java.util.Arrays;
54bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohenimport java.util.HashMap;
55d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohenimport java.util.Stack;
56c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen
57bdb5c5342adc550559fd723af461e53248f2fba8Michael Jurkapublic class CellLayout extends ViewGroup {
58aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung    static final String TAG = "CellLayout";
59aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
602acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen    private Launcher mLauncher;
6131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private int mCellWidth;
6231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private int mCellHeight;
63aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
64d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen    private int mCountX;
65d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen    private int mCountY;
6631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
67234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen    private int mOriginalWidthGap;
68234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen    private int mOriginalHeightGap;
6931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private int mWidthGap;
7031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private int mHeightGap;
714b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung    private int mMaxGap;
72ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen    private boolean mScrollingTransformsDirty = false;
7331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
7431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private final Rect mRect = new Rect();
7531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private final CellInfo mCellInfo = new CellInfo();
76aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
77de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy    // These are temporary variables to prevent having to allocate a new object just to
78de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy    // return an (x, y) value from helper functions. Do NOT use them to maintain other state.
790be025d64c1f84138fe430a58875886e66aae767Winson Chung    private final int[] mTmpXY = new int[2];
80de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy    private final int[] mTmpPoint = new int[2];
81de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy    private final PointF mTmpPointF = new PointF();
8269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen    int[] mTempLocation = new int[2];
836569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
8431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    boolean[][] mOccupied;
85482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    boolean[][] mTmpOccupied;
86d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka    private boolean mLastDownOnOccupiedCell = false;
8731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
88dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    private OnTouchListener mInterceptTouchListener;
89dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka
9069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen    private ArrayList<FolderRingAnimator> mFolderOuterRings = new ArrayList<FolderRingAnimator>();
91c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen    private int[] mFolderLeaveBehindCell = {-1, -1};
9269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
93b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    private int mForegroundAlpha = 0;
945f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka    private float mBackgroundAlpha;
951b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen    private float mBackgroundAlphaMultiplier = 1.0f;
96f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen
9733945b21544bc98381df17726a3537c292d8c985Michael Jurka    private Drawable mNormalBackground;
9833945b21544bc98381df17726a3537c292d8c985Michael Jurka    private Drawable mActiveGlowBackground;
99b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    private Drawable mOverScrollForegroundDrawable;
100b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    private Drawable mOverScrollLeft;
101b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    private Drawable mOverScrollRight;
10218014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka    private Rect mBackgroundRect;
103b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    private Rect mForegroundRect;
104b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    private int mForegroundPadding;
10533945b21544bc98381df17726a3537c292d8c985Michael Jurka
10633945b21544bc98381df17726a3537c292d8c985Michael Jurka    // If we're actively dragging something over this screen, mIsDragOverlapping is true
10733945b21544bc98381df17726a3537c292d8c985Michael Jurka    private boolean mIsDragOverlapping = false;
108de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy    private final Point mDragCenter = new Point();
1096569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
110150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung    // These arrays are used to implement the drag visualization on x-large screens.
1114be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato    // They are used as circular arrays, indexed by mDragOutlineCurrent.
112d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    private Rect[] mDragOutlines = new Rect[4];
113472b281d5cb4f5660df981a6c912266b9f5703feChet Haase    private float[] mDragOutlineAlphas = new float[mDragOutlines.length];
1144be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato    private InterruptibleInOutAnimator[] mDragOutlineAnims =
1154be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            new InterruptibleInOutAnimator[mDragOutlines.length];
116150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung
117150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung    // Used as an index into the above 3 arrays; indicates which is the most current value.
1184be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato    private int mDragOutlineCurrent = 0;
1198e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy    private final Paint mDragOutlinePaint = new Paint();
120150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung
12196864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy    private BubbleTextView mPressedOrFocusedIcon;
12296864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy
123482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private HashMap<CellLayout.LayoutParams, Animator> mReorderAnimators = new
124482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            HashMap<CellLayout.LayoutParams, Animator>();
12519f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private HashMap<View, ReorderHintAnimation>
12619f3792523fe2d55ea791a9286398a6120920690Adam Cohen            mShakeAnimators = new HashMap<View, ReorderHintAnimation>();
12719f3792523fe2d55ea791a9286398a6120920690Adam Cohen
12819f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private boolean mItemPlacementDirty = false;
129bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen
1306569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    // When a drag operation is in progress, holds the nearest cell to the touch point
1316569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    private final int[] mDragCell = new int[2];
13231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
1334be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato    private boolean mDragging = false;
1344be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato
135ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy    private TimeInterpolator mEaseOutInterpolator;
136a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka    private ShortcutAndWidgetContainer mShortcutsAndWidgets;
137ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy
1380dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn    private boolean mIsHotseat = false;
139eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung    private float mChildScale = 1f;
140eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung    private float mHotseatChildScale = 1f;
1410dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn
142482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public static final int MODE_DRAG_OVER = 0;
143482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public static final int MODE_ON_DROP = 1;
144482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public static final int MODE_ON_DROP_EXTERNAL = 2;
145482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public static final int MODE_ACCEPT_DROP = 3;
14619f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private static final boolean DESTRUCTIVE_REORDER = false;
147482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private static final boolean DEBUG_VISUALIZE_OCCUPIED = false;
148482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
149a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen    static final int LANDSCAPE = 0;
150a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen    static final int PORTRAIT = 1;
151a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen
15219f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private static final float REORDER_HINT_MAGNITUDE = 0.27f;
15319f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private static final int REORDER_ANIMATION_DURATION = 150;
15419f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private float mReorderHintAnimationMagnitude;
15519f3792523fe2d55ea791a9286398a6120920690Adam Cohen
156482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private ArrayList<View> mIntersectingViews = new ArrayList<View>();
157482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private Rect mOccupiedRect = new Rect();
158482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private int[] mDirectionVector = new int[2];
15919f3792523fe2d55ea791a9286398a6120920690Adam Cohen    int[] mPreviousReorderDirection = new int[2];
160b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen    private static final int INVALID_DIRECTION = -100;
161c6cc61d45836e4081920883cc4d448ccb0bb8417Adam Cohen    private DropTarget.DragEnforcer mDragEnforcer;
162482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1638a0bff5e35f63321178bbf777ec24d42544866b3Romain Guy    private final static PorterDuffXfermode sAddBlendMode =
1648a0bff5e35f63321178bbf777ec24d42544866b3Romain Guy            new PorterDuffXfermode(PorterDuff.Mode.ADD);
1658a0bff5e35f63321178bbf777ec24d42544866b3Romain Guy
16631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public CellLayout(Context context) {
16731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        this(context, null);
16831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
16931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
17031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public CellLayout(Context context, AttributeSet attrs) {
17131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        this(context, attrs, 0);
17231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
17331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
17431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public CellLayout(Context context, AttributeSet attrs, int defStyle) {
17531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        super(context, attrs, defStyle);
1768b805b17158886035b38261eb611d8641701ae43Michael Jurka        mDragEnforcer = new DropTarget.DragEnforcer(context);
1776569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
1786569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        // A ViewGroup usually does not draw, but CellLayout needs to draw a rectangle to show
1796569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        // the user where a dragged item will land when dropped.
1806569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        setWillNotDraw(false);
1812acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen        mLauncher = (Launcher) context;
182a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka
18331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CellLayout, defStyle, 0);
18431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
185f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        mCellWidth = a.getDimensionPixelSize(R.styleable.CellLayout_cellWidth, 10);
186f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        mCellHeight = a.getDimensionPixelSize(R.styleable.CellLayout_cellHeight, 10);
187234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen        mWidthGap = mOriginalWidthGap = a.getDimensionPixelSize(R.styleable.CellLayout_widthGap, 0);
188234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen        mHeightGap = mOriginalHeightGap = a.getDimensionPixelSize(R.styleable.CellLayout_heightGap, 0);
1894b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        mMaxGap = a.getDimensionPixelSize(R.styleable.CellLayout_maxGap, 0);
190d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        mCountX = LauncherModel.getCellCountX();
191d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        mCountY = LauncherModel.getCellCountY();
1920280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        mOccupied = new boolean[mCountX][mCountY];
193482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        mTmpOccupied = new boolean[mCountX][mCountY];
1945b53f29f809a0dad4a1e0717ba610ce737ee0f43Adam Cohen        mPreviousReorderDirection[0] = INVALID_DIRECTION;
1955b53f29f809a0dad4a1e0717ba610ce737ee0f43Adam Cohen        mPreviousReorderDirection[1] = INVALID_DIRECTION;
19631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
19731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        a.recycle();
19831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
19931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        setAlwaysDrawnWithCacheEnabled(false);
20031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
201046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        final Resources res = getResources();
202de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy
203967289b6d5fec77f5c381d11ffb2319f3bb5e737Winson Chung        mNormalBackground = res.getDrawable(R.drawable.homescreen_blue_normal_holo);
204dea74b7d12b0fcd50bfdb4274f9867ba76d75238Winson Chung        mActiveGlowBackground = res.getDrawable(R.drawable.homescreen_blue_strong_holo);
205b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung
206b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        mOverScrollLeft = res.getDrawable(R.drawable.overscroll_glow_left);
207b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        mOverScrollRight = res.getDrawable(R.drawable.overscroll_glow_right);
208b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        mForegroundPadding =
209b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen                res.getDimensionPixelSize(R.dimen.workspace_overscroll_drawable_padding);
210b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung
21119f3792523fe2d55ea791a9286398a6120920690Adam Cohen        mReorderHintAnimationMagnitude = (REORDER_HINT_MAGNITUDE *
21219f3792523fe2d55ea791a9286398a6120920690Adam Cohen                res.getDimensionPixelSize(R.dimen.app_icon_size));
21319f3792523fe2d55ea791a9286398a6120920690Adam Cohen
214b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung        mNormalBackground.setFilterBitmap(true);
215b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung        mActiveGlowBackground.setFilterBitmap(true);
216de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy
217eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung        int iconScale = res.getInteger(R.integer.app_icon_scale_percent);
218eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung        if (iconScale >= 0) {
219eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung            mChildScale = iconScale / 100f;
220eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung        }
221eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung        int hotseatIconScale = res.getInteger(R.integer.app_icon_hotseat_scale_percent);
222eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung        if (hotseatIconScale >= 0) {
223eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung            mHotseatChildScale = hotseatIconScale / 100f;
224eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung        }
2250dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn
226046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        // Initialize the data structures used for the drag visualization.
227150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung
228ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy        mEaseOutInterpolator = new DecelerateInterpolator(2.5f); // Quint ease out
229de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy
230046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy
231b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung        mDragCell[0] = mDragCell[1] = -1;
2324be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        for (int i = 0; i < mDragOutlines.length; i++) {
233d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            mDragOutlines[i] = new Rect(-1, -1, -1, -1);
234046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        }
235046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy
236046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        // When dragging things around the home screens, we show a green outline of
237046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        // where the item will land. The outlines gradually fade out, leaving a trail
238046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        // behind the drag path.
239046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        // Set up all the animations that are used to implement this fading.
240046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy        final int duration = res.getInteger(R.integer.config_dragOutlineFadeTime);
241472b281d5cb4f5660df981a6c912266b9f5703feChet Haase        final float fromAlphaValue = 0;
242472b281d5cb4f5660df981a6c912266b9f5703feChet Haase        final float toAlphaValue = (float)res.getInteger(R.integer.config_dragOutlineMaxAlpha);
2434be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato
2448e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy        Arrays.fill(mDragOutlineAlphas, fromAlphaValue);
2454be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato
2464be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        for (int i = 0; i < mDragOutlineAnims.length; i++) {
247046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy            final InterruptibleInOutAnimator anim =
248046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy                new InterruptibleInOutAnimator(duration, fromAlphaValue, toAlphaValue);
249ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy            anim.getAnimator().setInterpolator(mEaseOutInterpolator);
250046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy            final int thisIndex = i;
251472b281d5cb4f5660df981a6c912266b9f5703feChet Haase            anim.getAnimator().addUpdateListener(new AnimatorUpdateListener() {
252de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                public void onAnimationUpdate(ValueAnimator animation) {
2534be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    final Bitmap outline = (Bitmap)anim.getTag();
2544be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato
2554be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    // If an animation is started and then stopped very quickly, we can still
2564be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    // get spurious updates we've cleared the tag. Guard against this.
2574be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    if (outline == null) {
2583a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka                        @SuppressWarnings("all") // suppress dead code warning
2593a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka                        final boolean debug = false;
2603a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka                        if (debug) {
261fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy                            Object val = animation.getAnimatedValue();
262fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy                            Log.d(TAG, "anim " + thisIndex + " update: " + val +
263fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy                                     ", isStopped " + anim.isStopped());
264fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy                        }
2654be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                        // Try to prevent it from continuing to run
2664be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                        animation.cancel();
2674be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    } else {
268472b281d5cb4f5660df981a6c912266b9f5703feChet Haase                        mDragOutlineAlphas[thisIndex] = (Float) animation.getAnimatedValue();
269d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        CellLayout.this.invalidate(mDragOutlines[thisIndex]);
2704be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    }
271de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy                }
272de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy            });
2734be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            // The animation holds a reference to the drag outline bitmap as long is it's
2744be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            // running. This way the bitmap can be GCed when the animations are complete.
275472b281d5cb4f5660df981a6c912266b9f5703feChet Haase            anim.getAnimator().addListener(new AnimatorListenerAdapter() {
2763c4c20fbe682cb4b3ef94f09afe0af09171583f3Michael Jurka                @Override
2774be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                public void onAnimationEnd(Animator animation) {
278472b281d5cb4f5660df981a6c912266b9f5703feChet Haase                    if ((Float) ((ValueAnimator) animation).getAnimatedValue() == 0f) {
2794be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                        anim.setTag(null);
2804be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                    }
2814be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                }
2824be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            });
2834be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            mDragOutlineAnims[i] = anim;
284de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy        }
285ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy
28618014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka        mBackgroundRect = new Rect();
287b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        mForegroundRect = new Rect();
288bea15195346bab3c52b0156e92f2b71f0811b210Michael Jurka
289a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets = new ShortcutAndWidgetContainer(context);
290a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.setCellDimensions(mCellWidth, mCellHeight, mWidthGap, mHeightGap);
291a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        addView(mShortcutsAndWidgets);
29218014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka    }
29318014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka
294f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka    static int widthInPortrait(Resources r, int numCells) {
295f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka        // We use this method from Workspace to figure out how many rows/columns Launcher should
296f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka        // have. We ignore the left/right padding on CellLayout because it turns out in our design
297f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka        // the padding extends outside the visible screen size, but it looked fine anyway.
298f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka        int cellWidth = r.getDimensionPixelSize(R.dimen.workspace_cell_width);
2994b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        int minGap = Math.min(r.getDimensionPixelSize(R.dimen.workspace_width_gap),
3004b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                r.getDimensionPixelSize(R.dimen.workspace_height_gap));
301f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka
3024b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        return  minGap * (numCells - 1) + cellWidth * numCells;
303f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka    }
304f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka
305f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka    static int heightInLandscape(Resources r, int numCells) {
306f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka        // We use this method from Workspace to figure out how many rows/columns Launcher should
307f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka        // have. We ignore the left/right padding on CellLayout because it turns out in our design
308f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka        // the padding extends outside the visible screen size, but it looked fine anyway.
309f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka        int cellHeight = r.getDimensionPixelSize(R.dimen.workspace_cell_height);
3104b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        int minGap = Math.min(r.getDimensionPixelSize(R.dimen.workspace_width_gap),
3114b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                r.getDimensionPixelSize(R.dimen.workspace_height_gap));
312f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka
3134b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        return minGap * (numCells - 1) + cellHeight * numCells;
314f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka    }
315f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka
3162801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    public void enableHardwareLayers() {
317a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.enableHardwareLayers();
3182801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    }
3192801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
3202801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    public void setGridSize(int x, int y) {
3212801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        mCountX = x;
3222801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        mCountY = y;
3232801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        mOccupied = new boolean[mCountX][mCountY];
324482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        mTmpOccupied = new boolean[mCountX][mCountY];
3257fbec10b36818f100b631f3d73fe1ad5360975aaAdam Cohen        mTempRectStack.clear();
32676fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen        requestLayout();
3272801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    }
3282801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
32996864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy    private void invalidateBubbleTextView(BubbleTextView icon) {
33096864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        final int padding = icon.getPressedOrFocusedBackgroundPadding();
3314b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        invalidate(icon.getLeft() + getPaddingLeft() - padding,
3324b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                icon.getTop() + getPaddingTop() - padding,
3334b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                icon.getRight() + getPaddingLeft() + padding,
3344b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                icon.getBottom() + getPaddingTop() + padding);
33596864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy    }
33696864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy
337b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    void setOverScrollAmount(float r, boolean left) {
338b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        if (left && mOverScrollForegroundDrawable != mOverScrollLeft) {
339b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen            mOverScrollForegroundDrawable = mOverScrollLeft;
340b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        } else if (!left && mOverScrollForegroundDrawable != mOverScrollRight) {
341b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen            mOverScrollForegroundDrawable = mOverScrollRight;
342b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        }
343b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen
344b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        mForegroundAlpha = (int) Math.round((r * 255));
345b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        mOverScrollForegroundDrawable.setAlpha(mForegroundAlpha);
346b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        invalidate();
347b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    }
348b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen
34996864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy    void setPressedOrFocusedIcon(BubbleTextView icon) {
35096864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        // We draw the pressed or focused BubbleTextView's background in CellLayout because it
35196864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        // requires an expanded clip rect (due to the glow's blur radius)
35296864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        BubbleTextView oldIcon = mPressedOrFocusedIcon;
35396864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        mPressedOrFocusedIcon = icon;
35496864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        if (oldIcon != null) {
35596864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy            invalidateBubbleTextView(oldIcon);
35696864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        }
35796864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        if (mPressedOrFocusedIcon != null) {
35896864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy            invalidateBubbleTextView(mPressedOrFocusedIcon);
35996864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        }
36096864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy    }
36196864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy
36233945b21544bc98381df17726a3537c292d8c985Michael Jurka    void setIsDragOverlapping(boolean isDragOverlapping) {
36333945b21544bc98381df17726a3537c292d8c985Michael Jurka        if (mIsDragOverlapping != isDragOverlapping) {
36433945b21544bc98381df17726a3537c292d8c985Michael Jurka            mIsDragOverlapping = isDragOverlapping;
36533945b21544bc98381df17726a3537c292d8c985Michael Jurka            invalidate();
36633945b21544bc98381df17726a3537c292d8c985Michael Jurka        }
36733945b21544bc98381df17726a3537c292d8c985Michael Jurka    }
36833945b21544bc98381df17726a3537c292d8c985Michael Jurka
36933945b21544bc98381df17726a3537c292d8c985Michael Jurka    boolean getIsDragOverlapping() {
37033945b21544bc98381df17726a3537c292d8c985Michael Jurka        return mIsDragOverlapping;
37133945b21544bc98381df17726a3537c292d8c985Michael Jurka    }
37233945b21544bc98381df17726a3537c292d8c985Michael Jurka
373ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen    protected void setOverscrollTransformsDirty(boolean dirty) {
374ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen        mScrollingTransformsDirty = dirty;
375ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen    }
376ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen
377ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen    protected void resetOverscrollTransforms() {
378ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen        if (mScrollingTransformsDirty) {
379ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            setOverscrollTransformsDirty(false);
380ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            setTranslationX(0);
381ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            setRotationY(0);
382ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            // It doesn't matter if we pass true or false here, the important thing is that we
383ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            // pass 0, which results in the overscroll drawable not being drawn any more.
384ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            setOverScrollAmount(0, false);
385ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            setPivotX(getMeasuredWidth() / 2);
386ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen            setPivotY(getMeasuredHeight() / 2);
387ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen        }
388ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen    }
389ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen
390a6abce8464b57ce91e8f083951ad263370fc2da8Romain Guy    @Override
3911262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy    protected void onDraw(Canvas canvas) {
3923e7c7634531302271270c8cf418abc959d621cbcMichael Jurka        // When we're large, we are either drawn in a "hover" state (ie when dragging an item to
3933e7c7634531302271270c8cf418abc959d621cbcMichael Jurka        // a neighboring page) or with just a normal background (if backgroundAlpha > 0.0f)
3943e7c7634531302271270c8cf418abc959d621cbcMichael Jurka        // When we're small, we are either drawn normally or in the "accepts drops" state (during
3953e7c7634531302271270c8cf418abc959d621cbcMichael Jurka        // a drag). However, we also drag the mini hover background *over* one of those two
3963e7c7634531302271270c8cf418abc959d621cbcMichael Jurka        // backgrounds
397b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung        if (mBackgroundAlpha > 0.0f) {
398f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen            Drawable bg;
39933945b21544bc98381df17726a3537c292d8c985Michael Jurka
40033945b21544bc98381df17726a3537c292d8c985Michael Jurka            if (mIsDragOverlapping) {
40133945b21544bc98381df17726a3537c292d8c985Michael Jurka                // In the mini case, we draw the active_glow bg *over* the active background
402bdf78559f223ac11e01e3311edd5a48a80383e1eMichael Jurka                bg = mActiveGlowBackground;
403f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen            } else {
404bdf78559f223ac11e01e3311edd5a48a80383e1eMichael Jurka                bg = mNormalBackground;
405f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen            }
40633945b21544bc98381df17726a3537c292d8c985Michael Jurka
40733945b21544bc98381df17726a3537c292d8c985Michael Jurka            bg.setAlpha((int) (mBackgroundAlpha * mBackgroundAlphaMultiplier * 255));
40833945b21544bc98381df17726a3537c292d8c985Michael Jurka            bg.setBounds(mBackgroundRect);
40933945b21544bc98381df17726a3537c292d8c985Michael Jurka            bg.draw(canvas);
410a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka        }
41131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
4128e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy        final Paint paint = mDragOutlinePaint;
4134be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        for (int i = 0; i < mDragOutlines.length; i++) {
414472b281d5cb4f5660df981a6c912266b9f5703feChet Haase            final float alpha = mDragOutlineAlphas[i];
4154be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            if (alpha > 0) {
416d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                final Rect r = mDragOutlines[i];
4174be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato                final Bitmap b = (Bitmap) mDragOutlineAnims[i].getTag();
418472b281d5cb4f5660df981a6c912266b9f5703feChet Haase                paint.setAlpha((int)(alpha + .5f));
419d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                canvas.drawBitmap(b, null, r, paint);
420150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung            }
4216569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        }
42296864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy
42396864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        // We draw the pressed or focused BubbleTextView's background in CellLayout because it
42496864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        // requires an expanded clip rect (due to the glow's blur radius)
42596864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        if (mPressedOrFocusedIcon != null) {
42696864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy            final int padding = mPressedOrFocusedIcon.getPressedOrFocusedBackgroundPadding();
42796864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy            final Bitmap b = mPressedOrFocusedIcon.getPressedOrFocusedBackground();
42896864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy            if (b != null) {
42996864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy                canvas.drawBitmap(b,
4304b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                        mPressedOrFocusedIcon.getLeft() + getPaddingLeft() - padding,
4314b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung                        mPressedOrFocusedIcon.getTop() + getPaddingTop() - padding,
43296864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy                        null);
43396864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy            }
43496864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy        }
43569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
436482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (DEBUG_VISUALIZE_OCCUPIED) {
437482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            int[] pt = new int[2];
438482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            ColorDrawable cd = new ColorDrawable(Color.RED);
439482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            cd.setBounds(0, 0, 80, 80);
440482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            for (int i = 0; i < mCountX; i++) {
441482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                for (int j = 0; j < mCountY; j++) {
442482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    if (mOccupied[i][j]) {
443482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        cellToPoint(i, j, pt);
444482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        canvas.save();
445482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        canvas.translate(pt[0], pt[1]);
446482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        cd.draw(canvas);
447482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        canvas.restore();
448482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    }
449482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                }
450482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
451482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
452482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
453850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn        int previewOffset = FolderRingAnimator.sPreviewSize;
454850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn
45569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        // The folder outer / inner ring image(s)
45669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        for (int i = 0; i < mFolderOuterRings.size(); i++) {
45769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            FolderRingAnimator fra = mFolderOuterRings.get(i);
45869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
45969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            // Draw outer ring
46069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            Drawable d = FolderRingAnimator.sSharedOuterRingDrawable;
46169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            int width = (int) fra.getOuterRingSize();
46269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            int height = width;
46369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            cellToPoint(fra.mCellX, fra.mCellY, mTempLocation);
46469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
46569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            int centerX = mTempLocation[0] + mCellWidth / 2;
466850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn            int centerY = mTempLocation[1] + previewOffset / 2;
46769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
46869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            canvas.save();
46969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            canvas.translate(centerX - width / 2, centerY - height / 2);
47069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            d.setBounds(0, 0, width, height);
47169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            d.draw(canvas);
47269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            canvas.restore();
47369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
47469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            // Draw inner ring
47569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            d = FolderRingAnimator.sSharedInnerRingDrawable;
47669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            width = (int) fra.getInnerRingSize();
47769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            height = width;
47869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            cellToPoint(fra.mCellX, fra.mCellY, mTempLocation);
47969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
48069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            centerX = mTempLocation[0] + mCellWidth / 2;
481850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn            centerY = mTempLocation[1] + previewOffset / 2;
48269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            canvas.save();
48369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            canvas.translate(centerX - width / 2, centerY - width / 2);
48469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            d.setBounds(0, 0, width, height);
48569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            d.draw(canvas);
48669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            canvas.restore();
48769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        }
488c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen
489c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        if (mFolderLeaveBehindCell[0] >= 0 && mFolderLeaveBehindCell[1] >= 0) {
490c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            Drawable d = FolderIcon.sSharedFolderLeaveBehind;
491c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            int width = d.getIntrinsicWidth();
492c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            int height = d.getIntrinsicHeight();
493c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen
494c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            cellToPoint(mFolderLeaveBehindCell[0], mFolderLeaveBehindCell[1], mTempLocation);
495c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            int centerX = mTempLocation[0] + mCellWidth / 2;
496850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn            int centerY = mTempLocation[1] + previewOffset / 2;
497c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen
498c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            canvas.save();
499c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            canvas.translate(centerX - width / 2, centerY - width / 2);
500c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            d.setBounds(0, 0, width, height);
501c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            d.draw(canvas);
502c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen            canvas.restore();
503c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        }
50469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen    }
50569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
506b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    @Override
507b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    protected void dispatchDraw(Canvas canvas) {
508b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        super.dispatchDraw(canvas);
509b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        if (mForegroundAlpha > 0) {
510b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen            mOverScrollForegroundDrawable.setBounds(mForegroundRect);
511b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen            Paint p = ((NinePatchDrawable) mOverScrollForegroundDrawable).getPaint();
5128a0bff5e35f63321178bbf777ec24d42544866b3Romain Guy            p.setXfermode(sAddBlendMode);
513b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen            mOverScrollForegroundDrawable.draw(canvas);
514b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen            p.setXfermode(null);
515b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        }
516b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen    }
517b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen
51869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen    public void showFolderAccept(FolderRingAnimator fra) {
51969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        mFolderOuterRings.add(fra);
52069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen    }
52169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen
52269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen    public void hideFolderAccept(FolderRingAnimator fra) {
52369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        if (mFolderOuterRings.contains(fra)) {
52469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen            mFolderOuterRings.remove(fra);
52569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        }
52669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen        invalidate();
5276569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    }
5286569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
529c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen    public void setFolderLeaveBehindCell(int x, int y) {
530c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        mFolderLeaveBehindCell[0] = x;
531c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        mFolderLeaveBehindCell[1] = y;
532c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        invalidate();
533c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen    }
534c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen
535c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen    public void clearFolderLeaveBehind() {
536c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        mFolderLeaveBehindCell[0] = -1;
537c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        mFolderLeaveBehindCell[1] = -1;
538c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen        invalidate();
539c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen    }
540c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen
5416569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    @Override
542e6235dd225404239b55c459245543f3302326112Michael Jurka    public boolean shouldDelayChildPressedState() {
543e6235dd225404239b55c459245543f3302326112Michael Jurka        return false;
544e6235dd225404239b55c459245543f3302326112Michael Jurka    }
545e6235dd225404239b55c459245543f3302326112Michael Jurka
546e6235dd225404239b55c459245543f3302326112Michael Jurka    @Override
54783f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey    public void cancelLongPress() {
54883f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey        super.cancelLongPress();
54983f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey
55083f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey        // Cancel long press for all children
55183f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey        final int count = getChildCount();
55283f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey        for (int i = 0; i < count; i++) {
55383f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey            final View child = getChildAt(i);
55483f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey            child.cancelLongPress();
55583f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey        }
55683f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey    }
55783f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey
558dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    public void setOnInterceptTouchListener(View.OnTouchListener listener) {
559dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka        mInterceptTouchListener = listener;
560dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    }
561dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka
56231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    int getCountX() {
563d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        return mCountX;
56431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
56531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
56631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    int getCountY() {
567d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        return mCountY;
56831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
56931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
5700dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn    public void setIsHotseat(boolean isHotseat) {
5710dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn        mIsHotseat = isHotseat;
5720dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn    }
5730dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn
574eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung    public float getChildrenScale() {
575eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung        return mIsHotseat ? mHotseatChildScale : mChildScale;
576eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung    }
577eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung
5780dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn
579850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn    private void scaleChild(BubbleTextView bubbleChild, float scale) {
580bc239a15464f543a41b960b946aa77258454efafAndrew Flynn        // If we haven't measured the child yet, do it now
581bc239a15464f543a41b960b946aa77258454efafAndrew Flynn        // (this happens if we're being dropped from all-apps
582bc239a15464f543a41b960b946aa77258454efafAndrew Flynn        if (bubbleChild.getLayoutParams() instanceof LayoutParams &&
583bc239a15464f543a41b960b946aa77258454efafAndrew Flynn                (bubbleChild.getMeasuredWidth() | bubbleChild.getMeasuredHeight()) == 0) {
584a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            getShortcutsAndWidgets().measureChild(bubbleChild);
585bc239a15464f543a41b960b946aa77258454efafAndrew Flynn        }
586bc239a15464f543a41b960b946aa77258454efafAndrew Flynn
587bc239a15464f543a41b960b946aa77258454efafAndrew Flynn        bubbleChild.setScaleX(scale);
588bc239a15464f543a41b960b946aa77258454efafAndrew Flynn        bubbleChild.setScaleY(scale);
589bc239a15464f543a41b960b946aa77258454efafAndrew Flynn    }
590bc239a15464f543a41b960b946aa77258454efafAndrew Flynn
591bc239a15464f543a41b960b946aa77258454efafAndrew Flynn    private void resetChild(BubbleTextView bubbleChild) {
592bc239a15464f543a41b960b946aa77258454efafAndrew Flynn        bubbleChild.setScaleX(1f);
593bc239a15464f543a41b960b946aa77258454efafAndrew Flynn        bubbleChild.setScaleY(1f);
594bc239a15464f543a41b960b946aa77258454efafAndrew Flynn
595bc239a15464f543a41b960b946aa77258454efafAndrew Flynn        bubbleChild.setTextColor(getResources().getColor(R.color.workspace_icon_text_color));
596bc239a15464f543a41b960b946aa77258454efafAndrew Flynn    }
597bc239a15464f543a41b960b946aa77258454efafAndrew Flynn
5980dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn    public boolean addViewToCellLayout(View child, int index, int childId, LayoutParams params,
599850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn            boolean markCells) {
600aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        final LayoutParams lp = params;
601aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
6020dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn        // Hotseat icons - scale down and remove text
6030dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn        // Don't scale the all apps button
6040dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn        // scale percent set to -1 means do not scale
6050dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn        // Only scale BubbleTextViews
6060dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn        if (child instanceof BubbleTextView) {
6070dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn            BubbleTextView bubbleChild = (BubbleTextView) child;
6080dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn
609bc239a15464f543a41b960b946aa77258454efafAndrew Flynn            // Start the child with 100% scale and visible text
610bc239a15464f543a41b960b946aa77258454efafAndrew Flynn            resetChild(bubbleChild);
611bc239a15464f543a41b960b946aa77258454efafAndrew Flynn
612850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn            if (mIsHotseat && mHotseatChildScale >= 0) {
613bc239a15464f543a41b960b946aa77258454efafAndrew Flynn                // Scale/make transparent for a hotseat
614850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn                scaleChild(bubbleChild, mHotseatChildScale);
6150dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn
616bc239a15464f543a41b960b946aa77258454efafAndrew Flynn                bubbleChild.setTextColor(getResources().getColor(android.R.color.transparent));
617eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung            } else if (mChildScale >= 0) {
618bc239a15464f543a41b960b946aa77258454efafAndrew Flynn                // Else possibly still scale it if we need to for smaller icons
619850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn                scaleChild(bubbleChild, mChildScale);
6200dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn            }
6210dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn        }
6220dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn
62331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // Generate an id for each view, this assumes we have at most 256x256 cells
62431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // per workspace screen
625d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        if (lp.cellX >= 0 && lp.cellX <= mCountX - 1 && lp.cellY >= 0 && lp.cellY <= mCountY - 1) {
626aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            // If the horizontal or vertical span is set to -1, it is taken to
627aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            // mean that it spans the extent of the CellLayout
628d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen            if (lp.cellHSpan < 0) lp.cellHSpan = mCountX;
629d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen            if (lp.cellVSpan < 0) lp.cellVSpan = mCountY;
630aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
631aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            child.setId(childId);
63231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
633a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            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
656f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka    public void removeViewWithoutMarkingCells(View view) {
657a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.removeView(view);
658f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka    }
659f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka
6600280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    @Override
6610280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public void removeView(View view) {
6620280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        markCellsAsUnoccupiedForView(view);
663a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.removeView(view);
6640280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
6650280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
6660280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    @Override
6670280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public void removeViewAt(int index) {
668a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        markCellsAsUnoccupiedForView(mShortcutsAndWidgets.getChildAt(index));
669a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.removeViewAt(index);
6700280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
6710280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
6720280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    @Override
6730280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public void removeViewInLayout(View view) {
6740280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        markCellsAsUnoccupiedForView(view);
675a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.removeViewInLayout(view);
6760280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
6770280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
6780280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    @Override
6790280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public void removeViews(int start, int count) {
6800280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        for (int i = start; i < start + count; i++) {
681a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            markCellsAsUnoccupiedForView(mShortcutsAndWidgets.getChildAt(i));
6820280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        }
683a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.removeViews(start, count);
6840280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
6850280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
6860280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    @Override
6870280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    public void removeViewsInLayout(int start, int count) {
6880280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        for (int i = start; i < start + count; i++) {
689a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            markCellsAsUnoccupiedForView(mShortcutsAndWidgets.getChildAt(i));
6900280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        }
691a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.removeViewsInLayout(start, count);
692abded66084680bb31cc7ea403c88f44f79a3c884Michael Jurka    }
693abded66084680bb31cc7ea403c88f44f79a3c884Michael Jurka
69431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
69531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    protected void onAttachedToWindow() {
69631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        super.onAttachedToWindow();
69731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        mCellInfo.screen = ((ViewGroup) getParent()).indexOfChild(this);
69831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
69931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
700af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka    public void setTagToCellInfoForPoint(int touchX, int touchY) {
70131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        final CellInfo cellInfo = mCellInfo;
702eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung        Rect frame = mRect;
7038b805b17158886035b38261eb611d8641701ae43Michael Jurka        final int x = touchX + getScrollX();
7048b805b17158886035b38261eb611d8641701ae43Michael Jurka        final int y = touchY + getScrollY();
705a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        final int count = mShortcutsAndWidgets.getChildCount();
70631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
707af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka        boolean found = false;
708af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka        for (int i = count - 1; i >= 0; i--) {
709a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            final View child = mShortcutsAndWidgets.getChildAt(i);
710d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
711af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka
7121b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen            if ((child.getVisibility() == VISIBLE || child.getAnimation() != null) &&
7131b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen                    lp.isLockedToGrid) {
714af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                child.getHitRect(frame);
7150be025d64c1f84138fe430a58875886e66aae767Winson Chung
716eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                float scale = child.getScaleX();
717eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                frame = new Rect(child.getLeft(), child.getTop(), child.getRight(),
718eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                        child.getBottom());
7190be025d64c1f84138fe430a58875886e66aae767Winson Chung                // The child hit rect is relative to the CellLayoutChildren parent, so we need to
7200be025d64c1f84138fe430a58875886e66aae767Winson Chung                // offset that by this CellLayout's padding to test an (x,y) point that is relative
7210be025d64c1f84138fe430a58875886e66aae767Winson Chung                // to this view.
7228b805b17158886035b38261eb611d8641701ae43Michael Jurka                frame.offset(getPaddingLeft(), getPaddingTop());
723eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                frame.inset((int) (frame.width() * (1f - scale) / 2),
724eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                        (int) (frame.height() * (1f - scale) / 2));
7250be025d64c1f84138fe430a58875886e66aae767Winson Chung
726af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                if (frame.contains(x, y)) {
727af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                    cellInfo.cell = child;
728af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                    cellInfo.cellX = lp.cellX;
729af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                    cellInfo.cellY = lp.cellY;
730af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                    cellInfo.spanX = lp.cellHSpan;
731af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                    cellInfo.spanY = lp.cellVSpan;
732af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                    found = true;
733af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka                    break;
73431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                }
73531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            }
736af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka        }
737aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
738d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka        mLastDownOnOccupiedCell = found;
739d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka
740af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka        if (!found) {
7410be025d64c1f84138fe430a58875886e66aae767Winson Chung            final int cellXY[] = mTmpXY;
742af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka            pointToCellExact(x, y, cellXY);
74331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
744af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka            cellInfo.cell = null;
745af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka            cellInfo.cellX = cellXY[0];
746af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka            cellInfo.cellY = cellXY[1];
747af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka            cellInfo.spanX = 1;
748af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka            cellInfo.spanY = 1;
749af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka        }
750af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka        setTag(cellInfo);
751af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka    }
75231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
753af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka    @Override
754af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka    public boolean onInterceptTouchEvent(MotionEvent ev) {
755c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        // First we clear the tag to ensure that on every touch down we start with a fresh slate,
756c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        // even in the case where we return early. Not clearing here was causing bugs whereby on
757c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        // long-press we'd end up picking up an item from a previous drag operation.
758c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        final int action = ev.getAction();
759c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen
760c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        if (action == MotionEvent.ACTION_DOWN) {
761c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen            clearTagCellInfo();
762c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        }
763c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen
764dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka        if (mInterceptTouchListener != null && mInterceptTouchListener.onTouch(this, ev)) {
765dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka            return true;
766dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka        }
76731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
768af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka        if (action == MotionEvent.ACTION_DOWN) {
769af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka            setTagToCellInfoForPoint((int) ev.getX(), (int) ev.getY());
77031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
771eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung
77231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        return false;
77331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
77431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
775c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen    private void clearTagCellInfo() {
776c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        final CellInfo cellInfo = mCellInfo;
777c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        cellInfo.cell = null;
778c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        cellInfo.cellX = -1;
779c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        cellInfo.cellY = -1;
780c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        cellInfo.spanX = 0;
781c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        cellInfo.spanY = 0;
782c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen        setTag(cellInfo);
783c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen    }
784c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen
78531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public CellInfo getTag() {
7860280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        return (CellInfo) super.getTag();
78731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
78831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
7896569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    /**
790aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     * Given a point, return the cell that strictly encloses that point
79131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param x X coordinate of the point
79231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param y Y coordinate of the point
79331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param result Array of 2 ints to hold the x and y coordinate of the cell
79431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
79531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    void pointToCellExact(int x, int y, int[] result) {
7964b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int hStartPadding = getPaddingLeft();
7974b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int vStartPadding = getPaddingTop();
79831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
79931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        result[0] = (x - hStartPadding) / (mCellWidth + mWidthGap);
80031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        result[1] = (y - vStartPadding) / (mCellHeight + mHeightGap);
80131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
802d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        final int xAxis = mCountX;
803d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        final int yAxis = mCountY;
80431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
80531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        if (result[0] < 0) result[0] = 0;
80631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        if (result[0] >= xAxis) result[0] = xAxis - 1;
80731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        if (result[1] < 0) result[1] = 0;
80831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        if (result[1] >= yAxis) result[1] = yAxis - 1;
80931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
810aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
81131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
81231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * Given a point, return the cell that most closely encloses that point
81331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param x X coordinate of the point
81431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param y Y coordinate of the point
81531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param result Array of 2 ints to hold the x and y coordinate of the cell
81631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
81731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    void pointToCellRounded(int x, int y, int[] result) {
81831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        pointToCellExact(x + (mCellWidth / 2), y + (mCellHeight / 2), result);
81931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
82031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
82131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
82231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * Given a cell coordinate, return the point that represents the upper left corner of that cell
823aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     *
824aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     * @param cellX X coordinate of the cell
82531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param cellY Y coordinate of the cell
826aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     *
82731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param result Array of 2 ints to hold the x and y coordinate of the point
82831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
82931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    void cellToPoint(int cellX, int cellY, int[] result) {
8304b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int hStartPadding = getPaddingLeft();
8314b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int vStartPadding = getPaddingTop();
83231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
83331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        result[0] = hStartPadding + cellX * (mCellWidth + mWidthGap);
83431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        result[1] = vStartPadding + cellY * (mCellHeight + mHeightGap);
83531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
83631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
837e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen    /**
838482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * Given a cell coordinate, return the point that represents the center of the cell
839e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen     *
840e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen     * @param cellX X coordinate of the cell
841e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen     * @param cellY Y coordinate of the cell
842e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen     *
843e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen     * @param result Array of 2 ints to hold the x and y coordinate of the point
844e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen     */
845e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen    void cellToCenterPoint(int cellX, int cellY, int[] result) {
84647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        regionToCenterPoint(cellX, cellY, 1, 1, result);
84747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    }
84847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
84947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    /**
85047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * Given a cell coordinate and span return the point that represents the center of the regio
85147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     *
85247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param cellX X coordinate of the cell
85347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param cellY Y coordinate of the cell
85447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     *
85547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param result Array of 2 ints to hold the x and y coordinate of the point
85647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     */
85747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    void regionToCenterPoint(int cellX, int cellY, int spanX, int spanY, int[] result) {
8584b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int hStartPadding = getPaddingLeft();
8594b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int vStartPadding = getPaddingTop();
86047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        result[0] = hStartPadding + cellX * (mCellWidth + mWidthGap) +
86147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                (spanX * mCellWidth + (spanX - 1) * mWidthGap) / 2;
86247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        result[1] = vStartPadding + cellY * (mCellHeight + mHeightGap) +
86347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                (spanY * mCellHeight + (spanY - 1) * mHeightGap) / 2;
864e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen    }
865e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen
86619f3792523fe2d55ea791a9286398a6120920690Adam Cohen     /**
86719f3792523fe2d55ea791a9286398a6120920690Adam Cohen     * Given a cell coordinate and span fills out a corresponding pixel rect
86819f3792523fe2d55ea791a9286398a6120920690Adam Cohen     *
86919f3792523fe2d55ea791a9286398a6120920690Adam Cohen     * @param cellX X coordinate of the cell
87019f3792523fe2d55ea791a9286398a6120920690Adam Cohen     * @param cellY Y coordinate of the cell
87119f3792523fe2d55ea791a9286398a6120920690Adam Cohen     * @param result Rect in which to write the result
87219f3792523fe2d55ea791a9286398a6120920690Adam Cohen     */
87319f3792523fe2d55ea791a9286398a6120920690Adam Cohen     void regionToRect(int cellX, int cellY, int spanX, int spanY, Rect result) {
87419f3792523fe2d55ea791a9286398a6120920690Adam Cohen        final int hStartPadding = getPaddingLeft();
87519f3792523fe2d55ea791a9286398a6120920690Adam Cohen        final int vStartPadding = getPaddingTop();
87619f3792523fe2d55ea791a9286398a6120920690Adam Cohen        final int left = hStartPadding + cellX * (mCellWidth + mWidthGap);
87719f3792523fe2d55ea791a9286398a6120920690Adam Cohen        final int top = vStartPadding + cellY * (mCellHeight + mHeightGap);
87819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        result.set(left, top, left + (spanX * mCellWidth + (spanX - 1) * mWidthGap),
87919f3792523fe2d55ea791a9286398a6120920690Adam Cohen                top + (spanY * mCellHeight + (spanY - 1) * mHeightGap));
88019f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
88119f3792523fe2d55ea791a9286398a6120920690Adam Cohen
882482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public float getDistanceFromCell(float x, float y, int[] cell) {
883482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        cellToCenterPoint(cell[0], cell[1], mTmpPoint);
884482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        float distance = (float) Math.sqrt( Math.pow(x - mTmpPoint[0], 2) +
885482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                Math.pow(y - mTmpPoint[1], 2));
886482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return distance;
887482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
888482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
88984f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy    int getCellWidth() {
89084f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy        return mCellWidth;
89184f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy    }
89284f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy
89384f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy    int getCellHeight() {
89484f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy        return mCellHeight;
89584f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy    }
89684f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy
897d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    int getWidthGap() {
898d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        return mWidthGap;
899d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    }
900d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
901d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    int getHeightGap() {
902d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        return mHeightGap;
903d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    }
904d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
9057f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen    Rect getContentRect(Rect r) {
9067f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        if (r == null) {
9077f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            r = new Rect();
9087f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
9097f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        int left = getPaddingLeft();
9107f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        int top = getPaddingTop();
9118b805b17158886035b38261eb611d8641701ae43Michael Jurka        int right = left + getWidth() - getPaddingLeft() - getPaddingRight();
9128b805b17158886035b38261eb611d8641701ae43Michael Jurka        int bottom = top + getHeight() - getPaddingTop() - getPaddingBottom();
9137f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        r.set(left, top, right, bottom);
9147f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        return r;
9157f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen    }
9167f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
917a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen    static void getMetrics(Rect metrics, Resources res, int measureWidth, int measureHeight,
918a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen            int countX, int countY, int orientation) {
919a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen        int numWidthGaps = countX - 1;
920a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen        int numHeightGaps = countY - 1;
921f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen
922f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        int widthGap;
923f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        int heightGap;
924f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        int cellWidth;
925f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        int cellHeight;
926f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        int paddingLeft;
927f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        int paddingRight;
928f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        int paddingTop;
929f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        int paddingBottom;
930f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen
931a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen        int maxGap = res.getDimensionPixelSize(R.dimen.workspace_max_gap);
932f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        if (orientation == LANDSCAPE) {
933f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            cellWidth = res.getDimensionPixelSize(R.dimen.workspace_cell_width_land);
934f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            cellHeight = res.getDimensionPixelSize(R.dimen.workspace_cell_height_land);
935f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            widthGap = res.getDimensionPixelSize(R.dimen.workspace_width_gap_land);
936f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            heightGap = res.getDimensionPixelSize(R.dimen.workspace_height_gap_land);
937f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            paddingLeft = res.getDimensionPixelSize(R.dimen.cell_layout_left_padding_land);
938f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            paddingRight = res.getDimensionPixelSize(R.dimen.cell_layout_right_padding_land);
939f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            paddingTop = res.getDimensionPixelSize(R.dimen.cell_layout_top_padding_land);
940f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            paddingBottom = res.getDimensionPixelSize(R.dimen.cell_layout_bottom_padding_land);
941f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        } else {
942f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            // PORTRAIT
943f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            cellWidth = res.getDimensionPixelSize(R.dimen.workspace_cell_width_port);
944f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            cellHeight = res.getDimensionPixelSize(R.dimen.workspace_cell_height_port);
945f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            widthGap = res.getDimensionPixelSize(R.dimen.workspace_width_gap_port);
946f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            heightGap = res.getDimensionPixelSize(R.dimen.workspace_height_gap_port);
947f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            paddingLeft = res.getDimensionPixelSize(R.dimen.cell_layout_left_padding_port);
948f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            paddingRight = res.getDimensionPixelSize(R.dimen.cell_layout_right_padding_port);
949f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            paddingTop = res.getDimensionPixelSize(R.dimen.cell_layout_top_padding_port);
950f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            paddingBottom = res.getDimensionPixelSize(R.dimen.cell_layout_bottom_padding_port);
951f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        }
952f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen
953f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        if (widthGap < 0 || heightGap < 0) {
954f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            int hSpace = measureWidth - paddingLeft - paddingRight;
955f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            int vSpace = measureHeight - paddingTop - paddingBottom;
956a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen            int hFreeSpace = hSpace - (countX * cellWidth);
957a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen            int vFreeSpace = vSpace - (countY * cellHeight);
958a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen            widthGap = Math.min(maxGap, numWidthGaps > 0 ? (hFreeSpace / numWidthGaps) : 0);
959a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen            heightGap = Math.min(maxGap, numHeightGaps > 0 ? (vFreeSpace / numHeightGaps) : 0);
960f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        }
961f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen        metrics.set(cellWidth, cellHeight, widthGap, heightGap);
962f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen    }
963f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen
96431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
96531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
96631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
967aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
968aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
96931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
97031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int heightSpecSize =  MeasureSpec.getSize(heightMeasureSpec);
971aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
97231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        if (widthSpecMode == MeasureSpec.UNSPECIFIED || heightSpecMode == MeasureSpec.UNSPECIFIED) {
97331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            throw new RuntimeException("CellLayout cannot have UNSPECIFIED dimensions");
97431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
97531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
976d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        int numWidthGaps = mCountX - 1;
977d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        int numHeightGaps = mCountY - 1;
978d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen
979234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen        if (mOriginalWidthGap < 0 || mOriginalHeightGap < 0) {
980dd13e3d0f9925b7bb80c37e21d039aab4fa7e7a1Michael Jurka            int hSpace = widthSpecSize - getPaddingLeft() - getPaddingRight();
981dd13e3d0f9925b7bb80c37e21d039aab4fa7e7a1Michael Jurka            int vSpace = heightSpecSize - getPaddingTop() - getPaddingBottom();
982f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            int hFreeSpace = hSpace - (mCountX * mCellWidth);
983f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen            int vFreeSpace = vSpace - (mCountY * mCellHeight);
9844b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung            mWidthGap = Math.min(mMaxGap, numWidthGaps > 0 ? (hFreeSpace / numWidthGaps) : 0);
9854b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung            mHeightGap = Math.min(mMaxGap,numHeightGaps > 0 ? (vFreeSpace / numHeightGaps) : 0);
986a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            mShortcutsAndWidgets.setCellDimensions(mCellWidth, mCellHeight, mWidthGap, mHeightGap);
987234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen        } else {
988234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen            mWidthGap = mOriginalWidthGap;
989234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen            mHeightGap = mOriginalHeightGap;
990ece7f5b3b55cab646941123e03589241a61678e2Winson Chung        }
9915f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka
9928c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka        // Initial values correspond to widthSpecMode == MeasureSpec.EXACTLY
9938c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka        int newWidth = widthSpecSize;
9948c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka        int newHeight = heightSpecSize;
9958c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka        if (widthSpecMode == MeasureSpec.AT_MOST) {
9968b805b17158886035b38261eb611d8641701ae43Michael Jurka            newWidth = getPaddingLeft() + getPaddingRight() + (mCountX * mCellWidth) +
9978c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka                ((mCountX - 1) * mWidthGap);
9988b805b17158886035b38261eb611d8641701ae43Michael Jurka            newHeight = getPaddingTop() + getPaddingBottom() + (mCountY * mCellHeight) +
9998c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka                ((mCountY - 1) * mHeightGap);
10008c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka            setMeasuredDimension(newWidth, newHeight);
10018c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka        }
100231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
10038c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka        int count = getChildCount();
100431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        for (int i = 0; i < count; i++) {
100531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            View child = getChildAt(i);
10068b805b17158886035b38261eb611d8641701ae43Michael Jurka            int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(newWidth - getPaddingLeft() -
10078b805b17158886035b38261eb611d8641701ae43Michael Jurka                    getPaddingRight(), MeasureSpec.EXACTLY);
10088b805b17158886035b38261eb611d8641701ae43Michael Jurka            int childheightMeasureSpec = MeasureSpec.makeMeasureSpec(newHeight - getPaddingTop() -
10098b805b17158886035b38261eb611d8641701ae43Michael Jurka                    getPaddingBottom(), MeasureSpec.EXACTLY);
101031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            child.measure(childWidthMeasureSpec, childheightMeasureSpec);
101131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
10128c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka        setMeasuredDimension(newWidth, newHeight);
101331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
101431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
101531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
101628750fba6a2d141eb9a1e566718c17236030b815Michael Jurka    protected void onLayout(boolean changed, int l, int t, int r, int b) {
101731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int count = getChildCount();
101831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        for (int i = 0; i < count; i++) {
10198c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka            View child = getChildAt(i);
10208b805b17158886035b38261eb611d8641701ae43Michael Jurka            child.layout(getPaddingLeft(), getPaddingTop(),
10218b805b17158886035b38261eb611d8641701ae43Michael Jurka                    r - l - getPaddingRight(), b - t - getPaddingBottom());
102231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
102331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
102431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
102531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
1026dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
1027dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka        super.onSizeChanged(w, h, oldw, oldh);
102818014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka        mBackgroundRect.set(0, 0, w, h);
1029b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen        mForegroundRect.set(mForegroundPadding, mForegroundPadding,
1030b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen                w - 2 * mForegroundPadding, h - 2 * mForegroundPadding);
1031dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    }
1032dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka
1033dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    @Override
103431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    protected void setChildrenDrawingCacheEnabled(boolean enabled) {
1035a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.setChildrenDrawingCacheEnabled(enabled);
103631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
103731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
103831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
103931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    protected void setChildrenDrawnWithCacheEnabled(boolean enabled) {
1040a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.setChildrenDrawnWithCacheEnabled(enabled);
104131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
104231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
10435f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka    public float getBackgroundAlpha() {
10445f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka        return mBackgroundAlpha;
1045dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    }
1046dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka
10471b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen    public void setBackgroundAlphaMultiplier(float multiplier) {
1048a3d30adbfd4f013260f1f5ba3a56bc9bb4a11717Michael Jurka        if (mBackgroundAlphaMultiplier != multiplier) {
1049a3d30adbfd4f013260f1f5ba3a56bc9bb4a11717Michael Jurka            mBackgroundAlphaMultiplier = multiplier;
1050a3d30adbfd4f013260f1f5ba3a56bc9bb4a11717Michael Jurka            invalidate();
1051a3d30adbfd4f013260f1f5ba3a56bc9bb4a11717Michael Jurka        }
10521b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen    }
10531b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen
1054ddb821981e0919bbd3b4c9a2b6aa1811d6c86bb6Adam Cohen    public float getBackgroundAlphaMultiplier() {
1055ddb821981e0919bbd3b4c9a2b6aa1811d6c86bb6Adam Cohen        return mBackgroundAlphaMultiplier;
1056ddb821981e0919bbd3b4c9a2b6aa1811d6c86bb6Adam Cohen    }
1057ddb821981e0919bbd3b4c9a2b6aa1811d6c86bb6Adam Cohen
10585f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka    public void setBackgroundAlpha(float alpha) {
1059afaa05014e0bf3ed1192f9ddec2af4283bc50248Michael Jurka        if (mBackgroundAlpha != alpha) {
1060afaa05014e0bf3ed1192f9ddec2af4283bc50248Michael Jurka            mBackgroundAlpha = alpha;
1061afaa05014e0bf3ed1192f9ddec2af4283bc50248Michael Jurka            invalidate();
1062afaa05014e0bf3ed1192f9ddec2af4283bc50248Michael Jurka        }
1063dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    }
1064dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka
1065a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka    public void setShortcutAndWidgetAlpha(float alpha) {
10660142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka        final int childCount = getChildCount();
10670142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka        for (int i = 0; i < childCount; i++) {
1068dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka            getChildAt(i).setAlpha(alpha);
1069dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka        }
1070dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka    }
1071dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka
1072a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka    public ShortcutAndWidgetContainer getShortcutsAndWidgets() {
1073a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        if (getChildCount() > 0) {
1074a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            return (ShortcutAndWidgetContainer) getChildAt(0);
1075a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        }
1076a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        return null;
1077a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka    }
1078a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka
1079440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy    public View getChildAt(int x, int y) {
1080a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        return mShortcutsAndWidgets.getChildAt(x, y);
1081440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy    }
1082440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy
108376fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen    public boolean animateChildToPosition(final View child, int cellX, int cellY, int duration,
1084482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            int delay, boolean permanent, boolean adjustOccupied) {
1085a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        ShortcutAndWidgetContainer clc = getShortcutsAndWidgets();
1086482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        boolean[][] occupied = mOccupied;
1087482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (!permanent) {
1088482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            occupied = mTmpOccupied;
1089482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1090482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
109119f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if (clc.indexOfChild(child) != -1) {
1092bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
1093bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            final ItemInfo info = (ItemInfo) child.getTag();
1094bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen
1095bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            // We cancel any existing animations
1096bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            if (mReorderAnimators.containsKey(lp)) {
1097bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                mReorderAnimators.get(lp).cancel();
1098bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                mReorderAnimators.remove(lp);
1099bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            }
1100bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen
1101482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            final int oldX = lp.x;
1102482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            final int oldY = lp.y;
1103482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (adjustOccupied) {
1104482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                occupied[lp.cellX][lp.cellY] = false;
1105482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                occupied[cellX][cellY] = true;
1106482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1107bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            lp.isLockedToGrid = true;
1108482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (permanent) {
1109482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                lp.cellX = info.cellX = cellX;
1110482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                lp.cellY = info.cellY = cellY;
1111482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            } else {
1112482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                lp.tmpCellX = cellX;
1113482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                lp.tmpCellY = cellY;
1114482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1115bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            clc.setupLp(lp);
1116bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            lp.isLockedToGrid = false;
1117482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            final int newX = lp.x;
1118482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            final int newY = lp.y;
1119bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen
112076fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen            lp.x = oldX;
112176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen            lp.y = oldY;
112276fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen
1123482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            // Exit early if we're not actually moving the view
1124482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (oldX == newX && oldY == newY) {
1125482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                lp.isLockedToGrid = true;
1126482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                return true;
1127482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1128482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1129482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
1130482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            va.setDuration(duration);
1131482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            mReorderAnimators.put(lp, va);
1132482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1133482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            va.addUpdateListener(new AnimatorUpdateListener() {
1134482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                @Override
1135bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                public void onAnimationUpdate(ValueAnimator animation) {
1136482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    float r = ((Float) animation.getAnimatedValue()).floatValue();
113719f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    lp.x = (int) ((1 - r) * oldX + r * newX);
113819f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    lp.y = (int) ((1 - r) * oldY + r * newY);
11396b8a02d63a5d9cab8209381993e37db6a6afb753Adam Cohen                    child.requestLayout();
1140bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                }
1141bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            });
1142482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            va.addListener(new AnimatorListenerAdapter() {
1143bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                boolean cancelled = false;
1144bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                public void onAnimationEnd(Animator animation) {
1145bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    // If the animation was cancelled, it means that another animation
1146bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    // has interrupted this one, and we don't want to lock the item into
1147bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    // place just yet.
1148bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    if (!cancelled) {
1149bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                        lp.isLockedToGrid = true;
1150482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        child.requestLayout();
1151bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    }
1152bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    if (mReorderAnimators.containsKey(lp)) {
1153bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                        mReorderAnimators.remove(lp);
1154bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    }
1155bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                }
1156bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                public void onAnimationCancel(Animator animation) {
1157bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                    cancelled = true;
1158bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen                }
1159bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            });
1160482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            va.setStartDelay(delay);
1161482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            va.start();
1162bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen            return true;
1163bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        }
1164bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen        return false;
1165bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen    }
1166bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen
11676569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    /**
11686569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     * Estimate where the top left cell of the dragged item will land if it is dropped.
11696569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     *
11706569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     * @param originX The X value of the top left corner of the item
11716569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     * @param originY The Y value of the top left corner of the item
11726569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     * @param spanX The number of horizontal cells that the item spans
11736569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     * @param spanY The number of vertical cells that the item spans
11746569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     * @param result The estimated drop cell X and Y.
11756569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     */
11766569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    void estimateDropCell(int originX, int originY, int spanX, int spanY, int[] result) {
1177d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        final int countX = mCountX;
1178d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen        final int countY = mCountY;
11796569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
1180a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka        // pointToCellRounded takes the top left of a cell but will pad that with
1181a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka        // cellWidth/2 and cellHeight/2 when finding the matching cell
1182a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka        pointToCellRounded(originX, originY, result);
11836569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
11846569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        // If the item isn't fully on this screen, snap to the edges
11856569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        int rightOverhang = result[0] + spanX - countX;
11866569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        if (rightOverhang > 0) {
11876569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy            result[0] -= rightOverhang; // Snap to right
11886569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        }
11896569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        result[0] = Math.max(0, result[0]); // Snap to left
11906569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        int bottomOverhang = result[1] + spanY - countY;
11916569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        if (bottomOverhang > 0) {
11926569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy            result[1] -= bottomOverhang; // Snap to bottom
11936569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        }
11946569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        result[1] = Math.max(0, result[1]); // Snap to top
11956569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    }
11966569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
1197482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    void visualizeDropLocation(View v, Bitmap dragOutline, int originX, int originY, int cellX,
1198482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            int cellY, int spanX, int spanY, boolean resize, Point dragOffset, Rect dragRegion) {
119908ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy        final int oldDragCellX = mDragCell[0];
120008ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy        final int oldDragCellY = mDragCell[1];
1201482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1202b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung        if (v != null && dragOffset == null) {
1203a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung            mDragCenter.set(originX + (v.getWidth() / 2), originY + (v.getHeight() / 2));
1204a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung        } else {
1205a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung            mDragCenter.set(originX, originY);
1206a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung        }
12076569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
12082801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        if (dragOutline == null && v == null) {
12092801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            return;
12102801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        }
12112801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
1212482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (cellX != oldDragCellX || cellY != oldDragCellY) {
1213482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            mDragCell[0] = cellX;
1214482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            mDragCell[1] = cellY;
12156569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy            // Find the top left corner of the rect the object will occupy
1216de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy            final int[] topLeft = mTmpPoint;
1217482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            cellToPoint(cellX, cellY, topLeft);
1218de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy
12194be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            int left = topLeft[0];
12204be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            int top = topLeft[1];
12216569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
1222b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung            if (v != null && dragOffset == null) {
122399e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                // When drawing the drag outline, it did not account for margin offsets
122499e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                // added by the view's parent.
122599e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                MarginLayoutParams lp = (MarginLayoutParams) v.getLayoutParams();
122699e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                left += lp.leftMargin;
122799e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                top += lp.topMargin;
122899e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen
122999e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                // Offsets due to the size difference between the View and the dragOutline.
123099e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                // There is a size difference to account for the outer blur, which may lie
123199e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen                // outside the bounds of the view.
1232a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung                top += (v.getHeight() - dragOutline.getHeight()) / 2;
1233ae915cecd36af4973061a1cb0b58c5be1be699a0Adam Cohen                // We center about the x axis
1234ae915cecd36af4973061a1cb0b58c5be1be699a0Adam Cohen                left += ((mCellWidth * spanX) + ((spanX - 1) * mWidthGap)
1235ae915cecd36af4973061a1cb0b58c5be1be699a0Adam Cohen                        - dragOutline.getWidth()) / 2;
12366639687cd67bab1aeef2a75e5c6bc458b20dc082Adam Cohen            } else {
1237b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                if (dragOffset != null && dragRegion != null) {
1238b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                    // Center the drag region *horizontally* in the cell and apply a drag
1239b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                    // outline offset
1240b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                    left += dragOffset.x + ((mCellWidth * spanX) + ((spanX - 1) * mWidthGap)
1241b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                             - dragRegion.width()) / 2;
1242b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                    top += dragOffset.y;
1243b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                } else {
1244b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                    // Center the drag outline in the cell
1245b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                    left += ((mCellWidth * spanX) + ((spanX - 1) * mWidthGap)
1246b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                            - dragOutline.getWidth()) / 2;
1247b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                    top += ((mCellHeight * spanY) + ((spanY - 1) * mHeightGap)
1248b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                            - dragOutline.getHeight()) / 2;
1249b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung                }
1250a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung            }
12514be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            final int oldIndex = mDragOutlineCurrent;
125208ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy            mDragOutlineAnims[oldIndex].animateOut();
125308ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy            mDragOutlineCurrent = (oldIndex + 1) % mDragOutlines.length;
1254d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            Rect r = mDragOutlines[mDragOutlineCurrent];
1255d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            r.set(left, top, left + dragOutline.getWidth(), top + dragOutline.getHeight());
1256d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            if (resize) {
1257482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                cellToRect(cellX, cellY, spanX, spanY, r);
1258d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            }
1259150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung
126008ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy            mDragOutlineAnims[mDragOutlineCurrent].setTag(dragOutline);
126108ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy            mDragOutlineAnims[mDragOutlineCurrent].animateIn();
12626569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        }
12636569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    }
12646569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
1265e0310965022e7a1adb7ad489505d404186608689Adam Cohen    public void clearDragOutlines() {
1266e0310965022e7a1adb7ad489505d404186608689Adam Cohen        final int oldIndex = mDragOutlineCurrent;
1267e0310965022e7a1adb7ad489505d404186608689Adam Cohen        mDragOutlineAnims[oldIndex].animateOut();
1268d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        mDragCell[0] = mDragCell[1] = -1;
1269e0310965022e7a1adb7ad489505d404186608689Adam Cohen    }
1270e0310965022e7a1adb7ad489505d404186608689Adam Cohen
127131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
127270864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey     * Find a vacant area that will fit the given bounds nearest the requested
127370864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey     * cell location. Uses Euclidean distance to score multiple vacant areas.
1274aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     *
127551afc022fa76c79f0d1ece470ddc126c08fea8a4Romain Guy     * @param pixelX The X location at which you want to search for a vacant area.
127651afc022fa76c79f0d1ece470ddc126c08fea8a4Romain Guy     * @param pixelY The Y location at which you want to search for a vacant area.
127770864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey     * @param spanX Horizontal span of the object.
127870864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey     * @param spanY Vertical span of the object.
1279de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy     * @param result Array in which to place the result, or null (in which case a new array will
1280de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy     *        be allocated)
128170864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey     * @return The X, Y cell of a vacant area that can contain this object,
128270864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey     *         nearest the requested location.
128331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
1284d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    int[] findNearestVacantArea(int pixelX, int pixelY, int spanX, int spanY,
1285d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            int[] result) {
1286de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy        return findNearestVacantArea(pixelX, pixelY, spanX, spanY, null, result);
12876a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka    }
1288aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
12896a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka    /**
12906a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     * Find a vacant area that will fit the given bounds nearest the requested
12916a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     * cell location. Uses Euclidean distance to score multiple vacant areas.
12926a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     *
12936a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     * @param pixelX The X location at which you want to search for a vacant area.
12946a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     * @param pixelY The Y location at which you want to search for a vacant area.
1295d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param minSpanX The minimum horizontal span required
1296d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param minSpanY The minimum vertical span required
1297d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param spanX Horizontal span of the object.
1298d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param spanY Vertical span of the object.
1299d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param result Array in which to place the result, or null (in which case a new array will
1300d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *        be allocated)
1301d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @return The X, Y cell of a vacant area that can contain this object,
1302d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *         nearest the requested location.
1303d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     */
1304d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    int[] findNearestVacantArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX,
1305d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            int spanY, int[] result, int[] resultSpan) {
1306d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        return findNearestVacantArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, null,
1307d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                result, resultSpan);
1308d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    }
1309d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen
1310d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    /**
1311d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * Find a vacant area that will fit the given bounds nearest the requested
1312d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * cell location. Uses Euclidean distance to score multiple vacant areas.
1313d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *
1314d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param pixelX The X location at which you want to search for a vacant area.
1315d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param pixelY The Y location at which you want to search for a vacant area.
13166a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     * @param spanX Horizontal span of the object.
13176a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     * @param spanY Vertical span of the object.
1318df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param ignoreOccupied If true, the result can be an occupied cell
1319df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param result Array in which to place the result, or null (in which case a new array will
1320df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     *        be allocated)
13216a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     * @return The X, Y cell of a vacant area that can contain this object,
13226a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     *         nearest the requested location.
13236a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka     */
1324df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    int[] findNearestArea(int pixelX, int pixelY, int spanX, int spanY, View ignoreView,
1325df0353815c629fc678824b07a234b89a1ff94208Adam Cohen            boolean ignoreOccupied, int[] result) {
1326d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        return findNearestArea(pixelX, pixelY, spanX, spanY,
1327482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                spanX, spanY, ignoreView, ignoreOccupied, result, null, mOccupied);
1328d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    }
1329d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen
1330d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    private final Stack<Rect> mTempRectStack = new Stack<Rect>();
1331d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    private void lazyInitTempRectStack() {
1332d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        if (mTempRectStack.isEmpty()) {
1333d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            for (int i = 0; i < mCountX * mCountY; i++) {
1334d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                mTempRectStack.push(new Rect());
1335d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            }
1336d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        }
1337d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    }
1338482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1339d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    private void recycleTempRects(Stack<Rect> used) {
1340d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        while (!used.isEmpty()) {
1341d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            mTempRectStack.push(used.pop());
1342d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        }
1343d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    }
1344d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen
1345d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    /**
1346d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * Find a vacant area that will fit the given bounds nearest the requested
1347d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * cell location. Uses Euclidean distance to score multiple vacant areas.
1348d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *
1349d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param pixelX The X location at which you want to search for a vacant area.
1350d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param pixelY The Y location at which you want to search for a vacant area.
1351d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param minSpanX The minimum horizontal span required
1352d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param minSpanY The minimum vertical span required
1353d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param spanX Horizontal span of the object.
1354d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param spanY Vertical span of the object.
1355d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param ignoreOccupied If true, the result can be an occupied cell
1356d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param result Array in which to place the result, or null (in which case a new array will
1357d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *        be allocated)
1358d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @return The X, Y cell of a vacant area that can contain this object,
1359d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *         nearest the requested location.
1360d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     */
1361d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    int[] findNearestArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, int spanY,
1362482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            View ignoreView, boolean ignoreOccupied, int[] result, int[] resultSpan,
1363482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            boolean[][] occupied) {
1364d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        lazyInitTempRectStack();
1365c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka        // mark space take by ignoreView as available (method checks if ignoreView is null)
1366482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsAsUnoccupiedForView(ignoreView, occupied);
1367c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka
1368e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        // For items with a spanX / spanY > 1, the passed in point (pixelX, pixelY) corresponds
1369e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        // to the center of the item, but we are searching based on the top-left cell, so
1370e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        // we translate the point over to correspond to the top-left.
1371e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        pixelX -= (mCellWidth + mWidthGap) * (spanX - 1) / 2f;
1372e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen        pixelY -= (mCellHeight + mHeightGap) * (spanY - 1) / 2f;
1373e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen
137470864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey        // Keep track of best-scoring drop area
1375de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy        final int[] bestXY = result != null ? result : new int[2];
137670864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey        double bestDistance = Double.MAX_VALUE;
1377d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        final Rect bestRect = new Rect(-1, -1, -1, -1);
1378d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        final Stack<Rect> validRegions = new Stack<Rect>();
1379aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
1380de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy        final int countX = mCountX;
1381de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy        final int countY = mCountY;
1382de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy
1383d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        if (minSpanX <= 0 || minSpanY <= 0 || spanX <= 0 || spanY <= 0 ||
1384d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                spanX < minSpanX || spanY < minSpanY) {
1385d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            return bestXY;
1386d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        }
1387d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen
1388d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        for (int y = 0; y < countY - (minSpanY - 1); y++) {
1389c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka            inner:
1390d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            for (int x = 0; x < countX - (minSpanX - 1); x++) {
1391d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                int ySize = -1;
1392d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                int xSize = -1;
1393df0353815c629fc678824b07a234b89a1ff94208Adam Cohen                if (ignoreOccupied) {
1394d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    // First, let's see if this thing fits anywhere
1395d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    for (int i = 0; i < minSpanX; i++) {
1396d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        for (int j = 0; j < minSpanY; j++) {
1397df0353815c629fc678824b07a234b89a1ff94208Adam Cohen                            if (occupied[x + i][y + j]) {
1398df0353815c629fc678824b07a234b89a1ff94208Adam Cohen                                continue inner;
1399df0353815c629fc678824b07a234b89a1ff94208Adam Cohen                            }
1400c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                        }
1401c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                    }
1402d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    xSize = minSpanX;
1403d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    ySize = minSpanY;
1404d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen
1405d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    // We know that the item will fit at _some_ acceptable size, now let's see
1406d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    // how big we can make it. We'll alternate between incrementing x and y spans
1407d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    // until we hit a limit.
1408d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    boolean incX = true;
1409d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    boolean hitMaxX = xSize >= spanX;
1410d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    boolean hitMaxY = ySize >= spanY;
1411d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    while (!(hitMaxX && hitMaxY)) {
1412d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        if (incX && !hitMaxX) {
1413d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            for (int j = 0; j < ySize; j++) {
1414d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                if (x + xSize > countX -1 || occupied[x + xSize][y + j]) {
1415d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                    // We can't move out horizontally
1416d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                    hitMaxX = true;
1417d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                }
1418d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            }
1419d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            if (!hitMaxX) {
1420d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                xSize++;
1421d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            }
1422d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        } else if (!hitMaxY) {
1423d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            for (int i = 0; i < xSize; i++) {
1424d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                if (y + ySize > countY - 1 || occupied[x + i][y + ySize]) {
1425d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                    // We can't move out vertically
1426d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                    hitMaxY = true;
1427d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                }
1428d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            }
1429d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            if (!hitMaxY) {
1430d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                                ySize++;
1431d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                            }
1432d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        }
1433d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        hitMaxX |= xSize >= spanX;
1434d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        hitMaxY |= ySize >= spanY;
1435d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        incX = !incX;
1436d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    }
1437d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    incX = true;
1438d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    hitMaxX = xSize >= spanX;
1439d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    hitMaxY = ySize >= spanY;
1440c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                }
14410be025d64c1f84138fe430a58875886e66aae767Winson Chung                final int[] cellXY = mTmpXY;
1442e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen                cellToCenterPoint(x, y, cellXY);
1443c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka
1444d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                // We verify that the current rect is not a sub-rect of any of our previous
1445d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                // candidates. In this case, the current rect is disqualified in favour of the
1446d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                // containing rect.
1447d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                Rect currentRect = mTempRectStack.pop();
1448d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                currentRect.set(x, y, x + xSize, y + ySize);
1449d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                boolean contained = false;
1450d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                for (Rect r : validRegions) {
1451d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    if (r.contains(currentRect)) {
1452d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        contained = true;
1453d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        break;
1454d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    }
1455d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                }
1456d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                validRegions.push(currentRect);
1457c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                double distance = Math.sqrt(Math.pow(cellXY[0] - pixelX, 2)
1458c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                        + Math.pow(cellXY[1] - pixelY, 2));
1459482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1460d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                if ((distance <= bestDistance && !contained) ||
1461d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        currentRect.contains(bestRect)) {
1462c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                    bestDistance = distance;
1463c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                    bestXY[0] = x;
1464c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                    bestXY[1] = y;
1465d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    if (resultSpan != null) {
1466d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        resultSpan[0] = xSize;
1467d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                        resultSpan[1] = ySize;
1468d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    }
1469d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen                    bestRect.set(currentRect);
1470c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka                }
147131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            }
147231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
1473c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka        // re-mark space taken by ignoreView as occupied
1474482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsAsOccupiedForView(ignoreView, occupied);
147531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
1476c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        // Return -1, -1 if no suitable location found
1477c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        if (bestDistance == Double.MAX_VALUE) {
1478c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            bestXY[0] = -1;
1479c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen            bestXY[1] = -1;
148070864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey        }
1481d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        recycleTempRects(validRegions);
1482c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen        return bestXY;
148331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
1484aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
1485482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     /**
1486482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * Find a vacant area that will fit the given bounds nearest the requested
1487482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * cell location, and will also weigh in a suggested direction vector of the
1488482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * desired location. This method computers distance based on unit grid distances,
1489482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * not pixel distances.
1490482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     *
149147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param cellX The X cell nearest to which you want to search for a vacant area.
149247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param cellY The Y cell nearest which you want to search for a vacant area.
1493482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * @param spanX Horizontal span of the object.
1494482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * @param spanY Vertical span of the object.
149547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param direction The favored direction in which the views should move from x, y
149647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param exactDirectionOnly If this parameter is true, then only solutions where the direction
149747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     *        matches exactly. Otherwise we find the best matching direction.
149847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param occoupied The array which represents which cells in the CellLayout are occupied
149947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     * @param blockOccupied The array which represents which cells in the specified block (cellX,
150047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen     *        cellY, spanX, spanY) are occupied. This is used when try to move a group of views.
1501482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * @param result Array in which to place the result, or null (in which case a new array will
1502482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     *        be allocated)
1503482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * @return The X, Y cell of a vacant area that can contain this object,
1504482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     *         nearest the requested location.
1505482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     */
1506482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private int[] findNearestArea(int cellX, int cellY, int spanX, int spanY, int[] direction,
150747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            boolean[][] occupied, boolean blockOccupied[][], int[] result) {
1508482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // Keep track of best-scoring drop area
1509482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        final int[] bestXY = result != null ? result : new int[2];
1510482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        float bestDistance = Float.MAX_VALUE;
1511482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        int bestDirectionScore = Integer.MIN_VALUE;
1512482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1513482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        final int countX = mCountX;
1514482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        final int countY = mCountY;
1515482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1516482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int y = 0; y < countY - (spanY - 1); y++) {
1517482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            inner:
1518482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            for (int x = 0; x < countX - (spanX - 1); x++) {
1519482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                // First, let's see if this thing fits anywhere
1520482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                for (int i = 0; i < spanX; i++) {
1521482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    for (int j = 0; j < spanY; j++) {
152247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        if (occupied[x + i][y + j] && (blockOccupied == null || blockOccupied[i][j])) {
1523482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                            continue inner;
1524482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        }
1525482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    }
1526482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                }
1527482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1528482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                float distance = (float)
1529482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        Math.sqrt((x - cellX) * (x - cellX) + (y - cellY) * (y - cellY));
1530482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                int[] curDirection = mTmpPoint;
153147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                computeDirectionVector(x - cellX, y - cellY, curDirection);
153247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                // The direction score is just the dot product of the two candidate direction
153347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                // and that passed in.
1534482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                int curDirectionScore = direction[0] * curDirection[0] +
1535482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        direction[1] * curDirection[1];
153647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                boolean exactDirectionOnly = false;
153747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                boolean directionMatches = direction[0] == curDirection[0] &&
153847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        direction[0] == curDirection[0];
153947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                if ((directionMatches || !exactDirectionOnly) &&
154047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        Float.compare(distance,  bestDistance) < 0 || (Float.compare(distance,
1541482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        bestDistance) == 0 && curDirectionScore > bestDirectionScore)) {
1542482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    bestDistance = distance;
1543482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    bestDirectionScore = curDirectionScore;
1544482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    bestXY[0] = x;
1545482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    bestXY[1] = y;
1546482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                }
1547482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1548482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1549482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1550482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // Return -1, -1 if no suitable location found
1551482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (bestDistance == Float.MAX_VALUE) {
1552482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            bestXY[0] = -1;
1553482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            bestXY[1] = -1;
1554482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1555482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return bestXY;
1556482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1557482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
155847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    private int[] findNearestAreaInDirection(int cellX, int cellY, int spanX, int spanY,
155947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            int[] direction,boolean[][] occupied,
156047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            boolean blockOccupied[][], int[] result) {
156147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        // Keep track of best-scoring drop area
156247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        final int[] bestXY = result != null ? result : new int[2];
156347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        bestXY[0] = -1;
156447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        bestXY[1] = -1;
156547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        float bestDistance = Float.MAX_VALUE;
156647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
156747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        // We use this to march in a single direction
15685b53f29f809a0dad4a1e0717ba610ce737ee0f43Adam Cohen        if ((direction[0] != 0 && direction[1] != 0) ||
15695b53f29f809a0dad4a1e0717ba610ce737ee0f43Adam Cohen                (direction[0] == 0 && direction[1] == 0)) {
157047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            return bestXY;
157147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
157247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
157347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        // This will only incrememnet one of x or y based on the assertion above
157447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        int x = cellX + direction[0];
157547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        int y = cellY + direction[1];
157647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        while (x >= 0 && x + spanX <= mCountX && y >= 0 && y + spanY <= mCountY) {
157747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
157847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            boolean fail = false;
157947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            for (int i = 0; i < spanX; i++) {
158047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                for (int j = 0; j < spanY; j++) {
158147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    if (occupied[x + i][y + j] && (blockOccupied == null || blockOccupied[i][j])) {
158247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        fail = true;
158347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    }
158447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                }
158547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            }
158647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            if (!fail) {
158747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                float distance = (float)
158847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        Math.sqrt((x - cellX) * (x - cellX) + (y - cellY) * (y - cellY));
158947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                if (Float.compare(distance,  bestDistance) < 0) {
159047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    bestDistance = distance;
159147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    bestXY[0] = x;
159247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    bestXY[1] = y;
159347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                }
159447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            }
159547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            x += direction[0];
159647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            y += direction[1];
159747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
159847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        return bestXY;
159947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    }
160047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
1601482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private boolean addViewToTempLocation(View v, Rect rectOccupiedByPotentialDrop,
16028baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            int[] direction, ItemConfiguration currentState) {
16038baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        CellAndSpan c = currentState.map.get(v);
1604482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        boolean success = false;
16058baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, false);
1606482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsForRect(rectOccupiedByPotentialDrop, mTmpOccupied, true);
1607482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
16088baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        findNearestArea(c.x, c.y, c.spanX, c.spanY, direction, mTmpOccupied, null, mTempLocation);
1609482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1610482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (mTempLocation[0] >= 0 && mTempLocation[1] >= 0) {
16118baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            c.x = mTempLocation[0];
16128baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            c.y = mTempLocation[1];
1613482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            success = true;
1614482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1615482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
16168baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, true);
1617482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return success;
1618482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1619482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
162047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    // This method looks in the specified direction to see if there is an additional view
162147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    // immediately adjecent in that direction
162247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    private boolean addViewInDirection(ArrayList<View> views, Rect boundingRect, int[] direction,
162319f3792523fe2d55ea791a9286398a6120920690Adam Cohen            boolean[][] occupied, View dragView, ItemConfiguration currentState) {
162447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        boolean found = false;
162547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
1626a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        int childCount = mShortcutsAndWidgets.getChildCount();
162747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        Rect r0 = new Rect(boundingRect);
162847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        Rect r1 = new Rect();
162947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
163047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        int deltaX = 0;
163147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        int deltaY = 0;
163247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        if (direction[1] < 0) {
163347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            r0.set(r0.left, r0.top - 1, r0.right, r0.bottom);
163447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            deltaY = -1;
163547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        } else if (direction[1] > 0) {
163647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            r0.set(r0.left, r0.top, r0.right, r0.bottom + 1);
163747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            deltaY = 1;
163847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        } else if (direction[0] < 0) {
163947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            r0.set(r0.left - 1, r0.top, r0.right, r0.bottom);
164047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            deltaX = -1;
164147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        } else if (direction[0] > 0) {
164247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            r0.set(r0.left, r0.top, r0.right + 1, r0.bottom);
164347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            deltaX = 1;
164447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
164547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
164647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        for (int i = 0; i < childCount; i++) {
1647a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            View child = mShortcutsAndWidgets.getChildAt(i);
164819f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (views.contains(child) || child == dragView) continue;
16498baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = currentState.map.get(child);
165047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
16518baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
16528baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            r1.set(c.x, c.y, c.x + c.spanX, c.y + c.spanY);
165347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            if (Rect.intersects(r0, r1)) {
165447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                if (!lp.canReorder) {
165547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    return false;
165647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                }
165747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                boolean pushed = false;
16588baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                for (int x = c.x; x < c.x + c.spanX; x++) {
16598baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                    for (int y = c.y; y < c.y + c.spanY; y++) {
166047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        boolean inBounds = x - deltaX >= 0 && x -deltaX < mCountX
166147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                                && y - deltaY >= 0 && y - deltaY < mCountY;
166247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        if (inBounds && occupied[x - deltaX][y - deltaY]) {
166347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                            pushed = true;
166447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                        }
166547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    }
166647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                }
166747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                if (pushed) {
166847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    views.add(child);
16698baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                    boundingRect.union(c.x, c.y, c.x + c.spanX, c.y + c.spanY);
167047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                    found = true;
167147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen                }
167247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            }
167347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
167447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        return found;
167547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    }
167647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
16778baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen    private boolean addViewsToTempLocation(ArrayList<View> views, Rect rectOccupiedByPotentialDrop,
167819f3792523fe2d55ea791a9286398a6120920690Adam Cohen            int[] direction, boolean push, View dragView, ItemConfiguration currentState) {
167947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        if (views.size() == 0) return true;
168047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
168147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        boolean success = false;
168247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        Rect boundingRect = null;
16838baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // We construct a rect which represents the entire group of views passed in
168447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        for (View v: views) {
16858baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = currentState.map.get(v);
168647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            if (boundingRect == null) {
16878baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                boundingRect = new Rect(c.x, c.y, c.x + c.spanX, c.y + c.spanY);
168847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            } else {
16898baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                boundingRect.union(c.x, c.y, c.x + c.spanX, c.y + c.spanY);
169047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            }
169147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
169247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
16938baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        @SuppressWarnings("unchecked")
169447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        ArrayList<View> dup = (ArrayList<View>) views.clone();
16958baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // We try and expand the group of views in the direction vector passed, based on
16968baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // whether they are physically adjacent, ie. based on "push mechanics".
169719f3792523fe2d55ea791a9286398a6120920690Adam Cohen        while (push && addViewInDirection(dup, boundingRect, direction, mTmpOccupied, dragView,
16988baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                currentState)) {
169947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
17008baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen
17018baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // Mark the occupied state as false for the group of views we want to move.
170247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        for (View v: dup) {
17038baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = currentState.map.get(v);
17048baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, false);
170547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
170647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
170747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        boolean[][] blockOccupied = new boolean[boundingRect.width()][boundingRect.height()];
170847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        int top = boundingRect.top;
170947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        int left = boundingRect.left;
17108baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // We mark more precisely which parts of the bounding rect are truly occupied, allowing
17118baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // for tetris-style interlocking.
171247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        for (View v: dup) {
17138baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = currentState.map.get(v);
17148baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            markCellsForView(c.x - left, c.y - top, c.spanX, c.spanY, blockOccupied, true);
171547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
171647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
171747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        markCellsForRect(rectOccupiedByPotentialDrop, mTmpOccupied, true);
171847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
17198baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        if (push) {
17208baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            findNearestAreaInDirection(boundingRect.left, boundingRect.top, boundingRect.width(),
17218baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                    boundingRect.height(), direction, mTmpOccupied, blockOccupied, mTempLocation);
17228baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        } else {
17238baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            findNearestArea(boundingRect.left, boundingRect.top, boundingRect.width(),
17248baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                    boundingRect.height(), direction, mTmpOccupied, blockOccupied, mTempLocation);
17258baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        }
172647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
17278baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // If we successfuly found a location by pushing the block of views, we commit it
172847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        if (mTempLocation[0] >= 0 && mTempLocation[1] >= 0) {
17298baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            int deltaX = mTempLocation[0] - boundingRect.left;
17308baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            int deltaY = mTempLocation[1] - boundingRect.top;
173147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            for (View v: dup) {
17328baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                CellAndSpan c = currentState.map.get(v);
17338baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                c.x += deltaX;
17348baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                c.y += deltaY;
173547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            }
173647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            success = true;
173747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
1738482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
17398baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // In either case, we set the occupied array as marked for the location of the views
17408baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        for (View v: dup) {
17418baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = currentState.map.get(v);
17428baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, true);
1743482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1744482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return success;
1745482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1746482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1747482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private void markCellsForRect(Rect r, boolean[][] occupied, boolean value) {
1748482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsForView(r.left, r.top, r.width(), r.height(), occupied, value);
1749482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1750482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1751482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private boolean rearrangementExists(int cellX, int cellY, int spanX, int spanY, int[] direction,
17528baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            View ignoreView, ItemConfiguration solution) {
1753e3e03bcd313ba8060f2832b6a16dea6fd6d532eaWinson Chung        // Return early if get invalid cell positions
1754e3e03bcd313ba8060f2832b6a16dea6fd6d532eaWinson Chung        if (cellX < 0 || cellY < 0) return false;
1755482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
17568baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        mIntersectingViews.clear();
1757482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        mOccupiedRect.set(cellX, cellY, cellX + spanX, cellY + spanY);
1758482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
17598baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // Mark the desired location of the view currently being dragged.
1760482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (ignoreView != null) {
17618baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = solution.map.get(ignoreView);
176219f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (c != null) {
176319f3792523fe2d55ea791a9286398a6120920690Adam Cohen                c.x = cellX;
176419f3792523fe2d55ea791a9286398a6120920690Adam Cohen                c.y = cellY;
176519f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
1766482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1767482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        Rect r0 = new Rect(cellX, cellY, cellX + spanX, cellY + spanY);
1768482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        Rect r1 = new Rect();
17698baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        for (View child: solution.map.keySet()) {
1770482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (child == ignoreView) continue;
17718baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = solution.map.get(child);
1772482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
17738baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            r1.set(c.x, c.y, c.x + c.spanX, c.y + c.spanY);
1774482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (Rect.intersects(r0, r1)) {
1775482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                if (!lp.canReorder) {
1776482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    return false;
1777482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                }
1778482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                mIntersectingViews.add(child);
1779482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1780482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
178147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
17828baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // We try to move the intersecting views as a block using the push mechanic
178319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if (addViewsToTempLocation(mIntersectingViews, mOccupiedRect, direction, true, ignoreView,
178419f3792523fe2d55ea791a9286398a6120920690Adam Cohen                solution)) {
178547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            return true;
178647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
178747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        // Try the opposite direction
178847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        direction[0] *= -1;
178947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        direction[1] *= -1;
179019f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if (addViewsToTempLocation(mIntersectingViews, mOccupiedRect, direction, true, ignoreView,
179119f3792523fe2d55ea791a9286398a6120920690Adam Cohen                solution)) {
179247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen            return true;
179347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        }
179447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        // Switch the direction back
179547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        direction[0] *= -1;
179647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        direction[1] *= -1;
179747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
17988baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // Next we try moving the views as a block , but without requiring the push mechanic
179919f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if (addViewsToTempLocation(mIntersectingViews, mOccupiedRect, direction, false, ignoreView,
180019f3792523fe2d55ea791a9286398a6120920690Adam Cohen                solution)) {
1801482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            return true;
1802482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
180347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen
1804482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // Ok, they couldn't move as a block, let's move them individually
1805482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (View v : mIntersectingViews) {
18068baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            if (!addViewToTempLocation(v, mOccupiedRect, direction, solution)) {
1807482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                return false;
1808482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1809482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1810482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return true;
1811482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1812482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1813482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    /*
1814482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * Returns a pair (x, y), where x,y are in {-1, 0, 1} corresponding to vector between
1815482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     * the provided point and the provided cell
1816482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen     */
181747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen    private void computeDirectionVector(float deltaX, float deltaY, int[] result) {
1818482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        double angle = Math.atan(((float) deltaY) / deltaX);
1819482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1820482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        result[0] = 0;
1821482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        result[1] = 0;
1822482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (Math.abs(Math.cos(angle)) > 0.5f) {
1823482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            result[0] = (int) Math.signum(deltaX);
1824482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1825482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (Math.abs(Math.sin(angle)) > 0.5f) {
1826482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            result[1] = (int) Math.signum(deltaY);
1827482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1828482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1829482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
18308baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen    private void copyOccupiedArray(boolean[][] occupied) {
18318baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        for (int i = 0; i < mCountX; i++) {
18328baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            for (int j = 0; j < mCountY; j++) {
18338baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                occupied[i][j] = mOccupied[i][j];
18348baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            }
18358baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        }
18368baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen    }
18378baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen
1838482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    ItemConfiguration simpleSwap(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX,
1839482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            int spanY, int[] direction, View dragView, boolean decX, ItemConfiguration solution) {
18408baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // Copy the current state into the solution. This solution will be manipulated as necessary.
18418baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        copyCurrentStateToSolution(solution, false);
18428baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // Copy the current occupied array into the temporary occupied array. This array will be
18438baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        // manipulated as necessary to find a solution.
18448baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        copyOccupiedArray(mTmpOccupied);
1845482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1846482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // We find the nearest cell into which we would place the dragged item, assuming there's
1847482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // nothing in its way.
1848482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        int result[] = new int[2];
1849482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        result = findNearestArea(pixelX, pixelY, spanX, spanY, result);
1850482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1851482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        boolean success = false;
1852482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // First we try the exact nearest position of the item being dragged,
1853482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // we will then want to try to move this around to other neighbouring positions
18548baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        success = rearrangementExists(result[0], result[1], spanX, spanY, direction, dragView,
18558baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                solution);
1856482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1857482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (!success) {
1858482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            // We try shrinking the widget down to size in an alternating pattern, shrink 1 in
1859482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            // x, then 1 in y etc.
1860482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (spanX > minSpanX && (minSpanY == spanY || decX)) {
1861482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                return simpleSwap(pixelX, pixelY, minSpanX, minSpanY, spanX - 1, spanY, direction,
1862482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        dragView, false, solution);
1863482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            } else if (spanY > minSpanY) {
1864482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                return simpleSwap(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY - 1, direction,
1865482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                        dragView, true, solution);
1866482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1867482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.isSolution = false;
1868482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        } else {
1869482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.isSolution = true;
1870482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewX = result[0];
1871482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewY = result[1];
1872482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewSpanX = spanX;
1873482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewSpanY = spanY;
1874482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1875482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return solution;
1876482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1877482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1878482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private void copyCurrentStateToSolution(ItemConfiguration solution, boolean temp) {
1879a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        int childCount = mShortcutsAndWidgets.getChildCount();
1880482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < childCount; i++) {
1881a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            View child = mShortcutsAndWidgets.getChildAt(i);
1882482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
18838baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c;
1884482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (temp) {
18858baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                c = new CellAndSpan(lp.tmpCellX, lp.tmpCellY, lp.cellHSpan, lp.cellVSpan);
1886482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            } else {
18878baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                c = new CellAndSpan(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan);
1888482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
18898baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            solution.map.put(child, c);
1890482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1891482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1892482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1893482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private void copySolutionToTempState(ItemConfiguration solution, View dragView) {
1894482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < mCountX; i++) {
1895482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            for (int j = 0; j < mCountY; j++) {
1896482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                mTmpOccupied[i][j] = false;
1897482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1898482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1899482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1900a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        int childCount = mShortcutsAndWidgets.getChildCount();
1901482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < childCount; i++) {
1902a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            View child = mShortcutsAndWidgets.getChildAt(i);
1903482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (child == dragView) continue;
1904482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
19058baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = solution.map.get(child);
19068baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            if (c != null) {
19078baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                lp.tmpCellX = c.x;
19088baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                lp.tmpCellY = c.y;
19098baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                lp.cellHSpan = c.spanX;
19108baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                lp.cellVSpan = c.spanY;
19118baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, true);
1912482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1913482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1914482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsForView(solution.dragViewX, solution.dragViewY, solution.dragViewSpanX,
1915482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                solution.dragViewSpanY, mTmpOccupied, true);
1916482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1917482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1918482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private void animateItemsToSolution(ItemConfiguration solution, View dragView, boolean
1919482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            commitDragView) {
1920482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1921482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        boolean[][] occupied = DESTRUCTIVE_REORDER ? mOccupied : mTmpOccupied;
1922482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < mCountX; i++) {
1923482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            for (int j = 0; j < mCountY; j++) {
1924482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                occupied[i][j] = false;
1925482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1926482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1927482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
1928a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        int childCount = mShortcutsAndWidgets.getChildCount();
1929482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < childCount; i++) {
1930a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            View child = mShortcutsAndWidgets.getChildAt(i);
1931482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (child == dragView) continue;
19328baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            CellAndSpan c = solution.map.get(child);
19338baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            if (c != null) {
193419f3792523fe2d55ea791a9286398a6120920690Adam Cohen                animateChildToPosition(child, c.x, c.y, REORDER_ANIMATION_DURATION, 0,
193519f3792523fe2d55ea791a9286398a6120920690Adam Cohen                        DESTRUCTIVE_REORDER, false);
19368baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen                markCellsForView(c.x, c.y, c.spanX, c.spanY, occupied, true);
1937482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
1938482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1939482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (commitDragView) {
1940482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            markCellsForView(solution.dragViewX, solution.dragViewY, solution.dragViewSpanX,
1941482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    solution.dragViewSpanY, occupied, true);
1942482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
1943482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
1944482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
194519f3792523fe2d55ea791a9286398a6120920690Adam Cohen    // This method starts or changes the reorder hint animations
194619f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private void beginOrAdjustHintAnimations(ItemConfiguration solution, View dragView, int delay) {
194719f3792523fe2d55ea791a9286398a6120920690Adam Cohen        int childCount = mShortcutsAndWidgets.getChildCount();
194819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        int timeForPriorAnimationToComplete = getMaxCompletionTime();
194919f3792523fe2d55ea791a9286398a6120920690Adam Cohen        for (int i = 0; i < childCount; i++) {
195019f3792523fe2d55ea791a9286398a6120920690Adam Cohen            View child = mShortcutsAndWidgets.getChildAt(i);
195119f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (child == dragView) continue;
195219f3792523fe2d55ea791a9286398a6120920690Adam Cohen            CellAndSpan c = solution.map.get(child);
195319f3792523fe2d55ea791a9286398a6120920690Adam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
195419f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (c != null) {
195519f3792523fe2d55ea791a9286398a6120920690Adam Cohen                ReorderHintAnimation rha = new ReorderHintAnimation(child, lp.cellX, lp.cellY,
195619f3792523fe2d55ea791a9286398a6120920690Adam Cohen                        c.x, c.y, c.spanX, c.spanY);
195719f3792523fe2d55ea791a9286398a6120920690Adam Cohen                rha.animate(timeForPriorAnimationToComplete);
195819f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
195919f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
196019f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
196119f3792523fe2d55ea791a9286398a6120920690Adam Cohen
196219f3792523fe2d55ea791a9286398a6120920690Adam Cohen    // Class which represents the reorder hint animations. These animations show that an item is
196319f3792523fe2d55ea791a9286398a6120920690Adam Cohen    // in a temporary state, and hint at where the item will return to.
196419f3792523fe2d55ea791a9286398a6120920690Adam Cohen    class ReorderHintAnimation {
196519f3792523fe2d55ea791a9286398a6120920690Adam Cohen        View child;
196619f3792523fe2d55ea791a9286398a6120920690Adam Cohen        float deltaX;
196719f3792523fe2d55ea791a9286398a6120920690Adam Cohen        float deltaY;
196819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        private static final int DURATION = 140;
196919f3792523fe2d55ea791a9286398a6120920690Adam Cohen        private int repeatCount;
197019f3792523fe2d55ea791a9286398a6120920690Adam Cohen        private boolean cancelOnCycleComplete = false;
197119f3792523fe2d55ea791a9286398a6120920690Adam Cohen        ValueAnimator va;
197219f3792523fe2d55ea791a9286398a6120920690Adam Cohen
197319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        public ReorderHintAnimation(View child, int cellX0, int cellY0, int cellX1, int cellY1,
197419f3792523fe2d55ea791a9286398a6120920690Adam Cohen                int spanX, int spanY) {
197519f3792523fe2d55ea791a9286398a6120920690Adam Cohen            regionToCenterPoint(cellX0, cellY0, spanX, spanY, mTmpPoint);
197619f3792523fe2d55ea791a9286398a6120920690Adam Cohen            final int x0 = mTmpPoint[0];
197719f3792523fe2d55ea791a9286398a6120920690Adam Cohen            final int y0 = mTmpPoint[1];
197819f3792523fe2d55ea791a9286398a6120920690Adam Cohen            regionToCenterPoint(cellX1, cellY1, spanX, spanY, mTmpPoint);
197919f3792523fe2d55ea791a9286398a6120920690Adam Cohen            final int x1 = mTmpPoint[0];
198019f3792523fe2d55ea791a9286398a6120920690Adam Cohen            final int y1 = mTmpPoint[1];
198119f3792523fe2d55ea791a9286398a6120920690Adam Cohen            final int dX = x1 - x0;
198219f3792523fe2d55ea791a9286398a6120920690Adam Cohen            final int dY = y1 - y0;
198319f3792523fe2d55ea791a9286398a6120920690Adam Cohen            deltaX = 0;
198419f3792523fe2d55ea791a9286398a6120920690Adam Cohen            deltaY = 0;
198519f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (dX == dY && dX == 0) {
198619f3792523fe2d55ea791a9286398a6120920690Adam Cohen            } else {
198719f3792523fe2d55ea791a9286398a6120920690Adam Cohen                if (dY == 0) {
198819f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    deltaX = mReorderHintAnimationMagnitude;
198919f3792523fe2d55ea791a9286398a6120920690Adam Cohen                } else if (dX == 0) {
199019f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    deltaY = mReorderHintAnimationMagnitude;
199119f3792523fe2d55ea791a9286398a6120920690Adam Cohen                } else {
199219f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    double angle = Math.atan( (float) (dY) / dX);
199319f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    deltaX = (int) (Math.cos(angle) * mReorderHintAnimationMagnitude);
199419f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    deltaY = (int) (Math.sin(angle) * mReorderHintAnimationMagnitude);
199519f3792523fe2d55ea791a9286398a6120920690Adam Cohen                }
199619f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
199719f3792523fe2d55ea791a9286398a6120920690Adam Cohen            this.child = child;
199819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
199919f3792523fe2d55ea791a9286398a6120920690Adam Cohen
200019f3792523fe2d55ea791a9286398a6120920690Adam Cohen        void animate(int delay) {
200119f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (mShakeAnimators.containsKey(child)) {
200219f3792523fe2d55ea791a9286398a6120920690Adam Cohen                ReorderHintAnimation oldAnimation = mShakeAnimators.get(child);
200319f3792523fe2d55ea791a9286398a6120920690Adam Cohen                oldAnimation.completeAnimation();
200419f3792523fe2d55ea791a9286398a6120920690Adam Cohen                mShakeAnimators.remove(child);
200519f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
200619f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (deltaX == 0 && deltaY == 0) {
200719f3792523fe2d55ea791a9286398a6120920690Adam Cohen                return;
200819f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
200919f3792523fe2d55ea791a9286398a6120920690Adam Cohen            va = ValueAnimator.ofFloat(0f, 1f);
201019f3792523fe2d55ea791a9286398a6120920690Adam Cohen            va.setRepeatMode(ValueAnimator.REVERSE);
201119f3792523fe2d55ea791a9286398a6120920690Adam Cohen            va.setRepeatCount(ValueAnimator.INFINITE);
201219f3792523fe2d55ea791a9286398a6120920690Adam Cohen            va.setDuration(DURATION);
201319f3792523fe2d55ea791a9286398a6120920690Adam Cohen            va.addUpdateListener(new AnimatorUpdateListener() {
201419f3792523fe2d55ea791a9286398a6120920690Adam Cohen                @Override
201519f3792523fe2d55ea791a9286398a6120920690Adam Cohen                public void onAnimationUpdate(ValueAnimator animation) {
201619f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    float r = ((Float) animation.getAnimatedValue()).floatValue();
201719f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    float x = r * deltaX;
201819f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    float y = r * deltaY;
201919f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    child.setTranslationX(x);
202019f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    child.setTranslationY(y);
202119f3792523fe2d55ea791a9286398a6120920690Adam Cohen                }
202219f3792523fe2d55ea791a9286398a6120920690Adam Cohen            });
202319f3792523fe2d55ea791a9286398a6120920690Adam Cohen            va.addListener(new AnimatorListenerAdapter() {
202419f3792523fe2d55ea791a9286398a6120920690Adam Cohen                public void onAnimationRepeat(Animator animation) {
202519f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    repeatCount++;
202619f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    // We make sure to end only after a full period
202719f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    if (cancelOnCycleComplete && repeatCount % 2 == 0) {
202819f3792523fe2d55ea791a9286398a6120920690Adam Cohen                        va.cancel();
202919f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    }
203019f3792523fe2d55ea791a9286398a6120920690Adam Cohen                }
203119f3792523fe2d55ea791a9286398a6120920690Adam Cohen            });
203219f3792523fe2d55ea791a9286398a6120920690Adam Cohen            va.setStartDelay(Math.max(REORDER_ANIMATION_DURATION, delay));
203319f3792523fe2d55ea791a9286398a6120920690Adam Cohen            mShakeAnimators.put(child, this);
203419f3792523fe2d55ea791a9286398a6120920690Adam Cohen            va.start();
203519f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
203619f3792523fe2d55ea791a9286398a6120920690Adam Cohen
203719f3792523fe2d55ea791a9286398a6120920690Adam Cohen
203819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        private void completeAnimation() {
203919f3792523fe2d55ea791a9286398a6120920690Adam Cohen            cancelOnCycleComplete = true;
204019f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
204119f3792523fe2d55ea791a9286398a6120920690Adam Cohen
204219f3792523fe2d55ea791a9286398a6120920690Adam Cohen        // Returns the time required to complete the current oscillating animation
204319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        private int completionTime() {
204419f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (repeatCount % 2 == 0) {
204519f3792523fe2d55ea791a9286398a6120920690Adam Cohen                return (int) (va.getDuration() - va.getCurrentPlayTime() + DURATION);
204619f3792523fe2d55ea791a9286398a6120920690Adam Cohen            } else {
204719f3792523fe2d55ea791a9286398a6120920690Adam Cohen                return (int) (va.getDuration() - va.getCurrentPlayTime());
204819f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
204919f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
205019f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
205119f3792523fe2d55ea791a9286398a6120920690Adam Cohen
205219f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private void completeAndClearReorderHintAnimations() {
205319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        for (ReorderHintAnimation a: mShakeAnimators.values()) {
205419f3792523fe2d55ea791a9286398a6120920690Adam Cohen            a.completeAnimation();
205519f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
205619f3792523fe2d55ea791a9286398a6120920690Adam Cohen        mShakeAnimators.clear();
205719f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
205819f3792523fe2d55ea791a9286398a6120920690Adam Cohen
205919f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private int getMaxCompletionTime() {
206019f3792523fe2d55ea791a9286398a6120920690Adam Cohen        int maxTime = 0;
206119f3792523fe2d55ea791a9286398a6120920690Adam Cohen        for (ReorderHintAnimation a: mShakeAnimators.values()) {
206219f3792523fe2d55ea791a9286398a6120920690Adam Cohen            maxTime = Math.max(maxTime, a.completionTime());
206319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
206419f3792523fe2d55ea791a9286398a6120920690Adam Cohen        return maxTime;
206519f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
206619f3792523fe2d55ea791a9286398a6120920690Adam Cohen
2067482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private void commitTempPlacement() {
2068482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < mCountX; i++) {
2069482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            for (int j = 0; j < mCountY; j++) {
2070482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                mOccupied[i][j] = mTmpOccupied[i][j];
2071482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
2072482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2073a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        int childCount = mShortcutsAndWidgets.getChildCount();
2074482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < childCount; i++) {
2075ea889a294be004f4b1c21e9b874f9e63abfb8bd6Adam Cohen            View child = mShortcutsAndWidgets.getChildAt(i);
2076ea889a294be004f4b1c21e9b874f9e63abfb8bd6Adam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
2077ea889a294be004f4b1c21e9b874f9e63abfb8bd6Adam Cohen            ItemInfo info = (ItemInfo) child.getTag();
20782acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen            // We do a null check here because the item info can be null in the case of the
20792acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen            // AllApps button in the hotseat.
20802acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen            if (info != null) {
20812acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen                info.cellX = lp.cellX = lp.tmpCellX;
20822acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen                info.cellY = lp.cellY = lp.tmpCellY;
2083bebf042666cffe52039b875a549a582abd78a431Adam Cohen                info.spanX = lp.cellHSpan;
2084bebf042666cffe52039b875a549a582abd78a431Adam Cohen                info.spanY = lp.cellVSpan;
20852acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen            }
2086482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
20872acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen        mLauncher.getWorkspace().updateItemLocationsInDatabase(this);
2088482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2089482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2090482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public void setUseTempCoords(boolean useTempCoords) {
2091a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        int childCount = mShortcutsAndWidgets.getChildCount();
2092482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        for (int i = 0; i < childCount; i++) {
2093a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            LayoutParams lp = (LayoutParams) mShortcutsAndWidgets.getChildAt(i).getLayoutParams();
2094482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            lp.useTmpCoords = useTempCoords;
2095482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2096482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2097482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2098482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    ItemConfiguration findConfigurationNoShuffle(int pixelX, int pixelY, int minSpanX, int minSpanY,
2099482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            int spanX, int spanY, View dragView, ItemConfiguration solution) {
2100482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        int[] result = new int[2];
2101482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        int[] resultSpan = new int[2];
2102482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        findNearestVacantArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, null, result,
2103482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                resultSpan);
2104482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (result[0] >= 0 && result[1] >= 0) {
2105482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            copyCurrentStateToSolution(solution, false);
2106482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewX = result[0];
2107482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewY = result[1];
2108482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewSpanX = resultSpan[0];
2109482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.dragViewSpanY = resultSpan[1];
2110482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.isSolution = true;
2111482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        } else {
2112482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            solution.isSolution = false;
2113482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2114482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return solution;
2115482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2116482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2117482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public void prepareChildForDrag(View child) {
2118482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsAsUnoccupiedForView(child);
2119482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2120482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
212119f3792523fe2d55ea791a9286398a6120920690Adam Cohen    /* This seems like it should be obvious and straight-forward, but when the direction vector
212219f3792523fe2d55ea791a9286398a6120920690Adam Cohen    needs to match with the notion of the dragView pushing other views, we have to employ
212319f3792523fe2d55ea791a9286398a6120920690Adam Cohen    a slightly more subtle notion of the direction vector. The question is what two points is
212419f3792523fe2d55ea791a9286398a6120920690Adam Cohen    the vector between? The center of the dragView and its desired destination? Not quite, as
212519f3792523fe2d55ea791a9286398a6120920690Adam Cohen    this doesn't necessarily coincide with the interaction of the dragView and items occupying
212619f3792523fe2d55ea791a9286398a6120920690Adam Cohen    those cells. Instead we use some heuristics to often lock the vector to up, down, left
212719f3792523fe2d55ea791a9286398a6120920690Adam Cohen    or right, which helps make pushing feel right.
212819f3792523fe2d55ea791a9286398a6120920690Adam Cohen    */
212919f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private void getDirectionVectorForDrop(int dragViewCenterX, int dragViewCenterY, int spanX,
213019f3792523fe2d55ea791a9286398a6120920690Adam Cohen            int spanY, View dragView, int[] resultDirection) {
213119f3792523fe2d55ea791a9286398a6120920690Adam Cohen        int[] targetDestination = new int[2];
213219f3792523fe2d55ea791a9286398a6120920690Adam Cohen
213319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        findNearestArea(dragViewCenterX, dragViewCenterY, spanX, spanY, targetDestination);
213419f3792523fe2d55ea791a9286398a6120920690Adam Cohen        Rect dragRect = new Rect();
213519f3792523fe2d55ea791a9286398a6120920690Adam Cohen        regionToRect(targetDestination[0], targetDestination[1], spanX, spanY, dragRect);
213619f3792523fe2d55ea791a9286398a6120920690Adam Cohen        dragRect.offset(dragViewCenterX - dragRect.centerX(), dragViewCenterY - dragRect.centerY());
213719f3792523fe2d55ea791a9286398a6120920690Adam Cohen
213819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        Rect dropRegionRect = new Rect();
213919f3792523fe2d55ea791a9286398a6120920690Adam Cohen        getViewsIntersectingRegion(targetDestination[0], targetDestination[1], spanX, spanY,
214019f3792523fe2d55ea791a9286398a6120920690Adam Cohen                dragView, dropRegionRect, mIntersectingViews);
214119f3792523fe2d55ea791a9286398a6120920690Adam Cohen
214219f3792523fe2d55ea791a9286398a6120920690Adam Cohen        int dropRegionSpanX = dropRegionRect.width();
214319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        int dropRegionSpanY = dropRegionRect.height();
214419f3792523fe2d55ea791a9286398a6120920690Adam Cohen
214519f3792523fe2d55ea791a9286398a6120920690Adam Cohen        regionToRect(dropRegionRect.left, dropRegionRect.top, dropRegionRect.width(),
214619f3792523fe2d55ea791a9286398a6120920690Adam Cohen                dropRegionRect.height(), dropRegionRect);
214719f3792523fe2d55ea791a9286398a6120920690Adam Cohen
214819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        int deltaX = (dropRegionRect.centerX() - dragViewCenterX) / spanX;
214919f3792523fe2d55ea791a9286398a6120920690Adam Cohen        int deltaY = (dropRegionRect.centerY() - dragViewCenterY) / spanY;
215019f3792523fe2d55ea791a9286398a6120920690Adam Cohen
215119f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if (dropRegionSpanX == mCountX || spanX == mCountX) {
215219f3792523fe2d55ea791a9286398a6120920690Adam Cohen            deltaX = 0;
215319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
215419f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if (dropRegionSpanY == mCountY || spanY == mCountY) {
215519f3792523fe2d55ea791a9286398a6120920690Adam Cohen            deltaY = 0;
215619f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
215719f3792523fe2d55ea791a9286398a6120920690Adam Cohen
215819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if (deltaX == 0 && deltaY == 0) {
215919f3792523fe2d55ea791a9286398a6120920690Adam Cohen            // No idea what to do, give a random direction.
216019f3792523fe2d55ea791a9286398a6120920690Adam Cohen            resultDirection[0] = 1;
216119f3792523fe2d55ea791a9286398a6120920690Adam Cohen            resultDirection[1] = 0;
216219f3792523fe2d55ea791a9286398a6120920690Adam Cohen        } else {
216319f3792523fe2d55ea791a9286398a6120920690Adam Cohen            computeDirectionVector(deltaX, deltaY, resultDirection);
216419f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
216519f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
216619f3792523fe2d55ea791a9286398a6120920690Adam Cohen
216719f3792523fe2d55ea791a9286398a6120920690Adam Cohen    // For a given cell and span, fetch the set of views intersecting the region.
216819f3792523fe2d55ea791a9286398a6120920690Adam Cohen    private void getViewsIntersectingRegion(int cellX, int cellY, int spanX, int spanY,
216919f3792523fe2d55ea791a9286398a6120920690Adam Cohen            View dragView, Rect boundingRect, ArrayList<View> intersectingViews) {
217019f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if (boundingRect != null) {
217119f3792523fe2d55ea791a9286398a6120920690Adam Cohen            boundingRect.set(cellX, cellY, cellX + spanX, cellY + spanY);
217219f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
217319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        intersectingViews.clear();
217419f3792523fe2d55ea791a9286398a6120920690Adam Cohen        Rect r0 = new Rect(cellX, cellY, cellX + spanX, cellY + spanY);
217519f3792523fe2d55ea791a9286398a6120920690Adam Cohen        Rect r1 = new Rect();
217619f3792523fe2d55ea791a9286398a6120920690Adam Cohen        final int count = mShortcutsAndWidgets.getChildCount();
217719f3792523fe2d55ea791a9286398a6120920690Adam Cohen        for (int i = 0; i < count; i++) {
217819f3792523fe2d55ea791a9286398a6120920690Adam Cohen            View child = mShortcutsAndWidgets.getChildAt(i);
217919f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (child == dragView) continue;
218019f3792523fe2d55ea791a9286398a6120920690Adam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
218119f3792523fe2d55ea791a9286398a6120920690Adam Cohen            r1.set(lp.cellX, lp.cellY, lp.cellX + lp.cellHSpan, lp.cellY + lp.cellVSpan);
218219f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (Rect.intersects(r0, r1)) {
218319f3792523fe2d55ea791a9286398a6120920690Adam Cohen                mIntersectingViews.add(child);
218419f3792523fe2d55ea791a9286398a6120920690Adam Cohen                if (boundingRect != null) {
218519f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    boundingRect.union(r1);
218619f3792523fe2d55ea791a9286398a6120920690Adam Cohen                }
218719f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
218819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
218919f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
219019f3792523fe2d55ea791a9286398a6120920690Adam Cohen
219119f3792523fe2d55ea791a9286398a6120920690Adam Cohen    boolean isNearestDropLocationOccupied(int pixelX, int pixelY, int spanX, int spanY,
219219f3792523fe2d55ea791a9286398a6120920690Adam Cohen            View dragView, int[] result) {
219319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        result = findNearestArea(pixelX, pixelY, spanX, spanY, result);
219419f3792523fe2d55ea791a9286398a6120920690Adam Cohen        getViewsIntersectingRegion(result[0], result[1], spanX, spanY, dragView, null,
219519f3792523fe2d55ea791a9286398a6120920690Adam Cohen                mIntersectingViews);
219619f3792523fe2d55ea791a9286398a6120920690Adam Cohen        return !mIntersectingViews.isEmpty();
219719f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
219819f3792523fe2d55ea791a9286398a6120920690Adam Cohen
219919f3792523fe2d55ea791a9286398a6120920690Adam Cohen    void revertTempState() {
220019f3792523fe2d55ea791a9286398a6120920690Adam Cohen        if (!isItemPlacementDirty() || DESTRUCTIVE_REORDER) return;
220119f3792523fe2d55ea791a9286398a6120920690Adam Cohen        final int count = mShortcutsAndWidgets.getChildCount();
220219f3792523fe2d55ea791a9286398a6120920690Adam Cohen        for (int i = 0; i < count; i++) {
220319f3792523fe2d55ea791a9286398a6120920690Adam Cohen            View child = mShortcutsAndWidgets.getChildAt(i);
220419f3792523fe2d55ea791a9286398a6120920690Adam Cohen            LayoutParams lp = (LayoutParams) child.getLayoutParams();
220519f3792523fe2d55ea791a9286398a6120920690Adam Cohen            if (lp.tmpCellX != lp.cellX || lp.tmpCellY != lp.cellY) {
220619f3792523fe2d55ea791a9286398a6120920690Adam Cohen                lp.tmpCellX = lp.cellX;
220719f3792523fe2d55ea791a9286398a6120920690Adam Cohen                lp.tmpCellY = lp.cellY;
220819f3792523fe2d55ea791a9286398a6120920690Adam Cohen                animateChildToPosition(child, lp.cellX, lp.cellY, REORDER_ANIMATION_DURATION,
220919f3792523fe2d55ea791a9286398a6120920690Adam Cohen                        0, false, false);
221019f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
221119f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
221219f3792523fe2d55ea791a9286398a6120920690Adam Cohen        completeAndClearReorderHintAnimations();
221319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        setItemPlacementDirty(false);
221419f3792523fe2d55ea791a9286398a6120920690Adam Cohen    }
221519f3792523fe2d55ea791a9286398a6120920690Adam Cohen
2216bebf042666cffe52039b875a549a582abd78a431Adam Cohen    boolean createAreaForResize(int cellX, int cellY, int spanX, int spanY,
2217bebf042666cffe52039b875a549a582abd78a431Adam Cohen            View dragView, int[] direction, boolean commit) {
2218bebf042666cffe52039b875a549a582abd78a431Adam Cohen        int[] pixelXY = new int[2];
2219bebf042666cffe52039b875a549a582abd78a431Adam Cohen        regionToCenterPoint(cellX, cellY, spanX, spanY, pixelXY);
2220bebf042666cffe52039b875a549a582abd78a431Adam Cohen
2221bebf042666cffe52039b875a549a582abd78a431Adam Cohen        // First we determine if things have moved enough to cause a different layout
2222bebf042666cffe52039b875a549a582abd78a431Adam Cohen        ItemConfiguration swapSolution = simpleSwap(pixelXY[0], pixelXY[1], spanX, spanY,
2223bebf042666cffe52039b875a549a582abd78a431Adam Cohen                 spanX,  spanY, direction, dragView,  true,  new ItemConfiguration());
2224bebf042666cffe52039b875a549a582abd78a431Adam Cohen
2225bebf042666cffe52039b875a549a582abd78a431Adam Cohen        setUseTempCoords(true);
2226bebf042666cffe52039b875a549a582abd78a431Adam Cohen        if (swapSolution != null && swapSolution.isSolution) {
2227bebf042666cffe52039b875a549a582abd78a431Adam Cohen            // If we're just testing for a possible location (MODE_ACCEPT_DROP), we don't bother
2228bebf042666cffe52039b875a549a582abd78a431Adam Cohen            // committing anything or animating anything as we just want to determine if a solution
2229bebf042666cffe52039b875a549a582abd78a431Adam Cohen            // exists
2230bebf042666cffe52039b875a549a582abd78a431Adam Cohen            copySolutionToTempState(swapSolution, dragView);
2231bebf042666cffe52039b875a549a582abd78a431Adam Cohen            setItemPlacementDirty(true);
2232bebf042666cffe52039b875a549a582abd78a431Adam Cohen            animateItemsToSolution(swapSolution, dragView, commit);
2233bebf042666cffe52039b875a549a582abd78a431Adam Cohen
2234bebf042666cffe52039b875a549a582abd78a431Adam Cohen            if (commit) {
2235bebf042666cffe52039b875a549a582abd78a431Adam Cohen                commitTempPlacement();
2236bebf042666cffe52039b875a549a582abd78a431Adam Cohen                completeAndClearReorderHintAnimations();
2237bebf042666cffe52039b875a549a582abd78a431Adam Cohen                setItemPlacementDirty(false);
2238bebf042666cffe52039b875a549a582abd78a431Adam Cohen            } else {
2239bebf042666cffe52039b875a549a582abd78a431Adam Cohen                beginOrAdjustHintAnimations(swapSolution, dragView,
2240bebf042666cffe52039b875a549a582abd78a431Adam Cohen                        REORDER_ANIMATION_DURATION);
2241bebf042666cffe52039b875a549a582abd78a431Adam Cohen            }
2242bebf042666cffe52039b875a549a582abd78a431Adam Cohen            mShortcutsAndWidgets.requestLayout();
2243bebf042666cffe52039b875a549a582abd78a431Adam Cohen        }
2244bebf042666cffe52039b875a549a582abd78a431Adam Cohen        return swapSolution.isSolution;
2245bebf042666cffe52039b875a549a582abd78a431Adam Cohen    }
2246bebf042666cffe52039b875a549a582abd78a431Adam Cohen
2247482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    int[] createArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, int spanY,
2248482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            View dragView, int[] result, int resultSpan[], int mode) {
2249482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // First we determine if things have moved enough to cause a different layout
225047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen        result = findNearestArea(pixelX, pixelY, spanX, spanY, result);
2251482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2252482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (resultSpan == null) {
2253482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            resultSpan = new int[2];
2254482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2255482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
225619f3792523fe2d55ea791a9286398a6120920690Adam Cohen        // When we are checking drop validity or actually dropping, we don't recompute the
225719f3792523fe2d55ea791a9286398a6120920690Adam Cohen        // direction vector, since we want the solution to match the preview, and it's possible
225819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        // that the exact position of the item has changed to result in a new reordering outcome.
2259b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen        if ((mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL || mode == MODE_ACCEPT_DROP)
2260b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen               && mPreviousReorderDirection[0] != INVALID_DIRECTION) {
226119f3792523fe2d55ea791a9286398a6120920690Adam Cohen            mDirectionVector[0] = mPreviousReorderDirection[0];
226219f3792523fe2d55ea791a9286398a6120920690Adam Cohen            mDirectionVector[1] = mPreviousReorderDirection[1];
226319f3792523fe2d55ea791a9286398a6120920690Adam Cohen            // We reset this vector after drop
2264b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen            if (mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL) {
2265b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen                mPreviousReorderDirection[0] = INVALID_DIRECTION;
2266b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen                mPreviousReorderDirection[1] = INVALID_DIRECTION;
226719f3792523fe2d55ea791a9286398a6120920690Adam Cohen            }
226819f3792523fe2d55ea791a9286398a6120920690Adam Cohen        } else {
226919f3792523fe2d55ea791a9286398a6120920690Adam Cohen            getDirectionVectorForDrop(pixelX, pixelY, spanX, spanY, dragView, mDirectionVector);
227019f3792523fe2d55ea791a9286398a6120920690Adam Cohen            mPreviousReorderDirection[0] = mDirectionVector[0];
227119f3792523fe2d55ea791a9286398a6120920690Adam Cohen            mPreviousReorderDirection[1] = mDirectionVector[1];
227219f3792523fe2d55ea791a9286398a6120920690Adam Cohen        }
227319f3792523fe2d55ea791a9286398a6120920690Adam Cohen
2274482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        ItemConfiguration swapSolution = simpleSwap(pixelX, pixelY, minSpanX, minSpanY,
2275482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                 spanX,  spanY, mDirectionVector, dragView,  true,  new ItemConfiguration());
2276482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2277482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        // We attempt the approach which doesn't shuffle views at all
2278482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        ItemConfiguration noShuffleSolution = findConfigurationNoShuffle(pixelX, pixelY, minSpanX,
2279482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                minSpanY, spanX, spanY, dragView, new ItemConfiguration());
2280482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2281482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        ItemConfiguration finalSolution = null;
2282482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (swapSolution.isSolution && swapSolution.area() >= noShuffleSolution.area()) {
2283482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            finalSolution = swapSolution;
2284482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        } else if (noShuffleSolution.isSolution) {
2285482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            finalSolution = noShuffleSolution;
2286482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2287482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2288482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        boolean foundSolution = true;
2289482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (!DESTRUCTIVE_REORDER) {
2290482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            setUseTempCoords(true);
2291482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2292482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2293482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (finalSolution != null) {
2294482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            result[0] = finalSolution.dragViewX;
2295482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            result[1] = finalSolution.dragViewY;
2296482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            resultSpan[0] = finalSolution.dragViewSpanX;
2297482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            resultSpan[1] = finalSolution.dragViewSpanY;
2298482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2299482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            // If we're just testing for a possible location (MODE_ACCEPT_DROP), we don't bother
2300482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            // committing anything or animating anything as we just want to determine if a solution
2301482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            // exists
2302482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            if (mode == MODE_DRAG_OVER || mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL) {
2303482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                if (!DESTRUCTIVE_REORDER) {
2304482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    copySolutionToTempState(finalSolution, dragView);
2305482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                }
2306482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                setItemPlacementDirty(true);
2307482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                animateItemsToSolution(finalSolution, dragView, mode == MODE_ON_DROP);
2308482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
230919f3792523fe2d55ea791a9286398a6120920690Adam Cohen                if (!DESTRUCTIVE_REORDER &&
231019f3792523fe2d55ea791a9286398a6120920690Adam Cohen                        (mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL)) {
2311482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                    commitTempPlacement();
231219f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    completeAndClearReorderHintAnimations();
231319f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    setItemPlacementDirty(false);
231419f3792523fe2d55ea791a9286398a6120920690Adam Cohen                } else {
231519f3792523fe2d55ea791a9286398a6120920690Adam Cohen                    beginOrAdjustHintAnimations(finalSolution, dragView,
231619f3792523fe2d55ea791a9286398a6120920690Adam Cohen                            REORDER_ANIMATION_DURATION);
2317482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                }
2318482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            }
2319482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        } else {
2320482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            foundSolution = false;
2321482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            result[0] = result[1] = resultSpan[0] = resultSpan[1] = -1;
2322482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2323482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2324482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if ((mode == MODE_ON_DROP || !foundSolution) && !DESTRUCTIVE_REORDER) {
2325482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            setUseTempCoords(false);
2326482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2327482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2328a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        mShortcutsAndWidgets.requestLayout();
2329482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return result;
2330482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2331482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
233219f3792523fe2d55ea791a9286398a6120920690Adam Cohen    void setItemPlacementDirty(boolean dirty) {
233319f3792523fe2d55ea791a9286398a6120920690Adam Cohen        mItemPlacementDirty = dirty;
2334482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
233519f3792523fe2d55ea791a9286398a6120920690Adam Cohen    boolean isItemPlacementDirty() {
233619f3792523fe2d55ea791a9286398a6120920690Adam Cohen        return mItemPlacementDirty;
2337482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2338482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2339482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private class ItemConfiguration {
23408baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        HashMap<View, CellAndSpan> map = new HashMap<View, CellAndSpan>();
2341482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        boolean isSolution = false;
2342482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        int dragViewX, dragViewY, dragViewSpanX, dragViewSpanY;
2343482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2344482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        int area() {
2345482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            return dragViewSpanX * dragViewSpanY;
2346482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
23478baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen    }
23488baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen
23498baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen    private class CellAndSpan {
23508baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        int x, y;
23518baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        int spanX, spanY;
23528baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen
23538baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen        public CellAndSpan(int x, int y, int spanX, int spanY) {
23548baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            this.x = x;
23558baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            this.y = y;
23568baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            this.spanX = spanX;
23578baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen            this.spanY = spanY;
2358482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        }
2359482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2360482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2361df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    /**
2362df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * Find a vacant area that will fit the given bounds nearest the requested
2363df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * cell location. Uses Euclidean distance to score multiple vacant areas.
2364df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     *
2365df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param pixelX The X location at which you want to search for a vacant area.
2366df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param pixelY The Y location at which you want to search for a vacant area.
2367df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param spanX Horizontal span of the object.
2368df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param spanY Vertical span of the object.
2369df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param ignoreView Considers space occupied by this view as unoccupied
2370df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param result Previously returned value to possibly recycle.
2371df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @return The X, Y cell of a vacant area that can contain this object,
2372df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     *         nearest the requested location.
2373df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     */
2374df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    int[] findNearestVacantArea(
2375df0353815c629fc678824b07a234b89a1ff94208Adam Cohen            int pixelX, int pixelY, int spanX, int spanY, View ignoreView, int[] result) {
2376df0353815c629fc678824b07a234b89a1ff94208Adam Cohen        return findNearestArea(pixelX, pixelY, spanX, spanY, ignoreView, true, result);
2377df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    }
2378df0353815c629fc678824b07a234b89a1ff94208Adam Cohen
2379df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    /**
2380d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * Find a vacant area that will fit the given bounds nearest the requested
2381d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * cell location. Uses Euclidean distance to score multiple vacant areas.
2382d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *
2383d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param pixelX The X location at which you want to search for a vacant area.
2384d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param pixelY The Y location at which you want to search for a vacant area.
2385d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param minSpanX The minimum horizontal span required
2386d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param minSpanY The minimum vertical span required
2387d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param spanX Horizontal span of the object.
2388d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param spanY Vertical span of the object.
2389d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param ignoreView Considers space occupied by this view as unoccupied
2390d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @param result Previously returned value to possibly recycle.
2391d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     * @return The X, Y cell of a vacant area that can contain this object,
2392d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     *         nearest the requested location.
2393d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen     */
2394d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    int[] findNearestVacantArea(int pixelX, int pixelY, int minSpanX, int minSpanY,
2395d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen            int spanX, int spanY, View ignoreView, int[] result, int[] resultSpan) {
2396482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return findNearestArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, ignoreView, true,
2397482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                result, resultSpan, mOccupied);
2398d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    }
2399d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen
2400d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    /**
2401df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * Find a starting cell position that will fit the given bounds nearest the requested
2402df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * cell location. Uses Euclidean distance to score multiple vacant areas.
2403df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     *
2404df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param pixelX The X location at which you want to search for a vacant area.
2405df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param pixelY The Y location at which you want to search for a vacant area.
2406df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param spanX Horizontal span of the object.
2407df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param spanY Vertical span of the object.
2408df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param ignoreView Considers space occupied by this view as unoccupied
2409df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @param result Previously returned value to possibly recycle.
2410df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     * @return The X, Y cell of a vacant area that can contain this object,
2411df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     *         nearest the requested location.
2412df0353815c629fc678824b07a234b89a1ff94208Adam Cohen     */
2413df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    int[] findNearestArea(
2414df0353815c629fc678824b07a234b89a1ff94208Adam Cohen            int pixelX, int pixelY, int spanX, int spanY, int[] result) {
2415df0353815c629fc678824b07a234b89a1ff94208Adam Cohen        return findNearestArea(pixelX, pixelY, spanX, spanY, null, false, result);
2416df0353815c629fc678824b07a234b89a1ff94208Adam Cohen    }
2417df0353815c629fc678824b07a234b89a1ff94208Adam Cohen
24180280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    boolean existsEmptyCell() {
24190280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        return findCellForSpan(null, 1, 1);
24200280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
24210280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
24220280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    /**
24230280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * Finds the upper-left coordinate of the first rectangle in the grid that can
24240280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * hold a cell of the specified dimensions. If intersectX and intersectY are not -1,
24250280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * then this method will only return coordinates for rectangles that contain the cell
24260280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * (intersectX, intersectY)
24270280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     *
24280280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param cellXY The array that will contain the position of a vacant cell if such a cell
24290280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     *               can be found.
24300280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param spanX The horizontal span of the cell we want to find.
24310280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param spanY The vertical span of the cell we want to find.
24320280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     *
24330280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @return True if a vacant cell of the specified dimension was found, false otherwise.
24340280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     */
24350280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    boolean findCellForSpan(int[] cellXY, int spanX, int spanY) {
2436482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return findCellForSpanThatIntersectsIgnoring(cellXY, spanX, spanY, -1, -1, null, mOccupied);
24370280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
24380280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
24390280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    /**
24400280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * Like above, but ignores any cells occupied by the item "ignoreView"
24410280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     *
24420280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param cellXY The array that will contain the position of a vacant cell if such a cell
24430280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     *               can be found.
24440280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param spanX The horizontal span of the cell we want to find.
24450280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param spanY The vertical span of the cell we want to find.
24460280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param ignoreView The home screen item we should treat as not occupying any space
24470280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @return
24480280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     */
24490280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    boolean findCellForSpanIgnoring(int[] cellXY, int spanX, int spanY, View ignoreView) {
2450482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        return findCellForSpanThatIntersectsIgnoring(cellXY, spanX, spanY, -1, -1,
2451482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                ignoreView, mOccupied);
24520280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
24530280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
24540280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    /**
24550280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * Like above, but if intersectX and intersectY are not -1, then this method will try to
24560280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * return coordinates for rectangles that contain the cell [intersectX, intersectY]
24570280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     *
24580280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param spanX The horizontal span of the cell we want to find.
24590280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param spanY The vertical span of the cell we want to find.
24600280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param ignoreView The home screen item we should treat as not occupying any space
24610280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param intersectX The X coordinate of the cell that we should try to overlap
24620280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @param intersectX The Y coordinate of the cell that we should try to overlap
24630280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     *
24640280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * @return True if a vacant cell of the specified dimension was found, false otherwise.
24650280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     */
24660280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    boolean findCellForSpanThatIntersects(int[] cellXY, int spanX, int spanY,
24670280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            int intersectX, int intersectY) {
24680280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        return findCellForSpanThatIntersectsIgnoring(
2469482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                cellXY, spanX, spanY, intersectX, intersectY, null, mOccupied);
24700280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
24710280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
24720280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    /**
24730280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * The superset of the above two methods
24740280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     */
24750280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    boolean findCellForSpanThatIntersectsIgnoring(int[] cellXY, int spanX, int spanY,
2476482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            int intersectX, int intersectY, View ignoreView, boolean occupied[][]) {
2477c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka        // mark space take by ignoreView as available (method checks if ignoreView is null)
2478482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsAsUnoccupiedForView(ignoreView, occupied);
24790280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
248028750fba6a2d141eb9a1e566718c17236030b815Michael Jurka        boolean foundCell = false;
24810280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        while (true) {
24820280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            int startX = 0;
24830280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            if (intersectX >= 0) {
24840280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                startX = Math.max(startX, intersectX - (spanX - 1));
24850280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            }
24860280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            int endX = mCountX - (spanX - 1);
24870280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            if (intersectX >= 0) {
24880280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                endX = Math.min(endX, intersectX + (spanX - 1) + (spanX == 1 ? 1 : 0));
24890280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            }
24900280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            int startY = 0;
24910280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            if (intersectY >= 0) {
24920280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                startY = Math.max(startY, intersectY - (spanY - 1));
24930280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            }
24940280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            int endY = mCountY - (spanY - 1);
24950280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            if (intersectY >= 0) {
24960280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                endY = Math.min(endY, intersectY + (spanY - 1) + (spanY == 1 ? 1 : 0));
24970280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            }
24980280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
2499bbc60d8e79416e37cbede55c159bf6aaa6c171d5Winson Chung            for (int y = startY; y < endY && !foundCell; y++) {
25000280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                inner:
2501bbc60d8e79416e37cbede55c159bf6aaa6c171d5Winson Chung                for (int x = startX; x < endX; x++) {
25020280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                    for (int i = 0; i < spanX; i++) {
25030280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                        for (int j = 0; j < spanY; j++) {
2504482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                            if (occupied[x + i][y + j]) {
2505bbc60d8e79416e37cbede55c159bf6aaa6c171d5Winson Chung                                // small optimization: we can skip to after the column we just found
25060280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                                // an occupied cell
2507bbc60d8e79416e37cbede55c159bf6aaa6c171d5Winson Chung                                x += i;
25080280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                                continue inner;
25090280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                            }
25100280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                        }
25110280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                    }
25120280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                    if (cellXY != null) {
25130280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                        cellXY[0] = x;
25140280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                        cellXY[1] = y;
25150280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                    }
251628750fba6a2d141eb9a1e566718c17236030b815Michael Jurka                    foundCell = true;
251728750fba6a2d141eb9a1e566718c17236030b815Michael Jurka                    break;
25180280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                }
25190280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            }
25200280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            if (intersectX == -1 && intersectY == -1) {
25210280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                break;
25220280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            } else {
25230280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                // if we failed to find anything, try again but without any requirements of
25240280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                // intersecting
25250280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                intersectX = -1;
25260280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                intersectY = -1;
25270280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                continue;
25280280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            }
25290280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        }
25300280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
2531c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka        // re-mark space taken by ignoreView as occupied
2532482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsAsOccupiedForView(ignoreView, occupied);
253328750fba6a2d141eb9a1e566718c17236030b815Michael Jurka        return foundCell;
25340280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
25350280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
253631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
2537c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung     * A drag event has begun over this layout.
2538c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung     * It may have begun over this layout (in which case onDragChild is called first),
2539c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung     * or it may have begun on another layout.
2540c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung     */
2541c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung    void onDragEnter() {
2542c6cc61d45836e4081920883cc4d448ccb0bb8417Adam Cohen        mDragEnforcer.onDragEnter();
2543c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung        mDragging = true;
2544c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung    }
2545c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung
2546c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung    /**
25470280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka     * Called when drag has left this CellLayout or has been completed (successfully or not)
25486569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     */
25490280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    void onDragExit() {
2550c6cc61d45836e4081920883cc4d448ccb0bb8417Adam Cohen        mDragEnforcer.onDragExit();
25514be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        // This can actually be called when we aren't in a drag, e.g. when adding a new
25524be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        // item to this layout via the customize drawer.
25534be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        // Guard against that case.
25544be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        if (mDragging) {
25554be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato            mDragging = false;
25564be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        }
255708ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy
255808ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy        // Invalidate the drag data
2559d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen        mDragCell[0] = mDragCell[1] = -1;
256008ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy        mDragOutlineAnims[mDragOutlineCurrent].animateOut();
256108ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy        mDragOutlineCurrent = (mDragOutlineCurrent + 1) % mDragOutlineAnims.length;
256219f3792523fe2d55ea791a9286398a6120920690Adam Cohen        revertTempState();
256333945b21544bc98381df17726a3537c292d8c985Michael Jurka        setIsDragOverlapping(false);
25646569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    }
25656569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy
25666569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy    /**
2567aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     * Mark a child as having been dropped.
2568de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy     * At the beginning of the drag operation, the child may have been on another
2569ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy     * screen, but it is re-parented before this method is called.
257031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     *
257131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param child The child that is being dropped
257231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
2573716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen    void onDropChild(View child) {
2574d94533d04a5f8f5485f106d10af60169857ea899Romain Guy        if (child != null) {
2575d94533d04a5f8f5485f106d10af60169857ea899Romain Guy            LayoutParams lp = (LayoutParams) child.getLayoutParams();
257684f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy            lp.dropped = true;
2577d94533d04a5f8f5485f106d10af60169857ea899Romain Guy            child.requestLayout();
2578d94533d04a5f8f5485f106d10af60169857ea899Romain Guy        }
257931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
258031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
258131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
258231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * Computes a bounding rectangle for a range of cells
2583aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     *
258431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param cellX X coordinate of upper left corner expressed as a cell position
258531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param cellY Y coordinate of upper left corner expressed as a cell position
2586aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     * @param cellHSpan Width in cells
258731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param cellVSpan Height in cells
25886569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy     * @param resultRect Rect into which to put the results
258931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
2590d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    public void cellToRect(int cellX, int cellY, int cellHSpan, int cellVSpan, Rect resultRect) {
259131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        final int cellWidth = mCellWidth;
259231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        final int cellHeight = mCellHeight;
259331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        final int widthGap = mWidthGap;
259431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        final int heightGap = mHeightGap;
2595aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
25964b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int hStartPadding = getPaddingLeft();
25974b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        final int vStartPadding = getPaddingTop();
2598aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
259931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int width = cellHSpan * cellWidth + ((cellHSpan - 1) * widthGap);
260031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int height = cellVSpan * cellHeight + ((cellVSpan - 1) * heightGap);
260131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
260231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int x = hStartPadding + cellX * (cellWidth + widthGap);
260331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int y = vStartPadding + cellY * (cellHeight + heightGap);
2604aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
26056569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy        resultRect.set(x, y, x + width, y + height);
260631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
2607aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
260831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
2609aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     * Computes the required horizontal and vertical cell spans to always
261031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * fit the given rectangle.
2611aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     *
261231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param width Width in pixels
261331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param height Height in pixels
26148f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy     * @param result An array of length 2 in which to store the result (may be null).
261531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
26168f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy    public int[] rectToCell(int width, int height, int[] result) {
26179987a5c45e7d01a780d73b269bdce8d8a5309219Michael Jurka        return rectToCell(getResources(), width, height, result);
26189987a5c45e7d01a780d73b269bdce8d8a5309219Michael Jurka    }
26199987a5c45e7d01a780d73b269bdce8d8a5309219Michael Jurka
26209987a5c45e7d01a780d73b269bdce8d8a5309219Michael Jurka    public static int[] rectToCell(Resources resources, int width, int height, int[] result) {
262131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // Always assume we're working with the smallest span to make sure we
262231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // reserve enough space in both orientations.
262379e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato        int actualWidth = resources.getDimensionPixelSize(R.dimen.workspace_cell_width);
262479e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato        int actualHeight = resources.getDimensionPixelSize(R.dimen.workspace_cell_height);
262531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int smallerSize = Math.min(actualWidth, actualHeight);
262679e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato
262731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // Always round up to next largest cell
262854c725cc294cd43ed0650179bfae64a622547660Winson Chung        int spanX = (int) Math.ceil(width / (float) smallerSize);
262954c725cc294cd43ed0650179bfae64a622547660Winson Chung        int spanY = (int) Math.ceil(height / (float) smallerSize);
263079e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato
26318f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy        if (result == null) {
26328f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy            return new int[] { spanX, spanY };
26338f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy        }
26348f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy        result[0] = spanX;
26358f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy        result[1] = spanY;
26368f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy        return result;
263731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
263831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
2639f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka    public int[] cellSpansToSize(int hSpans, int vSpans) {
2640f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka        int[] size = new int[2];
2641f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka        size[0] = hSpans * mCellWidth + (hSpans - 1) * mWidthGap;
2642f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka        size[1] = vSpans * mCellHeight + (vSpans - 1) * mHeightGap;
2643f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka        return size;
2644f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka    }
2645f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka
264631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
2647047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy     * Calculate the grid spans needed to fit given item
2648047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy     */
2649047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy    public void calculateSpans(ItemInfo info) {
2650047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        final int minWidth;
2651047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        final int minHeight;
2652047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy
2653047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        if (info instanceof LauncherAppWidgetInfo) {
2654047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy            minWidth = ((LauncherAppWidgetInfo) info).minWidth;
2655047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy            minHeight = ((LauncherAppWidgetInfo) info).minHeight;
2656047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        } else if (info instanceof PendingAddWidgetInfo) {
2657047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy            minWidth = ((PendingAddWidgetInfo) info).minWidth;
2658047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy            minHeight = ((PendingAddWidgetInfo) info).minHeight;
2659047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        } else {
2660047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy            // It's not a widget, so it must be 1x1
2661047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy            info.spanX = info.spanY = 1;
2662047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy            return;
2663047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        }
2664047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        int[] spans = rectToCell(minWidth, minHeight, null);
2665047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        info.spanX = spans[0];
2666047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy        info.spanY = spans[1];
2667047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy    }
2668047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy
2669047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy    /**
267031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * Find the first vacant cell, if there is one.
267131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     *
267231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param vacant Holds the x and y coordinate of the vacant cell
267331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param spanX Horizontal cell span.
267431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param spanY Vertical cell span.
2675aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung     *
267631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @return True if a vacant cell was found
267731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
267831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public boolean getVacantCell(int[] vacant, int spanX, int spanY) {
267931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
26800280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        return findVacantCell(vacant, spanX, spanY, mCountX, mCountY, mOccupied);
268131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
268231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
268331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    static boolean findVacantCell(int[] vacant, int spanX, int spanY,
268431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            int xCount, int yCount, boolean[][] occupied) {
268531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
26862801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen        for (int y = 0; y < yCount; y++) {
26872801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen            for (int x = 0; x < xCount; x++) {
268831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                boolean available = !occupied[x][y];
268931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectout:            for (int i = x; i < x + spanX - 1 && x < xCount; i++) {
269031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                    for (int j = y; j < y + spanY - 1 && y < yCount; j++) {
269131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                        available = available && !occupied[i][j];
269231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                        if (!available) break out;
269331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                    }
269431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                }
269531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
269631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                if (available) {
269731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                    vacant[0] = x;
269831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                    vacant[1] = y;
269931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                    return true;
270031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                }
270131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            }
270231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
270331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
270431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        return false;
270531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
270631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
27070280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    private void clearOccupiedCells() {
27080280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        for (int x = 0; x < mCountX; x++) {
27090280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            for (int y = 0; y < mCountY; y++) {
27100280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka                mOccupied[x][y] = false;
271131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            }
271231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
27130280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
271431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
2715d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen    public void onMove(View view, int newCellX, int newCellY, int newSpanX, int newSpanY) {
27160280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        markCellsAsUnoccupiedForView(view);
2717482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsForView(newCellX, newCellY, newSpanX, newSpanY, mOccupied, true);
27180280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
271931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
2720d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    public void markCellsAsOccupiedForView(View view) {
2721482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsAsOccupiedForView(view, mOccupied);
2722482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2723482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public void markCellsAsOccupiedForView(View view, boolean[][] occupied) {
2724a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        if (view == null || view.getParent() != mShortcutsAndWidgets) return;
27250280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        LayoutParams lp = (LayoutParams) view.getLayoutParams();
2726482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, occupied, true);
27270280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
27280280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
2729d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen    public void markCellsAsUnoccupiedForView(View view) {
2730482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsAsUnoccupiedForView(view, mOccupied);
2731482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    }
2732482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    public void markCellsAsUnoccupiedForView(View view, boolean occupied[][]) {
2733a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        if (view == null || view.getParent() != mShortcutsAndWidgets) return;
27340280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        LayoutParams lp = (LayoutParams) view.getLayoutParams();
2735482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, occupied, false);
27360280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    }
27370280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka
2738482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen    private void markCellsForView(int cellX, int cellY, int spanX, int spanY, boolean[][] occupied,
2739482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen            boolean value) {
2740482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        if (cellX < 0 || cellY < 0) return;
27410280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka        for (int x = cellX; x < cellX + spanX && x < mCountX; x++) {
27420280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka            for (int y = cellY; y < cellY + spanY && y < mCountY; y++) {
2743482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                occupied[x][y] = value;
274431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            }
274531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
274631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
274731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
27482801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    public int getDesiredWidth() {
27498b805b17158886035b38261eb611d8641701ae43Michael Jurka        return getPaddingLeft() + getPaddingRight() + (mCountX * mCellWidth) +
27502801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen                (Math.max((mCountX - 1), 0) * mWidthGap);
27512801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    }
27522801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
27532801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    public int getDesiredHeight()  {
27548b805b17158886035b38261eb611d8641701ae43Michael Jurka        return getPaddingTop() + getPaddingBottom() + (mCountY * mCellHeight) +
27552801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen                (Math.max((mCountY - 1), 0) * mHeightGap);
27562801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen    }
27572801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen
275866d72178af91d455700875635473be942bc90e54Michael Jurka    public boolean isOccupied(int x, int y) {
275966d72178af91d455700875635473be942bc90e54Michael Jurka        if (x < mCountX && y < mCountY) {
276066d72178af91d455700875635473be942bc90e54Michael Jurka            return mOccupied[x][y];
276166d72178af91d455700875635473be942bc90e54Michael Jurka        } else {
276266d72178af91d455700875635473be942bc90e54Michael Jurka            throw new RuntimeException("Position exceeds the bound of this CellLayout");
276366d72178af91d455700875635473be942bc90e54Michael Jurka        }
276466d72178af91d455700875635473be942bc90e54Michael Jurka    }
276566d72178af91d455700875635473be942bc90e54Michael Jurka
276631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
276731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
276831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        return new CellLayout.LayoutParams(getContext(), attrs);
276931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
277031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
277131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
277231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
277331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        return p instanceof CellLayout.LayoutParams;
277431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
277531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
277631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    @Override
277731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
277831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        return new CellLayout.LayoutParams(p);
277931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
278031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
2781aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung    public static class CellLayoutAnimationController extends LayoutAnimationController {
2782aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        public CellLayoutAnimationController(Animation animation, float delay) {
2783aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            super(animation, delay);
2784aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        }
2785aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
2786aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        @Override
2787aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        protected long getDelayForView(View view) {
2788aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            return (int) (Math.random() * 150);
2789aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        }
2790aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung    }
2791aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
279231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public static class LayoutParams extends ViewGroup.MarginLayoutParams {
279331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        /**
279431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         * Horizontal location of the item in the grid.
279531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         */
279631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        @ViewDebug.ExportedProperty
279731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public int cellX;
279831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
279931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        /**
280031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         * Vertical location of the item in the grid.
280131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         */
280231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        @ViewDebug.ExportedProperty
280331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public int cellY;
280431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
280531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        /**
2806482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         * Temporary horizontal location of the item in the grid during reorder
2807482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         */
2808482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        public int tmpCellX;
2809482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2810482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        /**
2811482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         * Temporary vertical location of the item in the grid during reorder
2812482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         */
2813482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        public int tmpCellY;
2814482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2815482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        /**
2816482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         * Indicates that the temporary coordinates should be used to layout the items
2817482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         */
2818482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        public boolean useTmpCoords;
2819482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
2820482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        /**
282131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         * Number of cells spanned horizontally by the item.
282231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         */
282331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        @ViewDebug.ExportedProperty
282431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public int cellHSpan;
282531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
282631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        /**
282731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         * Number of cells spanned vertically by the item.
282831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project         */
282931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        @ViewDebug.ExportedProperty
283031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public int cellVSpan;
2831aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
28321b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen        /**
28331b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen         * Indicates whether the item will set its x, y, width and height parameters freely,
28341b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen         * or whether these will be computed based on cellX, cellY, cellHSpan and cellVSpan.
28351b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen         */
2836d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        public boolean isLockedToGrid = true;
2837d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
2838482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        /**
2839482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         * Indicates whether this item can be reordered. Always true except in the case of the
2840482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         * the AllApps button.
2841482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen         */
2842482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen        public boolean canReorder = true;
2843482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen
284431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // X coordinate of the view in the layout.
284531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        @ViewDebug.ExportedProperty
284631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int x;
284731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        // Y coordinate of the view in the layout.
284831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        @ViewDebug.ExportedProperty
284931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int y;
285031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
285184f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy        boolean dropped;
2852fcb9e7144e58614f5ae0e9b272fb7ce040848c67Romain Guy
285331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public LayoutParams(Context c, AttributeSet attrs) {
285431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            super(c, attrs);
285531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            cellHSpan = 1;
285631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            cellVSpan = 1;
285731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
285831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
285931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public LayoutParams(ViewGroup.LayoutParams source) {
286031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            super(source);
286131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            cellHSpan = 1;
286231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            cellVSpan = 1;
286331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
2864aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
2865aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        public LayoutParams(LayoutParams source) {
2866aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            super(source);
2867aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            this.cellX = source.cellX;
2868aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            this.cellY = source.cellY;
2869aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            this.cellHSpan = source.cellHSpan;
2870aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            this.cellVSpan = source.cellVSpan;
2871aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        }
2872aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung
287331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public LayoutParams(int cellX, int cellY, int cellHSpan, int cellVSpan) {
28748f19cdd62f6e2be05e3890916eabd11317ae1bc2Romain Guy            super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
287531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            this.cellX = cellX;
287631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            this.cellY = cellY;
287731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            this.cellHSpan = cellHSpan;
287831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            this.cellVSpan = cellVSpan;
287931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
288031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
28817f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public void setup(int cellWidth, int cellHeight, int widthGap, int heightGap) {
2882d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            if (isLockedToGrid) {
2883d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                final int myCellHSpan = cellHSpan;
2884d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                final int myCellVSpan = cellVSpan;
2885482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                final int myCellX = useTmpCoords ? tmpCellX : cellX;
2886482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen                final int myCellY = useTmpCoords ? tmpCellY : cellY;
28871b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen
2888d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                width = myCellHSpan * cellWidth + ((myCellHSpan - 1) * widthGap) -
2889d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                        leftMargin - rightMargin;
2890d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                height = myCellVSpan * cellHeight + ((myCellVSpan - 1) * heightGap) -
2891d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen                        topMargin - bottomMargin;
2892eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                x = (int) (myCellX * (cellWidth + widthGap) + leftMargin);
2893eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung                y = (int) (myCellY * (cellHeight + heightGap) + topMargin);
2894d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen            }
2895d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen        }
2896d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen
2897aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        public String toString() {
2898aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            return "(" + this.cellX + ", " + this.cellY + ")";
2899aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung        }
29007f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
29017f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public void setWidth(int width) {
29027f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            this.width = width;
29037f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
29047f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
29057f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public int getWidth() {
29067f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            return width;
29077f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
29087f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
29097f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public void setHeight(int height) {
29107f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            this.height = height;
29117f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
29127f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
29137f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public int getHeight() {
29147f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            return height;
29157f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
29167f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
29177f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public void setX(int x) {
29187f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            this.x = x;
29197f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
29207f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
29217f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public int getX() {
29227f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            return x;
29237f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
29247f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
29257f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public void setY(int y) {
29267f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            this.y = y;
29277f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
29287f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen
29297f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        public int getY() {
29307f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen            return y;
29317f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen        }
293231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
293331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
29340280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    // This class stores info for two purposes:
29350280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    // 1. When dragging items (mDragInfo in Workspace), we store the View, its cellX & cellY,
29360280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    //    its spanX, spanY, and the screen it is on
29370280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    // 2. When long clicking on an empty cell in a CellLayout, we save information about the
29380280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    //    cellX and cellY coordinates and which page was clicked. We then set this as a tag on
29390280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka    //    the CellLayout that was long clicked
2940e5fb0f27bca7afb996258a7163c76ca7390d7bffMichael Jurka    static final class CellInfo {
294131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        View cell;
2942a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka        int cellX = -1;
2943a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka        int cellY = -1;
294431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int spanX;
294531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int spanY;
294631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        int screen;
29473d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        long container;
294831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
294931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        @Override
295031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        public String toString() {
2951aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung            return "Cell[view=" + (cell == null ? "null" : cell.getClass())
2952aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung                    + ", x=" + cellX + ", y=" + cellY + "]";
295331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
295431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
2955d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka
2956d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka    public boolean lastDownOnOccupiedCell() {
2957d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka        return mLastDownOnOccupiedCell;
2958d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka    }
295931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project}
2960