CellLayout.java revision 215b416c1f7cf0234b777155b823637a0902739f
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; 20629758ff081a354e43aa409159211210ee4ee85aMichael Jurkaimport android.animation.AnimatorListenerAdapter; 2150e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keelyimport android.animation.AnimatorSet; 2200397b1d9233409d9d6b233b077ae12d09768ce8Chet Haaseimport android.animation.TimeInterpolator; 23de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroyimport android.animation.ValueAnimator; 24de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroyimport android.animation.ValueAnimator.AnimatorUpdateListener; 2531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.content.Context; 2679e56263dbcbe85dc434df372bc6e6730aa13477Joe Onoratoimport android.content.res.Resources; 27aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chungimport android.content.res.TypedArray; 284be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onoratoimport android.graphics.Bitmap; 29aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chungimport android.graphics.Canvas; 300dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynnimport android.graphics.Color; 314be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onoratoimport android.graphics.Paint; 32de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroyimport android.graphics.Point; 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; 391462de39f01cec0ba785386532719cb0207dd827Adam Cohenimport android.os.Parcelable; 4031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.util.AttributeSet; 414be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onoratoimport android.util.Log; 421462de39f01cec0ba785386532719cb0207dd827Adam Cohenimport android.util.SparseArray; 4331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.MotionEvent; 4431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.View; 4531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.ViewDebug; 4631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.ViewGroup; 47aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chungimport android.view.animation.Animation; 48150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chungimport android.view.animation.DecelerateInterpolator; 49aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chungimport android.view.animation.LayoutAnimationController; 5031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 516639687cd67bab1aeef2a75e5c6bc458b20dc082Adam Cohenimport com.android.launcher.R; 5269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohenimport com.android.launcher2.FolderIcon.FolderRingAnimator; 538e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy 5469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohenimport java.util.ArrayList; 55c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohenimport java.util.Arrays; 56bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohenimport java.util.HashMap; 57d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohenimport java.util.Stack; 58c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen 59bdb5c5342adc550559fd723af461e53248f2fba8Michael Jurkapublic class CellLayout extends ViewGroup { 60aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung static final String TAG = "CellLayout"; 61aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 622acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen private Launcher mLauncher; 6331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private int mCellWidth; 6431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private int mCellHeight; 65aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 66d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen private int mCountX; 67d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen private int mCountY; 6831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 69234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen private int mOriginalWidthGap; 70234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen private int mOriginalHeightGap; 7131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private int mWidthGap; 7231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private int mHeightGap; 734b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung private int mMaxGap; 74ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen private boolean mScrollingTransformsDirty = false; 7531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 7631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private final Rect mRect = new Rect(); 7731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private final CellInfo mCellInfo = new CellInfo(); 78aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 79de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy // These are temporary variables to prevent having to allocate a new object just to 80de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy // return an (x, y) value from helper functions. Do NOT use them to maintain other state. 810be025d64c1f84138fe430a58875886e66aae767Winson Chung private final int[] mTmpXY = new int[2]; 82de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy private final int[] mTmpPoint = new int[2]; 8369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen int[] mTempLocation = new int[2]; 846569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 8531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project boolean[][] mOccupied; 86482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean[][] mTmpOccupied; 87d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka private boolean mLastDownOnOccupiedCell = false; 8831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 89dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka private OnTouchListener mInterceptTouchListener; 90dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka 9169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen private ArrayList<FolderRingAnimator> mFolderOuterRings = new ArrayList<FolderRingAnimator>(); 92c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen private int[] mFolderLeaveBehindCell = {-1, -1}; 9369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 94b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen private int mForegroundAlpha = 0; 955f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka private float mBackgroundAlpha; 961b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen private float mBackgroundAlphaMultiplier = 1.0f; 97f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen 9833945b21544bc98381df17726a3537c292d8c985Michael Jurka private Drawable mNormalBackground; 9933945b21544bc98381df17726a3537c292d8c985Michael Jurka private Drawable mActiveGlowBackground; 100b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen private Drawable mOverScrollForegroundDrawable; 101b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen private Drawable mOverScrollLeft; 102b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen private Drawable mOverScrollRight; 10318014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka private Rect mBackgroundRect; 104b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen private Rect mForegroundRect; 105b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen private int mForegroundPadding; 10633945b21544bc98381df17726a3537c292d8c985Michael Jurka 10733945b21544bc98381df17726a3537c292d8c985Michael Jurka // If we're actively dragging something over this screen, mIsDragOverlapping is true 10833945b21544bc98381df17726a3537c292d8c985Michael Jurka private boolean mIsDragOverlapping = false; 109de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy private final Point mDragCenter = new Point(); 1106569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 111150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung // These arrays are used to implement the drag visualization on x-large screens. 1124be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // They are used as circular arrays, indexed by mDragOutlineCurrent. 113d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen private Rect[] mDragOutlines = new Rect[4]; 114472b281d5cb4f5660df981a6c912266b9f5703feChet Haase private float[] mDragOutlineAlphas = new float[mDragOutlines.length]; 1154be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato private InterruptibleInOutAnimator[] mDragOutlineAnims = 1164be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato new InterruptibleInOutAnimator[mDragOutlines.length]; 117150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung 118150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung // Used as an index into the above 3 arrays; indicates which is the most current value. 1194be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato private int mDragOutlineCurrent = 0; 1208e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy private final Paint mDragOutlinePaint = new Paint(); 121150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung 12296864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy private BubbleTextView mPressedOrFocusedIcon; 12396864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy 124482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private HashMap<CellLayout.LayoutParams, Animator> mReorderAnimators = new 125482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen HashMap<CellLayout.LayoutParams, Animator>(); 12619f3792523fe2d55ea791a9286398a6120920690Adam Cohen private HashMap<View, ReorderHintAnimation> 12719f3792523fe2d55ea791a9286398a6120920690Adam Cohen mShakeAnimators = new HashMap<View, ReorderHintAnimation>(); 12819f3792523fe2d55ea791a9286398a6120920690Adam Cohen 12919f3792523fe2d55ea791a9286398a6120920690Adam Cohen private boolean mItemPlacementDirty = false; 130bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen 1316569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy // When a drag operation is in progress, holds the nearest cell to the touch point 1326569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy private final int[] mDragCell = new int[2]; 13331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 1344be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato private boolean mDragging = false; 1354be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato 136ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy private TimeInterpolator mEaseOutInterpolator; 137a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka private ShortcutAndWidgetContainer mShortcutsAndWidgets; 138ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy 1390dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn private boolean mIsHotseat = false; 140307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen private float mHotseatScale = 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 1527bdfc9700b1cad043c04c757f134db1bf3df00daAdam Cohen private static final float REORDER_HINT_MAGNITUDE = 0.12f; 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); 165ca99383daef92fed673de22126875cb485be494fMichael Jurka private final static Paint sPaint = new Paint(); 1668a0bff5e35f63321178bbf777ec24d42544866b3Romain Guy 16731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public CellLayout(Context context) { 16831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this(context, null); 16931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 17031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 17131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public CellLayout(Context context, AttributeSet attrs) { 17231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this(context, attrs, 0); 17331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 17431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 17531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public CellLayout(Context context, AttributeSet attrs, int defStyle) { 17631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project super(context, attrs, defStyle); 1778b805b17158886035b38261eb611d8641701ae43Michael Jurka mDragEnforcer = new DropTarget.DragEnforcer(context); 1786569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 1796569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy // A ViewGroup usually does not draw, but CellLayout needs to draw a rectangle to show 1806569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy // the user where a dragged item will land when dropped. 1816569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy setWillNotDraw(false); 1822acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen mLauncher = (Launcher) context; 183a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka 18431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CellLayout, defStyle, 0); 18531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 186f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen mCellWidth = a.getDimensionPixelSize(R.styleable.CellLayout_cellWidth, 10); 187f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen mCellHeight = a.getDimensionPixelSize(R.styleable.CellLayout_cellHeight, 10); 188234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen mWidthGap = mOriginalWidthGap = a.getDimensionPixelSize(R.styleable.CellLayout_widthGap, 0); 189234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen mHeightGap = mOriginalHeightGap = a.getDimensionPixelSize(R.styleable.CellLayout_heightGap, 0); 1904b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung mMaxGap = a.getDimensionPixelSize(R.styleable.CellLayout_maxGap, 0); 191d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen mCountX = LauncherModel.getCellCountX(); 192d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen mCountY = LauncherModel.getCellCountY(); 1930280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka mOccupied = new boolean[mCountX][mCountY]; 194482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mTmpOccupied = new boolean[mCountX][mCountY]; 1955b53f29f809a0dad4a1e0717ba610ce737ee0f43Adam Cohen mPreviousReorderDirection[0] = INVALID_DIRECTION; 1965b53f29f809a0dad4a1e0717ba610ce737ee0f43Adam Cohen mPreviousReorderDirection[1] = INVALID_DIRECTION; 19731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 19831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project a.recycle(); 19931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 20031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project setAlwaysDrawnWithCacheEnabled(false); 20131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 202046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy final Resources res = getResources(); 203307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen mHotseatScale = (res.getInteger(R.integer.hotseat_item_scale_percentage) / 100f); 204de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy 205967289b6d5fec77f5c381d11ffb2319f3bb5e737Winson Chung mNormalBackground = res.getDrawable(R.drawable.homescreen_blue_normal_holo); 206dea74b7d12b0fcd50bfdb4274f9867ba76d75238Winson Chung mActiveGlowBackground = res.getDrawable(R.drawable.homescreen_blue_strong_holo); 207b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung 208b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mOverScrollLeft = res.getDrawable(R.drawable.overscroll_glow_left); 209b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mOverScrollRight = res.getDrawable(R.drawable.overscroll_glow_right); 210b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mForegroundPadding = 211b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen res.getDimensionPixelSize(R.dimen.workspace_overscroll_drawable_padding); 212b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung 21319f3792523fe2d55ea791a9286398a6120920690Adam Cohen mReorderHintAnimationMagnitude = (REORDER_HINT_MAGNITUDE * 21419f3792523fe2d55ea791a9286398a6120920690Adam Cohen res.getDimensionPixelSize(R.dimen.app_icon_size)); 21519f3792523fe2d55ea791a9286398a6120920690Adam Cohen 216b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung mNormalBackground.setFilterBitmap(true); 217b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung mActiveGlowBackground.setFilterBitmap(true); 218de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy 219046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy // Initialize the data structures used for the drag visualization. 220150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung 221ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy mEaseOutInterpolator = new DecelerateInterpolator(2.5f); // Quint ease out 222de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy 223046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy 224b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung mDragCell[0] = mDragCell[1] = -1; 2254be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato for (int i = 0; i < mDragOutlines.length; i++) { 226d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen mDragOutlines[i] = new Rect(-1, -1, -1, -1); 227046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy } 228046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy 229046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy // When dragging things around the home screens, we show a green outline of 230046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy // where the item will land. The outlines gradually fade out, leaving a trail 231046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy // behind the drag path. 232046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy // Set up all the animations that are used to implement this fading. 233046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy final int duration = res.getInteger(R.integer.config_dragOutlineFadeTime); 234472b281d5cb4f5660df981a6c912266b9f5703feChet Haase final float fromAlphaValue = 0; 235472b281d5cb4f5660df981a6c912266b9f5703feChet Haase final float toAlphaValue = (float)res.getInteger(R.integer.config_dragOutlineMaxAlpha); 2364be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato 2378e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy Arrays.fill(mDragOutlineAlphas, fromAlphaValue); 2384be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato 2394be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato for (int i = 0; i < mDragOutlineAnims.length; i++) { 240046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy final InterruptibleInOutAnimator anim = 241046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy new InterruptibleInOutAnimator(duration, fromAlphaValue, toAlphaValue); 242ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy anim.getAnimator().setInterpolator(mEaseOutInterpolator); 243046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy final int thisIndex = i; 244472b281d5cb4f5660df981a6c912266b9f5703feChet Haase anim.getAnimator().addUpdateListener(new AnimatorUpdateListener() { 245de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy public void onAnimationUpdate(ValueAnimator animation) { 2464be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato final Bitmap outline = (Bitmap)anim.getTag(); 2474be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato 2484be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // If an animation is started and then stopped very quickly, we can still 2494be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // get spurious updates we've cleared the tag. Guard against this. 2504be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato if (outline == null) { 2513a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka @SuppressWarnings("all") // suppress dead code warning 2523a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka final boolean debug = false; 2533a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka if (debug) { 254fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy Object val = animation.getAnimatedValue(); 255fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy Log.d(TAG, "anim " + thisIndex + " update: " + val + 256fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy ", isStopped " + anim.isStopped()); 257fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy } 2584be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // Try to prevent it from continuing to run 2594be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato animation.cancel(); 2604be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato } else { 261472b281d5cb4f5660df981a6c912266b9f5703feChet Haase mDragOutlineAlphas[thisIndex] = (Float) animation.getAnimatedValue(); 262d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen CellLayout.this.invalidate(mDragOutlines[thisIndex]); 2634be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato } 264de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy } 265de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy }); 2664be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // The animation holds a reference to the drag outline bitmap as long is it's 2674be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // running. This way the bitmap can be GCed when the animations are complete. 268472b281d5cb4f5660df981a6c912266b9f5703feChet Haase anim.getAnimator().addListener(new AnimatorListenerAdapter() { 2693c4c20fbe682cb4b3ef94f09afe0af09171583f3Michael Jurka @Override 2704be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato public void onAnimationEnd(Animator animation) { 271472b281d5cb4f5660df981a6c912266b9f5703feChet Haase if ((Float) ((ValueAnimator) animation).getAnimatedValue() == 0f) { 2724be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato anim.setTag(null); 2734be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato } 2744be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato } 2754be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato }); 2764be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato mDragOutlineAnims[i] = anim; 277de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy } 278ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy 27918014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka mBackgroundRect = new Rect(); 280b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mForegroundRect = new Rect(); 281bea15195346bab3c52b0156e92f2b71f0811b210Michael Jurka 282a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets = new ShortcutAndWidgetContainer(context); 283a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.setCellDimensions(mCellWidth, mCellHeight, mWidthGap, mHeightGap); 284a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka addView(mShortcutsAndWidgets); 28518014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka } 28618014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka 287f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka static int widthInPortrait(Resources r, int numCells) { 288f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka // We use this method from Workspace to figure out how many rows/columns Launcher should 289f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka // have. We ignore the left/right padding on CellLayout because it turns out in our design 290f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka // the padding extends outside the visible screen size, but it looked fine anyway. 291f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka int cellWidth = r.getDimensionPixelSize(R.dimen.workspace_cell_width); 2924b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung int minGap = Math.min(r.getDimensionPixelSize(R.dimen.workspace_width_gap), 2934b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung r.getDimensionPixelSize(R.dimen.workspace_height_gap)); 294f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka 2954b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung return minGap * (numCells - 1) + cellWidth * numCells; 296f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka } 297f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka 298f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka static int heightInLandscape(Resources r, int numCells) { 299f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka // We use this method from Workspace to figure out how many rows/columns Launcher should 300f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka // have. We ignore the left/right padding on CellLayout because it turns out in our design 301f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka // the padding extends outside the visible screen size, but it looked fine anyway. 302f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka int cellHeight = r.getDimensionPixelSize(R.dimen.workspace_cell_height); 3034b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung int minGap = Math.min(r.getDimensionPixelSize(R.dimen.workspace_width_gap), 3044b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung r.getDimensionPixelSize(R.dimen.workspace_height_gap)); 305f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka 3064b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung return minGap * (numCells - 1) + cellHeight * numCells; 307f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka } 308f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka 3092801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen public void enableHardwareLayers() { 310ca99383daef92fed673de22126875cb485be494fMichael Jurka mShortcutsAndWidgets.setLayerType(LAYER_TYPE_HARDWARE, sPaint); 311d51f33a6316c34fc69b8040946ed9a62519bb225Michael Jurka } 312d51f33a6316c34fc69b8040946ed9a62519bb225Michael Jurka 313d51f33a6316c34fc69b8040946ed9a62519bb225Michael Jurka public void disableHardwareLayers() { 314ca99383daef92fed673de22126875cb485be494fMichael Jurka mShortcutsAndWidgets.setLayerType(LAYER_TYPE_NONE, sPaint); 315d51f33a6316c34fc69b8040946ed9a62519bb225Michael Jurka } 316d51f33a6316c34fc69b8040946ed9a62519bb225Michael Jurka 317d51f33a6316c34fc69b8040946ed9a62519bb225Michael Jurka public void buildHardwareLayer() { 318d51f33a6316c34fc69b8040946ed9a62519bb225Michael Jurka mShortcutsAndWidgets.buildLayer(); 3192801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen } 3202801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen 321307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen public float getChildrenScale() { 322307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen return mIsHotseat ? mHotseatScale : 1.0f; 323307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen } 324307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen 3252801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen public void setGridSize(int x, int y) { 3262801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen mCountX = x; 3272801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen mCountY = y; 3282801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen mOccupied = new boolean[mCountX][mCountY]; 329482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mTmpOccupied = new boolean[mCountX][mCountY]; 3307fbec10b36818f100b631f3d73fe1ad5360975aaAdam Cohen mTempRectStack.clear(); 33176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen requestLayout(); 3322801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen } 3332801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen 33496864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy private void invalidateBubbleTextView(BubbleTextView icon) { 33596864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy final int padding = icon.getPressedOrFocusedBackgroundPadding(); 3364b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung invalidate(icon.getLeft() + getPaddingLeft() - padding, 3374b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung icon.getTop() + getPaddingTop() - padding, 3384b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung icon.getRight() + getPaddingLeft() + padding, 3394b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung icon.getBottom() + getPaddingTop() + padding); 34096864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy } 34196864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy 342b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen void setOverScrollAmount(float r, boolean left) { 343b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen if (left && mOverScrollForegroundDrawable != mOverScrollLeft) { 344b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mOverScrollForegroundDrawable = mOverScrollLeft; 345b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen } else if (!left && mOverScrollForegroundDrawable != mOverScrollRight) { 346b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mOverScrollForegroundDrawable = mOverScrollRight; 347b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen } 348b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen 349b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mForegroundAlpha = (int) Math.round((r * 255)); 350b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mOverScrollForegroundDrawable.setAlpha(mForegroundAlpha); 351b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen invalidate(); 352b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen } 353b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen 35496864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy void setPressedOrFocusedIcon(BubbleTextView icon) { 35596864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy // We draw the pressed or focused BubbleTextView's background in CellLayout because it 35696864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy // requires an expanded clip rect (due to the glow's blur radius) 35796864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy BubbleTextView oldIcon = mPressedOrFocusedIcon; 35896864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy mPressedOrFocusedIcon = icon; 35996864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy if (oldIcon != null) { 36096864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy invalidateBubbleTextView(oldIcon); 36196864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy } 36296864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy if (mPressedOrFocusedIcon != null) { 36396864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy invalidateBubbleTextView(mPressedOrFocusedIcon); 36496864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy } 36596864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy } 36696864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy 36733945b21544bc98381df17726a3537c292d8c985Michael Jurka void setIsDragOverlapping(boolean isDragOverlapping) { 36833945b21544bc98381df17726a3537c292d8c985Michael Jurka if (mIsDragOverlapping != isDragOverlapping) { 36933945b21544bc98381df17726a3537c292d8c985Michael Jurka mIsDragOverlapping = isDragOverlapping; 37033945b21544bc98381df17726a3537c292d8c985Michael Jurka invalidate(); 37133945b21544bc98381df17726a3537c292d8c985Michael Jurka } 37233945b21544bc98381df17726a3537c292d8c985Michael Jurka } 37333945b21544bc98381df17726a3537c292d8c985Michael Jurka 37433945b21544bc98381df17726a3537c292d8c985Michael Jurka boolean getIsDragOverlapping() { 37533945b21544bc98381df17726a3537c292d8c985Michael Jurka return mIsDragOverlapping; 37633945b21544bc98381df17726a3537c292d8c985Michael Jurka } 37733945b21544bc98381df17726a3537c292d8c985Michael Jurka 378ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen protected void setOverscrollTransformsDirty(boolean dirty) { 379ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen mScrollingTransformsDirty = dirty; 380ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen } 381ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen 382ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen protected void resetOverscrollTransforms() { 383ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen if (mScrollingTransformsDirty) { 384ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen setOverscrollTransformsDirty(false); 385ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen setTranslationX(0); 386ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen setRotationY(0); 387ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen // It doesn't matter if we pass true or false here, the important thing is that we 388ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen // pass 0, which results in the overscroll drawable not being drawn any more. 389ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen setOverScrollAmount(0, false); 390ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen setPivotX(getMeasuredWidth() / 2); 391ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen setPivotY(getMeasuredHeight() / 2); 392ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen } 393ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen } 394ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen 395307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen public void scaleRect(Rect r, float scale) { 396307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen if (scale != 1.0f) { 397307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen r.left = (int) (r.left * scale + 0.5f); 398307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen r.top = (int) (r.top * scale + 0.5f); 399307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen r.right = (int) (r.right * scale + 0.5f); 400307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen r.bottom = (int) (r.bottom * scale + 0.5f); 401307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen } 402307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen } 403307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen 404307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen Rect temp = new Rect(); 405307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen void scaleRectAboutCenter(Rect in, Rect out, float scale) { 406307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen int cx = in.centerX(); 407307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen int cy = in.centerY(); 408307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen out.set(in); 409307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen out.offset(-cx, -cy); 410307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen scaleRect(out, scale); 411307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen out.offset(cx, cy); 412307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen } 413307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen 414a6abce8464b57ce91e8f083951ad263370fc2da8Romain Guy @Override 4151262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy protected void onDraw(Canvas canvas) { 4163e7c7634531302271270c8cf418abc959d621cbcMichael Jurka // When we're large, we are either drawn in a "hover" state (ie when dragging an item to 4173e7c7634531302271270c8cf418abc959d621cbcMichael Jurka // a neighboring page) or with just a normal background (if backgroundAlpha > 0.0f) 4183e7c7634531302271270c8cf418abc959d621cbcMichael Jurka // When we're small, we are either drawn normally or in the "accepts drops" state (during 4193e7c7634531302271270c8cf418abc959d621cbcMichael Jurka // a drag). However, we also drag the mini hover background *over* one of those two 4203e7c7634531302271270c8cf418abc959d621cbcMichael Jurka // backgrounds 421b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung if (mBackgroundAlpha > 0.0f) { 422f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen Drawable bg; 42333945b21544bc98381df17726a3537c292d8c985Michael Jurka 42433945b21544bc98381df17726a3537c292d8c985Michael Jurka if (mIsDragOverlapping) { 42533945b21544bc98381df17726a3537c292d8c985Michael Jurka // In the mini case, we draw the active_glow bg *over* the active background 426bdf78559f223ac11e01e3311edd5a48a80383e1eMichael Jurka bg = mActiveGlowBackground; 427f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen } else { 428bdf78559f223ac11e01e3311edd5a48a80383e1eMichael Jurka bg = mNormalBackground; 429f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen } 43033945b21544bc98381df17726a3537c292d8c985Michael Jurka 43133945b21544bc98381df17726a3537c292d8c985Michael Jurka bg.setAlpha((int) (mBackgroundAlpha * mBackgroundAlphaMultiplier * 255)); 43233945b21544bc98381df17726a3537c292d8c985Michael Jurka bg.setBounds(mBackgroundRect); 43333945b21544bc98381df17726a3537c292d8c985Michael Jurka bg.draw(canvas); 434a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka } 43531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 4368e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy final Paint paint = mDragOutlinePaint; 4374be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato for (int i = 0; i < mDragOutlines.length; i++) { 438472b281d5cb4f5660df981a6c912266b9f5703feChet Haase final float alpha = mDragOutlineAlphas[i]; 4394be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato if (alpha > 0) { 440d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen final Rect r = mDragOutlines[i]; 441307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen scaleRectAboutCenter(r, temp, getChildrenScale()); 4424be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato final Bitmap b = (Bitmap) mDragOutlineAnims[i].getTag(); 443472b281d5cb4f5660df981a6c912266b9f5703feChet Haase paint.setAlpha((int)(alpha + .5f)); 444307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen canvas.drawBitmap(b, null, temp, paint); 445150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung } 4466569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy } 44796864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy 44896864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy // We draw the pressed or focused BubbleTextView's background in CellLayout because it 44996864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy // requires an expanded clip rect (due to the glow's blur radius) 45096864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy if (mPressedOrFocusedIcon != null) { 45196864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy final int padding = mPressedOrFocusedIcon.getPressedOrFocusedBackgroundPadding(); 45296864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy final Bitmap b = mPressedOrFocusedIcon.getPressedOrFocusedBackground(); 45396864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy if (b != null) { 45496864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy canvas.drawBitmap(b, 4554b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung mPressedOrFocusedIcon.getLeft() + getPaddingLeft() - padding, 4564b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung mPressedOrFocusedIcon.getTop() + getPaddingTop() - padding, 45796864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy null); 45896864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy } 45996864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy } 46069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 461482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (DEBUG_VISUALIZE_OCCUPIED) { 462482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int[] pt = new int[2]; 463482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen ColorDrawable cd = new ColorDrawable(Color.RED); 464e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen cd.setBounds(0, 0, mCellWidth, mCellHeight); 465482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < mCountX; i++) { 466482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int j = 0; j < mCountY; j++) { 467482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (mOccupied[i][j]) { 468482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen cellToPoint(i, j, pt); 469482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen canvas.save(); 470482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen canvas.translate(pt[0], pt[1]); 471482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen cd.draw(canvas); 472482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen canvas.restore(); 473482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 474482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 475482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 476482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 477482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 478850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn int previewOffset = FolderRingAnimator.sPreviewSize; 479850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn 48069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen // The folder outer / inner ring image(s) 48169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen for (int i = 0; i < mFolderOuterRings.size(); i++) { 48269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen FolderRingAnimator fra = mFolderOuterRings.get(i); 48369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 48469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen // Draw outer ring 48569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen Drawable d = FolderRingAnimator.sSharedOuterRingDrawable; 48669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen int width = (int) fra.getOuterRingSize(); 48769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen int height = width; 48869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen cellToPoint(fra.mCellX, fra.mCellY, mTempLocation); 48969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 49069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen int centerX = mTempLocation[0] + mCellWidth / 2; 491850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn int centerY = mTempLocation[1] + previewOffset / 2; 49269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 49369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen canvas.save(); 49469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen canvas.translate(centerX - width / 2, centerY - height / 2); 49569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen d.setBounds(0, 0, width, height); 49669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen d.draw(canvas); 49769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen canvas.restore(); 49869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 49969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen // Draw inner ring 50069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen d = FolderRingAnimator.sSharedInnerRingDrawable; 50169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen width = (int) fra.getInnerRingSize(); 50269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen height = width; 50369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen cellToPoint(fra.mCellX, fra.mCellY, mTempLocation); 50469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 50569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen centerX = mTempLocation[0] + mCellWidth / 2; 506850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn centerY = mTempLocation[1] + previewOffset / 2; 50769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen canvas.save(); 50869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen canvas.translate(centerX - width / 2, centerY - width / 2); 50969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen d.setBounds(0, 0, width, height); 51069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen d.draw(canvas); 51169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen canvas.restore(); 51269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen } 513c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen 514c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen if (mFolderLeaveBehindCell[0] >= 0 && mFolderLeaveBehindCell[1] >= 0) { 515c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen Drawable d = FolderIcon.sSharedFolderLeaveBehind; 516c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen int width = d.getIntrinsicWidth(); 517c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen int height = d.getIntrinsicHeight(); 518c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen 519c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen cellToPoint(mFolderLeaveBehindCell[0], mFolderLeaveBehindCell[1], mTempLocation); 520c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen int centerX = mTempLocation[0] + mCellWidth / 2; 521850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn int centerY = mTempLocation[1] + previewOffset / 2; 522c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen 523c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen canvas.save(); 524c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen canvas.translate(centerX - width / 2, centerY - width / 2); 525c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen d.setBounds(0, 0, width, height); 526c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen d.draw(canvas); 527c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen canvas.restore(); 528c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen } 52969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen } 53069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 531b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen @Override 532b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen protected void dispatchDraw(Canvas canvas) { 533b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen super.dispatchDraw(canvas); 534b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen if (mForegroundAlpha > 0) { 535b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mOverScrollForegroundDrawable.setBounds(mForegroundRect); 536b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen Paint p = ((NinePatchDrawable) mOverScrollForegroundDrawable).getPaint(); 5378a0bff5e35f63321178bbf777ec24d42544866b3Romain Guy p.setXfermode(sAddBlendMode); 538b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mOverScrollForegroundDrawable.draw(canvas); 539b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen p.setXfermode(null); 540b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen } 541b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen } 542b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen 54369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen public void showFolderAccept(FolderRingAnimator fra) { 54469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen mFolderOuterRings.add(fra); 54569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen } 54669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 54769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen public void hideFolderAccept(FolderRingAnimator fra) { 54869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen if (mFolderOuterRings.contains(fra)) { 54969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen mFolderOuterRings.remove(fra); 55069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen } 55169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen invalidate(); 5526569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy } 5536569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 554c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen public void setFolderLeaveBehindCell(int x, int y) { 555c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen mFolderLeaveBehindCell[0] = x; 556c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen mFolderLeaveBehindCell[1] = y; 557c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen invalidate(); 558c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen } 559c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen 560c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen public void clearFolderLeaveBehind() { 561c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen mFolderLeaveBehindCell[0] = -1; 562c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen mFolderLeaveBehindCell[1] = -1; 563c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen invalidate(); 564c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen } 565c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen 5666569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy @Override 567e6235dd225404239b55c459245543f3302326112Michael Jurka public boolean shouldDelayChildPressedState() { 568e6235dd225404239b55c459245543f3302326112Michael Jurka return false; 569e6235dd225404239b55c459245543f3302326112Michael Jurka } 570e6235dd225404239b55c459245543f3302326112Michael Jurka 5711462de39f01cec0ba785386532719cb0207dd827Adam Cohen public void restoreInstanceState(SparseArray<Parcelable> states) { 5721462de39f01cec0ba785386532719cb0207dd827Adam Cohen dispatchRestoreInstanceState(states); 5731462de39f01cec0ba785386532719cb0207dd827Adam Cohen } 5741462de39f01cec0ba785386532719cb0207dd827Adam Cohen 575e6235dd225404239b55c459245543f3302326112Michael Jurka @Override 57683f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey public void cancelLongPress() { 57783f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey super.cancelLongPress(); 57883f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey 57983f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey // Cancel long press for all children 58083f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey final int count = getChildCount(); 58183f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey for (int i = 0; i < count; i++) { 58283f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey final View child = getChildAt(i); 58383f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey child.cancelLongPress(); 58483f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey } 58583f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey } 58683f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey 587dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka public void setOnInterceptTouchListener(View.OnTouchListener listener) { 588dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka mInterceptTouchListener = listener; 589dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } 590dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka 59131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int getCountX() { 592d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen return mCountX; 59331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 59431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 59531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int getCountY() { 596d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen return mCountY; 59731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 59831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 5990dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn public void setIsHotseat(boolean isHotseat) { 6000dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn mIsHotseat = isHotseat; 6010dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn } 6020dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn 6030dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn public boolean addViewToCellLayout(View child, int index, int childId, LayoutParams params, 604850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn boolean markCells) { 605aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung final LayoutParams lp = params; 606aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 607de38e42fe89fd7490221427908cd97c51da21b44Andrew Flynn // Hotseat icons - remove text 6080dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn if (child instanceof BubbleTextView) { 6090dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn BubbleTextView bubbleChild = (BubbleTextView) child; 6100dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn 611de38e42fe89fd7490221427908cd97c51da21b44Andrew Flynn Resources res = getResources(); 612de38e42fe89fd7490221427908cd97c51da21b44Andrew Flynn if (mIsHotseat) { 613de38e42fe89fd7490221427908cd97c51da21b44Andrew Flynn bubbleChild.setTextColor(res.getColor(android.R.color.transparent)); 614de38e42fe89fd7490221427908cd97c51da21b44Andrew Flynn } else { 615de38e42fe89fd7490221427908cd97c51da21b44Andrew Flynn bubbleChild.setTextColor(res.getColor(R.color.workspace_icon_text_color)); 6160dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn } 6170dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn } 6180dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn 619307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen child.setScaleX(getChildrenScale()); 620307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen child.setScaleY(getChildrenScale()); 621307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen 62231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // Generate an id for each view, this assumes we have at most 256x256 cells 62331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // per workspace screen 624d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen if (lp.cellX >= 0 && lp.cellX <= mCountX - 1 && lp.cellY >= 0 && lp.cellY <= mCountY - 1) { 625aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung // If the horizontal or vertical span is set to -1, it is taken to 626aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung // mean that it spans the extent of the CellLayout 627d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen if (lp.cellHSpan < 0) lp.cellHSpan = mCountX; 628d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen if (lp.cellVSpan < 0) lp.cellVSpan = mCountY; 629aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 630aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung child.setId(childId); 63131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 632a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.addView(child, index, lp); 633dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka 634f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka if (markCells) markCellsAsOccupiedForView(child); 6350280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 636aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung return true; 637aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung } 638aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung return false; 63931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 6403e7c7634531302271270c8cf418abc959d621cbcMichael Jurka 64131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 6420280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka public void removeAllViews() { 6430280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka clearOccupiedCells(); 644a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.removeAllViews(); 6450280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 6460280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 6470280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka @Override 6480280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka public void removeAllViewsInLayout() { 649a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka if (mShortcutsAndWidgets.getChildCount() > 0) { 6507cfc2825c3a1029f962d2fc387ae2eaa85b51798Michael Jurka clearOccupiedCells(); 651a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.removeAllViewsInLayout(); 6527cfc2825c3a1029f962d2fc387ae2eaa85b51798Michael Jurka } 6530280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 6540280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 655f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka public void removeViewWithoutMarkingCells(View view) { 656a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.removeView(view); 657f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka } 658f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka 6590280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka @Override 6600280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka public void removeView(View view) { 6610280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka markCellsAsUnoccupiedForView(view); 662a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.removeView(view); 6630280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 6640280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 6650280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka @Override 6660280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka public void removeViewAt(int index) { 667a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka markCellsAsUnoccupiedForView(mShortcutsAndWidgets.getChildAt(index)); 668a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.removeViewAt(index); 6690280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 6700280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 6710280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka @Override 6720280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka public void removeViewInLayout(View view) { 6730280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka markCellsAsUnoccupiedForView(view); 674a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.removeViewInLayout(view); 6750280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 6760280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 6770280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka @Override 6780280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka public void removeViews(int start, int count) { 6790280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka for (int i = start; i < start + count; i++) { 680a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka markCellsAsUnoccupiedForView(mShortcutsAndWidgets.getChildAt(i)); 6810280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 682a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.removeViews(start, count); 6830280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 6840280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 6850280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka @Override 6860280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka public void removeViewsInLayout(int start, int count) { 6870280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka for (int i = start; i < start + count; i++) { 688a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka markCellsAsUnoccupiedForView(mShortcutsAndWidgets.getChildAt(i)); 6890280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 690a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.removeViewsInLayout(start, count); 691abded66084680bb31cc7ea403c88f44f79a3c884Michael Jurka } 692abded66084680bb31cc7ea403c88f44f79a3c884Michael Jurka 69331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 69431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected void onAttachedToWindow() { 69531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project super.onAttachedToWindow(); 69631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mCellInfo.screen = ((ViewGroup) getParent()).indexOfChild(this); 69731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 69831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 699af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka public void setTagToCellInfoForPoint(int touchX, int touchY) { 70031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final CellInfo cellInfo = mCellInfo; 701eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung Rect frame = mRect; 7028b805b17158886035b38261eb611d8641701ae43Michael Jurka final int x = touchX + getScrollX(); 7038b805b17158886035b38261eb611d8641701ae43Michael Jurka final int y = touchY + getScrollY(); 704a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka final int count = mShortcutsAndWidgets.getChildCount(); 70531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 706af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka boolean found = false; 707af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka for (int i = count - 1; i >= 0; i--) { 708a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka final View child = mShortcutsAndWidgets.getChildAt(i); 709d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 710af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka 7111b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen if ((child.getVisibility() == VISIBLE || child.getAnimation() != null) && 7121b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen lp.isLockedToGrid) { 713af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka child.getHitRect(frame); 7140be025d64c1f84138fe430a58875886e66aae767Winson Chung 715eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung float scale = child.getScaleX(); 716eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung frame = new Rect(child.getLeft(), child.getTop(), child.getRight(), 717eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung child.getBottom()); 7180be025d64c1f84138fe430a58875886e66aae767Winson Chung // The child hit rect is relative to the CellLayoutChildren parent, so we need to 7190be025d64c1f84138fe430a58875886e66aae767Winson Chung // offset that by this CellLayout's padding to test an (x,y) point that is relative 7200be025d64c1f84138fe430a58875886e66aae767Winson Chung // to this view. 7218b805b17158886035b38261eb611d8641701ae43Michael Jurka frame.offset(getPaddingLeft(), getPaddingTop()); 722eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung frame.inset((int) (frame.width() * (1f - scale) / 2), 723eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung (int) (frame.height() * (1f - scale) / 2)); 7240be025d64c1f84138fe430a58875886e66aae767Winson Chung 725af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka if (frame.contains(x, y)) { 726af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.cell = child; 727af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.cellX = lp.cellX; 728af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.cellY = lp.cellY; 729af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.spanX = lp.cellHSpan; 730af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.spanY = lp.cellVSpan; 731af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka found = true; 732af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka break; 73331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 73431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 735af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka } 736aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 737d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka mLastDownOnOccupiedCell = found; 738d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka 739af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka if (!found) { 7400be025d64c1f84138fe430a58875886e66aae767Winson Chung final int cellXY[] = mTmpXY; 741af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka pointToCellExact(x, y, cellXY); 74231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 743af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.cell = null; 744af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.cellX = cellXY[0]; 745af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.cellY = cellXY[1]; 746af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.spanX = 1; 747af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.spanY = 1; 748af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka } 749af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka setTag(cellInfo); 750af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka } 75131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 752af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka @Override 753af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka public boolean onInterceptTouchEvent(MotionEvent ev) { 754c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen // First we clear the tag to ensure that on every touch down we start with a fresh slate, 755c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen // even in the case where we return early. Not clearing here was causing bugs whereby on 756c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen // long-press we'd end up picking up an item from a previous drag operation. 757c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen final int action = ev.getAction(); 758c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen 759c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen if (action == MotionEvent.ACTION_DOWN) { 760c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen clearTagCellInfo(); 761c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen } 762c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen 763dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka if (mInterceptTouchListener != null && mInterceptTouchListener.onTouch(this, ev)) { 764dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka return true; 765dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } 76631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 767af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka if (action == MotionEvent.ACTION_DOWN) { 768af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka setTagToCellInfoForPoint((int) ev.getX(), (int) ev.getY()); 76931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 770eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung 77131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return false; 77231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 77331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 774c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen private void clearTagCellInfo() { 775c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen final CellInfo cellInfo = mCellInfo; 776c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen cellInfo.cell = null; 777c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen cellInfo.cellX = -1; 778c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen cellInfo.cellY = -1; 779c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen cellInfo.spanX = 0; 780c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen cellInfo.spanY = 0; 781c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen setTag(cellInfo); 782c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen } 783c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen 78431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public CellInfo getTag() { 7850280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka return (CellInfo) super.getTag(); 78631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 78731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 7886569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy /** 789aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * Given a point, return the cell that strictly encloses that point 79031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param x X coordinate of the point 79131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param y Y coordinate of the point 79231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param result Array of 2 ints to hold the x and y coordinate of the cell 79331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 79431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project void pointToCellExact(int x, int y, int[] result) { 7954b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung final int hStartPadding = getPaddingLeft(); 7964b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung final int vStartPadding = getPaddingTop(); 79731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 79831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project result[0] = (x - hStartPadding) / (mCellWidth + mWidthGap); 79931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project result[1] = (y - vStartPadding) / (mCellHeight + mHeightGap); 80031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 801d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen final int xAxis = mCountX; 802d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen final int yAxis = mCountY; 80331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 80431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (result[0] < 0) result[0] = 0; 80531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (result[0] >= xAxis) result[0] = xAxis - 1; 80631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (result[1] < 0) result[1] = 0; 80731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (result[1] >= yAxis) result[1] = yAxis - 1; 80831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 809aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 81031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 81131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Given a point, return the cell that most closely encloses that point 81231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param x X coordinate of the point 81331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param y Y coordinate of the point 81431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param result Array of 2 ints to hold the x and y coordinate of the cell 81531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 81631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project void pointToCellRounded(int x, int y, int[] result) { 81731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project pointToCellExact(x + (mCellWidth / 2), y + (mCellHeight / 2), result); 81831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 81931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 82031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 82131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Given a cell coordinate, return the point that represents the upper left corner of that cell 822aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * 823aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * @param cellX X coordinate of the cell 82431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param cellY Y coordinate of the cell 825aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * 82631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param result Array of 2 ints to hold the x and y coordinate of the point 82731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 82831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project void cellToPoint(int cellX, int cellY, int[] result) { 8294b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung final int hStartPadding = getPaddingLeft(); 8304b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung final int vStartPadding = getPaddingTop(); 83131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 83231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project result[0] = hStartPadding + cellX * (mCellWidth + mWidthGap); 83331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project result[1] = vStartPadding + cellY * (mCellHeight + mHeightGap); 83431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 83531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 836e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen /** 837482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * Given a cell coordinate, return the point that represents the center of the cell 838e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen * 839e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen * @param cellX X coordinate of the cell 840e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen * @param cellY Y coordinate of the cell 841e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen * 842e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen * @param result Array of 2 ints to hold the x and y coordinate of the point 843e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen */ 844e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen void cellToCenterPoint(int cellX, int cellY, int[] result) { 84547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen regionToCenterPoint(cellX, cellY, 1, 1, result); 84647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 84747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 84847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen /** 84947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * Given a cell coordinate and span return the point that represents the center of the regio 85047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * 85147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param cellX X coordinate of the cell 85247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param cellY Y coordinate of the cell 85347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * 85447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param result Array of 2 ints to hold the x and y coordinate of the point 85547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen */ 85647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen void regionToCenterPoint(int cellX, int cellY, int spanX, int spanY, int[] result) { 8574b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung final int hStartPadding = getPaddingLeft(); 8584b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung final int vStartPadding = getPaddingTop(); 85947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen result[0] = hStartPadding + cellX * (mCellWidth + mWidthGap) + 86047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen (spanX * mCellWidth + (spanX - 1) * mWidthGap) / 2; 86147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen result[1] = vStartPadding + cellY * (mCellHeight + mHeightGap) + 86247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen (spanY * mCellHeight + (spanY - 1) * mHeightGap) / 2; 863e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen } 864e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen 86519f3792523fe2d55ea791a9286398a6120920690Adam Cohen /** 86619f3792523fe2d55ea791a9286398a6120920690Adam Cohen * Given a cell coordinate and span fills out a corresponding pixel rect 86719f3792523fe2d55ea791a9286398a6120920690Adam Cohen * 86819f3792523fe2d55ea791a9286398a6120920690Adam Cohen * @param cellX X coordinate of the cell 86919f3792523fe2d55ea791a9286398a6120920690Adam Cohen * @param cellY Y coordinate of the cell 87019f3792523fe2d55ea791a9286398a6120920690Adam Cohen * @param result Rect in which to write the result 87119f3792523fe2d55ea791a9286398a6120920690Adam Cohen */ 87219f3792523fe2d55ea791a9286398a6120920690Adam Cohen void regionToRect(int cellX, int cellY, int spanX, int spanY, Rect result) { 87319f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int hStartPadding = getPaddingLeft(); 87419f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int vStartPadding = getPaddingTop(); 87519f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int left = hStartPadding + cellX * (mCellWidth + mWidthGap); 87619f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int top = vStartPadding + cellY * (mCellHeight + mHeightGap); 87719f3792523fe2d55ea791a9286398a6120920690Adam Cohen result.set(left, top, left + (spanX * mCellWidth + (spanX - 1) * mWidthGap), 87819f3792523fe2d55ea791a9286398a6120920690Adam Cohen top + (spanY * mCellHeight + (spanY - 1) * mHeightGap)); 87919f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 88019f3792523fe2d55ea791a9286398a6120920690Adam Cohen 881482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public float getDistanceFromCell(float x, float y, int[] cell) { 882482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen cellToCenterPoint(cell[0], cell[1], mTmpPoint); 883482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen float distance = (float) Math.sqrt( Math.pow(x - mTmpPoint[0], 2) + 884482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen Math.pow(y - mTmpPoint[1], 2)); 885482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return distance; 886482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 887482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 88884f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy int getCellWidth() { 88984f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy return mCellWidth; 89084f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy } 89184f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy 89284f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy int getCellHeight() { 89384f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy return mCellHeight; 89484f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy } 89584f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy 896d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen int getWidthGap() { 897d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen return mWidthGap; 898d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen } 899d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen 900d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen int getHeightGap() { 901d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen return mHeightGap; 902d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen } 903d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen 9047f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen Rect getContentRect(Rect r) { 9057f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen if (r == null) { 9067f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen r = new Rect(); 9077f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 9087f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen int left = getPaddingLeft(); 9097f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen int top = getPaddingTop(); 9108b805b17158886035b38261eb611d8641701ae43Michael Jurka int right = left + getWidth() - getPaddingLeft() - getPaddingRight(); 9118b805b17158886035b38261eb611d8641701ae43Michael Jurka int bottom = top + getHeight() - getPaddingTop() - getPaddingBottom(); 9127f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen r.set(left, top, right, bottom); 9137f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen return r; 9147f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 9157f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 916a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen static void getMetrics(Rect metrics, Resources res, int measureWidth, int measureHeight, 917a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen int countX, int countY, int orientation) { 918a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen int numWidthGaps = countX - 1; 919a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen int numHeightGaps = countY - 1; 920f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen 921f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen int widthGap; 922f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen int heightGap; 923f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen int cellWidth; 924f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen int cellHeight; 925f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen int paddingLeft; 926f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen int paddingRight; 927f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen int paddingTop; 928f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen int paddingBottom; 929f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen 930a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen int maxGap = res.getDimensionPixelSize(R.dimen.workspace_max_gap); 931f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen if (orientation == LANDSCAPE) { 932f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen cellWidth = res.getDimensionPixelSize(R.dimen.workspace_cell_width_land); 933f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen cellHeight = res.getDimensionPixelSize(R.dimen.workspace_cell_height_land); 934f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen widthGap = res.getDimensionPixelSize(R.dimen.workspace_width_gap_land); 935f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen heightGap = res.getDimensionPixelSize(R.dimen.workspace_height_gap_land); 936f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen paddingLeft = res.getDimensionPixelSize(R.dimen.cell_layout_left_padding_land); 937f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen paddingRight = res.getDimensionPixelSize(R.dimen.cell_layout_right_padding_land); 938f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen paddingTop = res.getDimensionPixelSize(R.dimen.cell_layout_top_padding_land); 939f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen paddingBottom = res.getDimensionPixelSize(R.dimen.cell_layout_bottom_padding_land); 940f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen } else { 941f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen // PORTRAIT 942f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen cellWidth = res.getDimensionPixelSize(R.dimen.workspace_cell_width_port); 943f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen cellHeight = res.getDimensionPixelSize(R.dimen.workspace_cell_height_port); 944f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen widthGap = res.getDimensionPixelSize(R.dimen.workspace_width_gap_port); 945f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen heightGap = res.getDimensionPixelSize(R.dimen.workspace_height_gap_port); 946f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen paddingLeft = res.getDimensionPixelSize(R.dimen.cell_layout_left_padding_port); 947f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen paddingRight = res.getDimensionPixelSize(R.dimen.cell_layout_right_padding_port); 948f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen paddingTop = res.getDimensionPixelSize(R.dimen.cell_layout_top_padding_port); 949f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen paddingBottom = res.getDimensionPixelSize(R.dimen.cell_layout_bottom_padding_port); 950f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen } 951f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen 952f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen if (widthGap < 0 || heightGap < 0) { 953f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen int hSpace = measureWidth - paddingLeft - paddingRight; 954f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen int vSpace = measureHeight - paddingTop - paddingBottom; 955a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen int hFreeSpace = hSpace - (countX * cellWidth); 956a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen int vFreeSpace = vSpace - (countY * cellHeight); 957a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen widthGap = Math.min(maxGap, numWidthGaps > 0 ? (hFreeSpace / numWidthGaps) : 0); 958a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen heightGap = Math.min(maxGap, numHeightGaps > 0 ? (vFreeSpace / numHeightGaps) : 0); 959f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen } 960f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen metrics.set(cellWidth, cellHeight, widthGap, heightGap); 961f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen } 962f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen 96331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 96431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 96531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec); 966aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec); 967aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 96831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec); 96931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec); 970aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 97131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (widthSpecMode == MeasureSpec.UNSPECIFIED || heightSpecMode == MeasureSpec.UNSPECIFIED) { 97231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project throw new RuntimeException("CellLayout cannot have UNSPECIFIED dimensions"); 97331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 97431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 975d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen int numWidthGaps = mCountX - 1; 976d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen int numHeightGaps = mCountY - 1; 977d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen 978234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen if (mOriginalWidthGap < 0 || mOriginalHeightGap < 0) { 979dd13e3d0f9925b7bb80c37e21d039aab4fa7e7a1Michael Jurka int hSpace = widthSpecSize - getPaddingLeft() - getPaddingRight(); 980dd13e3d0f9925b7bb80c37e21d039aab4fa7e7a1Michael Jurka int vSpace = heightSpecSize - getPaddingTop() - getPaddingBottom(); 981f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen int hFreeSpace = hSpace - (mCountX * mCellWidth); 982f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen int vFreeSpace = vSpace - (mCountY * mCellHeight); 9834b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung mWidthGap = Math.min(mMaxGap, numWidthGaps > 0 ? (hFreeSpace / numWidthGaps) : 0); 9844b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung mHeightGap = Math.min(mMaxGap,numHeightGaps > 0 ? (vFreeSpace / numHeightGaps) : 0); 985a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.setCellDimensions(mCellWidth, mCellHeight, mWidthGap, mHeightGap); 986234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen } else { 987234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen mWidthGap = mOriginalWidthGap; 988234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen mHeightGap = mOriginalHeightGap; 989ece7f5b3b55cab646941123e03589241a61678e2Winson Chung } 9905f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka 9918c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka // Initial values correspond to widthSpecMode == MeasureSpec.EXACTLY 9928c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka int newWidth = widthSpecSize; 9938c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka int newHeight = heightSpecSize; 9948c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka if (widthSpecMode == MeasureSpec.AT_MOST) { 9958b805b17158886035b38261eb611d8641701ae43Michael Jurka newWidth = getPaddingLeft() + getPaddingRight() + (mCountX * mCellWidth) + 9968c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka ((mCountX - 1) * mWidthGap); 9978b805b17158886035b38261eb611d8641701ae43Michael Jurka newHeight = getPaddingTop() + getPaddingBottom() + (mCountY * mCellHeight) + 9988c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka ((mCountY - 1) * mHeightGap); 9998c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka setMeasuredDimension(newWidth, newHeight); 10008c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka } 100131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 10028c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka int count = getChildCount(); 100331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int i = 0; i < count; i++) { 100431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project View child = getChildAt(i); 10058b805b17158886035b38261eb611d8641701ae43Michael Jurka int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(newWidth - getPaddingLeft() - 10068b805b17158886035b38261eb611d8641701ae43Michael Jurka getPaddingRight(), MeasureSpec.EXACTLY); 10078b805b17158886035b38261eb611d8641701ae43Michael Jurka int childheightMeasureSpec = MeasureSpec.makeMeasureSpec(newHeight - getPaddingTop() - 10088b805b17158886035b38261eb611d8641701ae43Michael Jurka getPaddingBottom(), MeasureSpec.EXACTLY); 100931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project child.measure(childWidthMeasureSpec, childheightMeasureSpec); 101031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 10118c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka setMeasuredDimension(newWidth, newHeight); 101231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 101331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 101431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 101528750fba6a2d141eb9a1e566718c17236030b815Michael Jurka protected void onLayout(boolean changed, int l, int t, int r, int b) { 101631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int count = getChildCount(); 101731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int i = 0; i < count; i++) { 10188c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka View child = getChildAt(i); 10198b805b17158886035b38261eb611d8641701ae43Michael Jurka child.layout(getPaddingLeft(), getPaddingTop(), 10208b805b17158886035b38261eb611d8641701ae43Michael Jurka r - l - getPaddingRight(), b - t - getPaddingBottom()); 102131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 102231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 102331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 102431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 1025dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka protected void onSizeChanged(int w, int h, int oldw, int oldh) { 1026dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka super.onSizeChanged(w, h, oldw, oldh); 102718014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka mBackgroundRect.set(0, 0, w, h); 1028b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mForegroundRect.set(mForegroundPadding, mForegroundPadding, 1029215b416c1f7cf0234b777155b823637a0902739fAdam Cohen w - mForegroundPadding, h - mForegroundPadding); 1030dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } 1031dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka 1032dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka @Override 103331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected void setChildrenDrawingCacheEnabled(boolean enabled) { 1034a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.setChildrenDrawingCacheEnabled(enabled); 103531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 103631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 103731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 103831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected void setChildrenDrawnWithCacheEnabled(boolean enabled) { 1039a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.setChildrenDrawnWithCacheEnabled(enabled); 104031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 104131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 10425f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka public float getBackgroundAlpha() { 10435f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka return mBackgroundAlpha; 1044dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } 1045dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka 10461b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen public void setBackgroundAlphaMultiplier(float multiplier) { 1047a3d30adbfd4f013260f1f5ba3a56bc9bb4a11717Michael Jurka if (mBackgroundAlphaMultiplier != multiplier) { 1048a3d30adbfd4f013260f1f5ba3a56bc9bb4a11717Michael Jurka mBackgroundAlphaMultiplier = multiplier; 1049a3d30adbfd4f013260f1f5ba3a56bc9bb4a11717Michael Jurka invalidate(); 1050a3d30adbfd4f013260f1f5ba3a56bc9bb4a11717Michael Jurka } 10511b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen } 10521b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen 1053ddb821981e0919bbd3b4c9a2b6aa1811d6c86bb6Adam Cohen public float getBackgroundAlphaMultiplier() { 1054ddb821981e0919bbd3b4c9a2b6aa1811d6c86bb6Adam Cohen return mBackgroundAlphaMultiplier; 1055ddb821981e0919bbd3b4c9a2b6aa1811d6c86bb6Adam Cohen } 1056ddb821981e0919bbd3b4c9a2b6aa1811d6c86bb6Adam Cohen 10575f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka public void setBackgroundAlpha(float alpha) { 1058afaa05014e0bf3ed1192f9ddec2af4283bc50248Michael Jurka if (mBackgroundAlpha != alpha) { 1059afaa05014e0bf3ed1192f9ddec2af4283bc50248Michael Jurka mBackgroundAlpha = alpha; 1060afaa05014e0bf3ed1192f9ddec2af4283bc50248Michael Jurka invalidate(); 1061afaa05014e0bf3ed1192f9ddec2af4283bc50248Michael Jurka } 1062dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } 1063dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka 1064a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka public void setShortcutAndWidgetAlpha(float alpha) { 10650142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka final int childCount = getChildCount(); 10660142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka for (int i = 0; i < childCount; i++) { 1067dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka getChildAt(i).setAlpha(alpha); 1068dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } 1069dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } 1070dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka 1071a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka public ShortcutAndWidgetContainer getShortcutsAndWidgets() { 1072a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka if (getChildCount() > 0) { 1073a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka return (ShortcutAndWidgetContainer) getChildAt(0); 1074a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka } 1075a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka return null; 1076a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka } 1077a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka 1078440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy public View getChildAt(int x, int y) { 1079a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka return mShortcutsAndWidgets.getChildAt(x, y); 1080440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy } 1081440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy 108276fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen public boolean animateChildToPosition(final View child, int cellX, int cellY, int duration, 1083482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int delay, boolean permanent, boolean adjustOccupied) { 1084a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka ShortcutAndWidgetContainer clc = getShortcutsAndWidgets(); 1085482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean[][] occupied = mOccupied; 1086482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (!permanent) { 1087482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen occupied = mTmpOccupied; 1088482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1089482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 109019f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (clc.indexOfChild(child) != -1) { 1091bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 1092bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen final ItemInfo info = (ItemInfo) child.getTag(); 1093bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen 1094bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen // We cancel any existing animations 1095bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen if (mReorderAnimators.containsKey(lp)) { 1096bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen mReorderAnimators.get(lp).cancel(); 1097bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen mReorderAnimators.remove(lp); 1098bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 1099bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen 1100482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int oldX = lp.x; 1101482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int oldY = lp.y; 1102482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (adjustOccupied) { 1103482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen occupied[lp.cellX][lp.cellY] = false; 1104482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen occupied[cellX][cellY] = true; 1105482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1106bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen lp.isLockedToGrid = true; 1107482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (permanent) { 1108482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen lp.cellX = info.cellX = cellX; 1109482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen lp.cellY = info.cellY = cellY; 1110482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } else { 1111482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen lp.tmpCellX = cellX; 1112482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen lp.tmpCellY = cellY; 1113482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1114bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen clc.setupLp(lp); 1115bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen lp.isLockedToGrid = false; 1116482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int newX = lp.x; 1117482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int newY = lp.y; 1118bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen 111976fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen lp.x = oldX; 112076fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen lp.y = oldY; 112176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen 1122482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // Exit early if we're not actually moving the view 1123482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (oldX == newX && oldY == newY) { 1124482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen lp.isLockedToGrid = true; 1125482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return true; 1126482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1127482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 11282ecf995e0d2d55eb71d03f7230ca87270872d1a3Michael Jurka ValueAnimator va = LauncherAnimUtils.ofFloat(0f, 1f); 1129482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen va.setDuration(duration); 1130482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mReorderAnimators.put(lp, va); 1131482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1132482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen va.addUpdateListener(new AnimatorUpdateListener() { 1133482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen @Override 1134bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen public void onAnimationUpdate(ValueAnimator animation) { 1135482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen float r = ((Float) animation.getAnimatedValue()).floatValue(); 113619f3792523fe2d55ea791a9286398a6120920690Adam Cohen lp.x = (int) ((1 - r) * oldX + r * newX); 113719f3792523fe2d55ea791a9286398a6120920690Adam Cohen lp.y = (int) ((1 - r) * oldY + r * newY); 11386b8a02d63a5d9cab8209381993e37db6a6afb753Adam Cohen child.requestLayout(); 1139bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 1140bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen }); 1141482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen va.addListener(new AnimatorListenerAdapter() { 1142bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen boolean cancelled = false; 1143bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen public void onAnimationEnd(Animator animation) { 1144bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen // If the animation was cancelled, it means that another animation 1145bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen // has interrupted this one, and we don't want to lock the item into 1146bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen // place just yet. 1147bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen if (!cancelled) { 1148bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen lp.isLockedToGrid = true; 1149482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen child.requestLayout(); 1150bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 1151bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen if (mReorderAnimators.containsKey(lp)) { 1152bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen mReorderAnimators.remove(lp); 1153bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 1154bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 1155bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen public void onAnimationCancel(Animator animation) { 1156bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen cancelled = true; 1157bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 1158bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen }); 1159482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen va.setStartDelay(delay); 1160482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen va.start(); 1161bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen return true; 1162bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 1163bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen return false; 1164bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 1165bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen 11666569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy /** 11676569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy * Estimate where the top left cell of the dragged item will land if it is dropped. 11686569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy * 11696569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy * @param originX The X value of the top left corner of the item 11706569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy * @param originY The Y value of the top left corner of the item 11716569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy * @param spanX The number of horizontal cells that the item spans 11726569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy * @param spanY The number of vertical cells that the item spans 11736569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy * @param result The estimated drop cell X and Y. 11746569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy */ 11756569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy void estimateDropCell(int originX, int originY, int spanX, int spanY, int[] result) { 1176d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen final int countX = mCountX; 1177d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen final int countY = mCountY; 11786569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 1179a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka // pointToCellRounded takes the top left of a cell but will pad that with 1180a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka // cellWidth/2 and cellHeight/2 when finding the matching cell 1181a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka pointToCellRounded(originX, originY, result); 11826569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 11836569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy // If the item isn't fully on this screen, snap to the edges 11846569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy int rightOverhang = result[0] + spanX - countX; 11856569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy if (rightOverhang > 0) { 11866569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy result[0] -= rightOverhang; // Snap to right 11876569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy } 11886569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy result[0] = Math.max(0, result[0]); // Snap to left 11896569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy int bottomOverhang = result[1] + spanY - countY; 11906569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy if (bottomOverhang > 0) { 11916569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy result[1] -= bottomOverhang; // Snap to bottom 11926569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy } 11936569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy result[1] = Math.max(0, result[1]); // Snap to top 11946569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy } 11956569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 1196482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen void visualizeDropLocation(View v, Bitmap dragOutline, int originX, int originY, int cellX, 1197482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int cellY, int spanX, int spanY, boolean resize, Point dragOffset, Rect dragRegion) { 119808ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy final int oldDragCellX = mDragCell[0]; 119908ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy final int oldDragCellY = mDragCell[1]; 1200482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1201b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung if (v != null && dragOffset == null) { 1202a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung mDragCenter.set(originX + (v.getWidth() / 2), originY + (v.getHeight() / 2)); 1203a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung } else { 1204a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung mDragCenter.set(originX, originY); 1205a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung } 12066569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 12072801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen if (dragOutline == null && v == null) { 12082801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen return; 12092801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen } 12102801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen 1211482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (cellX != oldDragCellX || cellY != oldDragCellY) { 1212482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mDragCell[0] = cellX; 1213482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mDragCell[1] = cellY; 12146569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy // Find the top left corner of the rect the object will occupy 1215de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy final int[] topLeft = mTmpPoint; 1216482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen cellToPoint(cellX, cellY, topLeft); 1217de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy 12184be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato int left = topLeft[0]; 12194be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato int top = topLeft[1]; 12206569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 1221b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung if (v != null && dragOffset == null) { 122299e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen // When drawing the drag outline, it did not account for margin offsets 122399e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen // added by the view's parent. 122499e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen MarginLayoutParams lp = (MarginLayoutParams) v.getLayoutParams(); 122599e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen left += lp.leftMargin; 122699e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen top += lp.topMargin; 122799e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen 122899e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen // Offsets due to the size difference between the View and the dragOutline. 122999e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen // There is a size difference to account for the outer blur, which may lie 123099e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen // outside the bounds of the view. 1231a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung top += (v.getHeight() - dragOutline.getHeight()) / 2; 1232ae915cecd36af4973061a1cb0b58c5be1be699a0Adam Cohen // We center about the x axis 1233ae915cecd36af4973061a1cb0b58c5be1be699a0Adam Cohen left += ((mCellWidth * spanX) + ((spanX - 1) * mWidthGap) 1234ae915cecd36af4973061a1cb0b58c5be1be699a0Adam Cohen - dragOutline.getWidth()) / 2; 12356639687cd67bab1aeef2a75e5c6bc458b20dc082Adam Cohen } else { 1236b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung if (dragOffset != null && dragRegion != null) { 1237b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung // Center the drag region *horizontally* in the cell and apply a drag 1238b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung // outline offset 1239b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung left += dragOffset.x + ((mCellWidth * spanX) + ((spanX - 1) * mWidthGap) 1240b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung - dragRegion.width()) / 2; 1241b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung top += dragOffset.y; 1242b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung } else { 1243b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung // Center the drag outline in the cell 1244b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung left += ((mCellWidth * spanX) + ((spanX - 1) * mWidthGap) 1245b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung - dragOutline.getWidth()) / 2; 1246b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung top += ((mCellHeight * spanY) + ((spanY - 1) * mHeightGap) 1247b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung - dragOutline.getHeight()) / 2; 1248b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung } 1249a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung } 12504be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato final int oldIndex = mDragOutlineCurrent; 125108ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy mDragOutlineAnims[oldIndex].animateOut(); 125208ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy mDragOutlineCurrent = (oldIndex + 1) % mDragOutlines.length; 1253d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen Rect r = mDragOutlines[mDragOutlineCurrent]; 1254d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen r.set(left, top, left + dragOutline.getWidth(), top + dragOutline.getHeight()); 1255d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (resize) { 1256482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen cellToRect(cellX, cellY, spanX, spanY, r); 1257d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1258150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung 125908ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy mDragOutlineAnims[mDragOutlineCurrent].setTag(dragOutline); 126008ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy mDragOutlineAnims[mDragOutlineCurrent].animateIn(); 12616569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy } 12626569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy } 12636569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 1264e0310965022e7a1adb7ad489505d404186608689Adam Cohen public void clearDragOutlines() { 1265e0310965022e7a1adb7ad489505d404186608689Adam Cohen final int oldIndex = mDragOutlineCurrent; 1266e0310965022e7a1adb7ad489505d404186608689Adam Cohen mDragOutlineAnims[oldIndex].animateOut(); 1267d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen mDragCell[0] = mDragCell[1] = -1; 1268e0310965022e7a1adb7ad489505d404186608689Adam Cohen } 1269e0310965022e7a1adb7ad489505d404186608689Adam Cohen 127031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 127170864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * Find a vacant area that will fit the given bounds nearest the requested 127270864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * cell location. Uses Euclidean distance to score multiple vacant areas. 1273aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * 127451afc022fa76c79f0d1ece470ddc126c08fea8a4Romain Guy * @param pixelX The X location at which you want to search for a vacant area. 127551afc022fa76c79f0d1ece470ddc126c08fea8a4Romain Guy * @param pixelY The Y location at which you want to search for a vacant area. 127670864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * @param spanX Horizontal span of the object. 127770864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * @param spanY Vertical span of the object. 1278de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy * @param result Array in which to place the result, or null (in which case a new array will 1279de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy * be allocated) 128070864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * @return The X, Y cell of a vacant area that can contain this object, 128170864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * nearest the requested location. 128231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 1283d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int[] findNearestVacantArea(int pixelX, int pixelY, int spanX, int spanY, 1284d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int[] result) { 1285de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy return findNearestVacantArea(pixelX, pixelY, spanX, spanY, null, result); 12866a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka } 1287aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 12886a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka /** 12896a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * Find a vacant area that will fit the given bounds nearest the requested 12906a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * cell location. Uses Euclidean distance to score multiple vacant areas. 12916a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * 12926a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * @param pixelX The X location at which you want to search for a vacant area. 12936a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * @param pixelY The Y location at which you want to search for a vacant area. 1294d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param minSpanX The minimum horizontal span required 1295d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param minSpanY The minimum vertical span required 1296d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param spanX Horizontal span of the object. 1297d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param spanY Vertical span of the object. 1298d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param result Array in which to place the result, or null (in which case a new array will 1299d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * be allocated) 1300d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @return The X, Y cell of a vacant area that can contain this object, 1301d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * nearest the requested location. 1302d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen */ 1303d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int[] findNearestVacantArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, 1304d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int spanY, int[] result, int[] resultSpan) { 1305d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen return findNearestVacantArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, null, 1306d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen result, resultSpan); 1307d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1308d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen 1309d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen /** 1310d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * Find a vacant area that will fit the given bounds nearest the requested 1311d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * cell location. Uses Euclidean distance to score multiple vacant areas. 1312d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * 1313d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param pixelX The X location at which you want to search for a vacant area. 1314d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param pixelY The Y location at which you want to search for a vacant area. 13156a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * @param spanX Horizontal span of the object. 13166a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * @param spanY Vertical span of the object. 1317df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param ignoreOccupied If true, the result can be an occupied cell 1318df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param result Array in which to place the result, or null (in which case a new array will 1319df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * be allocated) 13206a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * @return The X, Y cell of a vacant area that can contain this object, 13216a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * nearest the requested location. 13226a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka */ 1323df0353815c629fc678824b07a234b89a1ff94208Adam Cohen int[] findNearestArea(int pixelX, int pixelY, int spanX, int spanY, View ignoreView, 1324df0353815c629fc678824b07a234b89a1ff94208Adam Cohen boolean ignoreOccupied, int[] result) { 1325d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen return findNearestArea(pixelX, pixelY, spanX, spanY, 1326482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen spanX, spanY, ignoreView, ignoreOccupied, result, null, mOccupied); 1327d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1328d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen 1329d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen private final Stack<Rect> mTempRectStack = new Stack<Rect>(); 1330d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen private void lazyInitTempRectStack() { 1331d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (mTempRectStack.isEmpty()) { 1332d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen for (int i = 0; i < mCountX * mCountY; i++) { 1333d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen mTempRectStack.push(new Rect()); 1334d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1335d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1336d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1337482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1338d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen private void recycleTempRects(Stack<Rect> used) { 1339d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen while (!used.isEmpty()) { 1340d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen mTempRectStack.push(used.pop()); 1341d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1342d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1343d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen 1344d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen /** 1345d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * Find a vacant area that will fit the given bounds nearest the requested 1346d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * cell location. Uses Euclidean distance to score multiple vacant areas. 1347d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * 1348d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param pixelX The X location at which you want to search for a vacant area. 1349d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param pixelY The Y location at which you want to search for a vacant area. 1350d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param minSpanX The minimum horizontal span required 1351d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param minSpanY The minimum vertical span required 1352d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param spanX Horizontal span of the object. 1353d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param spanY Vertical span of the object. 1354d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param ignoreOccupied If true, the result can be an occupied cell 1355d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param result Array in which to place the result, or null (in which case a new array will 1356d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * be allocated) 1357d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @return The X, Y cell of a vacant area that can contain this object, 1358d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * nearest the requested location. 1359d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen */ 1360d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int[] findNearestArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, int spanY, 1361482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen View ignoreView, boolean ignoreOccupied, int[] result, int[] resultSpan, 1362482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean[][] occupied) { 1363d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen lazyInitTempRectStack(); 1364c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka // mark space take by ignoreView as available (method checks if ignoreView is null) 1365482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsAsUnoccupiedForView(ignoreView, occupied); 1366c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka 1367e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen // For items with a spanX / spanY > 1, the passed in point (pixelX, pixelY) corresponds 1368e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen // to the center of the item, but we are searching based on the top-left cell, so 1369e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen // we translate the point over to correspond to the top-left. 1370e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen pixelX -= (mCellWidth + mWidthGap) * (spanX - 1) / 2f; 1371e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen pixelY -= (mCellHeight + mHeightGap) * (spanY - 1) / 2f; 1372e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen 137370864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey // Keep track of best-scoring drop area 1374de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy final int[] bestXY = result != null ? result : new int[2]; 137570864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey double bestDistance = Double.MAX_VALUE; 1376d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen final Rect bestRect = new Rect(-1, -1, -1, -1); 1377d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen final Stack<Rect> validRegions = new Stack<Rect>(); 1378aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 1379de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy final int countX = mCountX; 1380de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy final int countY = mCountY; 1381de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy 1382d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (minSpanX <= 0 || minSpanY <= 0 || spanX <= 0 || spanY <= 0 || 1383d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen spanX < minSpanX || spanY < minSpanY) { 1384d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen return bestXY; 1385d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1386d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen 1387d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen for (int y = 0; y < countY - (minSpanY - 1); y++) { 1388c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka inner: 1389d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen for (int x = 0; x < countX - (minSpanX - 1); x++) { 1390d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int ySize = -1; 1391d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int xSize = -1; 1392df0353815c629fc678824b07a234b89a1ff94208Adam Cohen if (ignoreOccupied) { 1393d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // First, let's see if this thing fits anywhere 1394d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen for (int i = 0; i < minSpanX; i++) { 1395d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen for (int j = 0; j < minSpanY; j++) { 1396df0353815c629fc678824b07a234b89a1ff94208Adam Cohen if (occupied[x + i][y + j]) { 1397df0353815c629fc678824b07a234b89a1ff94208Adam Cohen continue inner; 1398df0353815c629fc678824b07a234b89a1ff94208Adam Cohen } 1399c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka } 1400c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka } 1401d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen xSize = minSpanX; 1402d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen ySize = minSpanY; 1403d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen 1404d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // We know that the item will fit at _some_ acceptable size, now let's see 1405d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // how big we can make it. We'll alternate between incrementing x and y spans 1406d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // until we hit a limit. 1407d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen boolean incX = true; 1408d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen boolean hitMaxX = xSize >= spanX; 1409d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen boolean hitMaxY = ySize >= spanY; 1410d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen while (!(hitMaxX && hitMaxY)) { 1411d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (incX && !hitMaxX) { 1412d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen for (int j = 0; j < ySize; j++) { 1413d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (x + xSize > countX -1 || occupied[x + xSize][y + j]) { 1414d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // We can't move out horizontally 1415d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen hitMaxX = true; 1416d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1417d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1418d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (!hitMaxX) { 1419d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen xSize++; 1420d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1421d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } else if (!hitMaxY) { 1422d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen for (int i = 0; i < xSize; i++) { 1423d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (y + ySize > countY - 1 || occupied[x + i][y + ySize]) { 1424d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // We can't move out vertically 1425d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen hitMaxY = true; 1426d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1427d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1428d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (!hitMaxY) { 1429d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen ySize++; 1430d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1431d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1432d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen hitMaxX |= xSize >= spanX; 1433d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen hitMaxY |= ySize >= spanY; 1434d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen incX = !incX; 1435d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1436d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen incX = true; 1437d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen hitMaxX = xSize >= spanX; 1438d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen hitMaxY = ySize >= spanY; 1439c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka } 14400be025d64c1f84138fe430a58875886e66aae767Winson Chung final int[] cellXY = mTmpXY; 1441e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen cellToCenterPoint(x, y, cellXY); 1442c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka 1443d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // We verify that the current rect is not a sub-rect of any of our previous 1444d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // candidates. In this case, the current rect is disqualified in favour of the 1445d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // containing rect. 1446d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen Rect currentRect = mTempRectStack.pop(); 1447d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen currentRect.set(x, y, x + xSize, y + ySize); 1448d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen boolean contained = false; 1449d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen for (Rect r : validRegions) { 1450d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (r.contains(currentRect)) { 1451d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen contained = true; 1452d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen break; 1453d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1454d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1455d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen validRegions.push(currentRect); 1456c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka double distance = Math.sqrt(Math.pow(cellXY[0] - pixelX, 2) 1457c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka + Math.pow(cellXY[1] - pixelY, 2)); 1458482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1459d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if ((distance <= bestDistance && !contained) || 1460d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen currentRect.contains(bestRect)) { 1461c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka bestDistance = distance; 1462c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka bestXY[0] = x; 1463c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka bestXY[1] = y; 1464d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (resultSpan != null) { 1465d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen resultSpan[0] = xSize; 1466d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen resultSpan[1] = ySize; 1467d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1468d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen bestRect.set(currentRect); 1469c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka } 147031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 147131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 1472c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka // re-mark space taken by ignoreView as occupied 1473482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsAsOccupiedForView(ignoreView, occupied); 147431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 1475c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen // Return -1, -1 if no suitable location found 1476c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen if (bestDistance == Double.MAX_VALUE) { 1477c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen bestXY[0] = -1; 1478c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen bestXY[1] = -1; 147970864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey } 1480d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen recycleTempRects(validRegions); 1481c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen return bestXY; 148231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 1483aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 1484482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen /** 1485482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * Find a vacant area that will fit the given bounds nearest the requested 1486482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * cell location, and will also weigh in a suggested direction vector of the 1487482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * desired location. This method computers distance based on unit grid distances, 1488482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * not pixel distances. 1489482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * 149047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param cellX The X cell nearest to which you want to search for a vacant area. 149147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param cellY The Y cell nearest which you want to search for a vacant area. 1492482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * @param spanX Horizontal span of the object. 1493482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * @param spanY Vertical span of the object. 149447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param direction The favored direction in which the views should move from x, y 149547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param exactDirectionOnly If this parameter is true, then only solutions where the direction 149647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * matches exactly. Otherwise we find the best matching direction. 149747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param occoupied The array which represents which cells in the CellLayout are occupied 149847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param blockOccupied The array which represents which cells in the specified block (cellX, 149947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * cellY, spanX, spanY) are occupied. This is used when try to move a group of views. 1500482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * @param result Array in which to place the result, or null (in which case a new array will 1501482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * be allocated) 1502482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * @return The X, Y cell of a vacant area that can contain this object, 1503482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * nearest the requested location. 1504482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen */ 1505482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private int[] findNearestArea(int cellX, int cellY, int spanX, int spanY, int[] direction, 150647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean[][] occupied, boolean blockOccupied[][], int[] result) { 1507482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // Keep track of best-scoring drop area 1508482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int[] bestXY = result != null ? result : new int[2]; 1509482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen float bestDistance = Float.MAX_VALUE; 1510482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int bestDirectionScore = Integer.MIN_VALUE; 1511482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1512482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int countX = mCountX; 1513482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int countY = mCountY; 1514482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1515482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int y = 0; y < countY - (spanY - 1); y++) { 1516482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen inner: 1517482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int x = 0; x < countX - (spanX - 1); x++) { 1518482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // First, let's see if this thing fits anywhere 1519482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < spanX; i++) { 1520482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int j = 0; j < spanY; j++) { 152147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (occupied[x + i][y + j] && (blockOccupied == null || blockOccupied[i][j])) { 1522482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen continue inner; 1523482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1524482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1525482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1526482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1527482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen float distance = (float) 1528482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen Math.sqrt((x - cellX) * (x - cellX) + (y - cellY) * (y - cellY)); 1529482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int[] curDirection = mTmpPoint; 153047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen computeDirectionVector(x - cellX, y - cellY, curDirection); 153147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen // The direction score is just the dot product of the two candidate direction 153247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen // and that passed in. 1533482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int curDirectionScore = direction[0] * curDirection[0] + 1534482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen direction[1] * curDirection[1]; 153547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean exactDirectionOnly = false; 153647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean directionMatches = direction[0] == curDirection[0] && 153747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen direction[0] == curDirection[0]; 153847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if ((directionMatches || !exactDirectionOnly) && 153947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen Float.compare(distance, bestDistance) < 0 || (Float.compare(distance, 1540482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen bestDistance) == 0 && curDirectionScore > bestDirectionScore)) { 1541482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen bestDistance = distance; 1542482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen bestDirectionScore = curDirectionScore; 1543482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen bestXY[0] = x; 1544482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen bestXY[1] = y; 1545482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1546482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1547482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1548482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1549482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // Return -1, -1 if no suitable location found 1550482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (bestDistance == Float.MAX_VALUE) { 1551482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen bestXY[0] = -1; 1552482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen bestXY[1] = -1; 1553482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1554482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return bestXY; 1555482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1556482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 155747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen private int[] findNearestAreaInDirection(int cellX, int cellY, int spanX, int spanY, 155847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen int[] direction,boolean[][] occupied, 155947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean blockOccupied[][], int[] result) { 156047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen // Keep track of best-scoring drop area 156147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen final int[] bestXY = result != null ? result : new int[2]; 156247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen bestXY[0] = -1; 156347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen bestXY[1] = -1; 156447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen float bestDistance = Float.MAX_VALUE; 156547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 156647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen // We use this to march in a single direction 15675b53f29f809a0dad4a1e0717ba610ce737ee0f43Adam Cohen if ((direction[0] != 0 && direction[1] != 0) || 15685b53f29f809a0dad4a1e0717ba610ce737ee0f43Adam Cohen (direction[0] == 0 && direction[1] == 0)) { 156947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen return bestXY; 157047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 157147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 157247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen // This will only incrememnet one of x or y based on the assertion above 157347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen int x = cellX + direction[0]; 157447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen int y = cellY + direction[1]; 157547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen while (x >= 0 && x + spanX <= mCountX && y >= 0 && y + spanY <= mCountY) { 157647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean fail = false; 157747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen for (int i = 0; i < spanX; i++) { 157847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen for (int j = 0; j < spanY; j++) { 157947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (occupied[x + i][y + j] && (blockOccupied == null || blockOccupied[i][j])) { 158047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen fail = true; 158147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 158247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 158347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 158447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (!fail) { 158547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen float distance = (float) 158647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen Math.sqrt((x - cellX) * (x - cellX) + (y - cellY) * (y - cellY)); 158747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (Float.compare(distance, bestDistance) < 0) { 158847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen bestDistance = distance; 158947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen bestXY[0] = x; 159047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen bestXY[1] = y; 159147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 159247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 159347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen x += direction[0]; 159447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen y += direction[1]; 159547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 159647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen return bestXY; 159747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 159847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 1599482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private boolean addViewToTempLocation(View v, Rect rectOccupiedByPotentialDrop, 16008baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen int[] direction, ItemConfiguration currentState) { 16018baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = currentState.map.get(v); 1602482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean success = false; 16038baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, false); 1604482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsForRect(rectOccupiedByPotentialDrop, mTmpOccupied, true); 1605482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 16068baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen findNearestArea(c.x, c.y, c.spanX, c.spanY, direction, mTmpOccupied, null, mTempLocation); 1607482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1608482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (mTempLocation[0] >= 0 && mTempLocation[1] >= 0) { 16098baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen c.x = mTempLocation[0]; 16108baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen c.y = mTempLocation[1]; 1611482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen success = true; 1612482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1613482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 16148baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, true); 1615482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return success; 1616482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1617482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1618a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen // This method looks in the specified direction to see if there are additional views adjacent 1619e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen // to the current set of views. If there are, then these views are added to the current 1620a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen // set of views. This is performed iteratively, giving a cascading push behaviour. 162147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen private boolean addViewInDirection(ArrayList<View> views, Rect boundingRect, int[] direction, 162219f3792523fe2d55ea791a9286398a6120920690Adam Cohen boolean[][] occupied, View dragView, ItemConfiguration currentState) { 162347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean found = false; 162447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 1625a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka int childCount = mShortcutsAndWidgets.getChildCount(); 162647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen Rect r0 = new Rect(boundingRect); 162747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen Rect r1 = new Rect(); 162847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 1629a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen // First, we consider the rect of the views that we are trying to translate 163047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen int deltaX = 0; 163147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen int deltaY = 0; 163247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (direction[1] < 0) { 1633a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen r0.set(r0.left, r0.top - 1, r0.right, r0.bottom - 1); 163447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen deltaY = -1; 163547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } else if (direction[1] > 0) { 1636a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen r0.set(r0.left, r0.top + 1, r0.right, r0.bottom + 1); 163747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen deltaY = 1; 163847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } else if (direction[0] < 0) { 1639a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen r0.set(r0.left - 1, r0.top, r0.right - 1, r0.bottom); 164047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen deltaX = -1; 164147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } else if (direction[0] > 0) { 1642a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen r0.set(r0.left + 1, r0.top, r0.right + 1, r0.bottom); 164347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen deltaX = 1; 164447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 164547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 1646a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen // Now we see which views, if any, are being overlapped by shifting the current group 1647a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen // of views in the desired direction. 164847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen for (int i = 0; i < childCount; i++) { 1649a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen // We don't need to worry about views already in our group, or the current drag view. 1650a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka View child = mShortcutsAndWidgets.getChildAt(i); 165119f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (views.contains(child) || child == dragView) continue; 16528baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = currentState.map.get(child); 165347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 16548baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen LayoutParams lp = (LayoutParams) child.getLayoutParams(); 16558baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen r1.set(c.x, c.y, c.x + c.spanX, c.y + c.spanY); 165647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (Rect.intersects(r0, r1)) { 165747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (!lp.canReorder) { 165847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen return false; 165947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 1660a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen // First we verify that the view in question is at the border of the extents 1661a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen // of the block of items we are pushing 1662a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen if ((direction[0] < 0 && c.x == r0.left) || 1663a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen (direction[0] > 0 && c.x == r0.right - 1) || 1664a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen (direction[1] < 0 && c.y == r0.top) || 1665a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen (direction[1] > 0 && c.y == r0.bottom - 1)) { 1666a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen boolean pushed = false; 1667e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen // Since the bounding rect is a coarse description of the region (there can 1668a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen // be holes at the edge of the block), we need to check to verify that a solid 1669a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen // piece is intersecting. This ensures that interlocking is possible. 1670a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen for (int x = c.x; x < c.x + c.spanX; x++) { 1671a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen for (int y = c.y; y < c.y + c.spanY; y++) { 1672a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen if (occupied[x - deltaX][y - deltaY]) { 1673a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen pushed = true; 1674a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen break; 1675a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen } 1676a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen if (pushed) break; 167747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 167847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 1679a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen if (pushed) { 1680a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen views.add(child); 1681a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen boundingRect.union(c.x, c.y, c.x + c.spanX, c.y + c.spanY); 1682a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen found = true; 1683a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen } 168447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 168547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 168647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 168747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen return found; 168847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 168947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 1690e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen private void completeSetOfViewsToMove(ArrayList<View> views, Rect boundingRect, int[] direction, 1691e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen boolean[][] occupied, View dragView, ItemConfiguration currentState) { 1692e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen Rect r0 = new Rect(boundingRect); 1693e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen int minRuns = 0; 1694e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen 1695e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen // The first thing we do is to reduce the bounding rect to first or last row or column, 1696e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen // depending on the direction. Then, we add any necessary views that are already contained 1697e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen // by the bounding rect, but aren't in the list of intersecting views, and will be pushed 1698e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen // by something already in the intersecting views. 1699e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen if (direction[1] < 0) { 1700e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen r0.set(r0.left, r0.bottom - 1, r0.right, r0.bottom); 1701e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen } else if (direction[1] > 0) { 1702e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen r0.set(r0.left, r0.top, r0.right, r0.top + 1); 1703e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen } else if (direction[0] < 0) { 1704e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen r0.set(r0.right - 1, r0.top, r0.right, r0.bottom); 1705e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen } else if (direction[0] > 0) { 1706e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen r0.set(r0.left, r0.top, r0.left + 1, r0.bottom); 1707e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen } 1708e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen 1709e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen minRuns = Math.max(Math.abs(boundingRect.width() - r0.width()), 1710e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen Math.abs(boundingRect.height() - r0.height())) + 1; 1711e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen 1712e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen // Here the first number of runs (minRuns) accounts for the the comment above, and 1713e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen // further runs execute based on whether the intersecting views / bounding rect need 1714e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen // to be expanded to include other views that will be pushed. 1715e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen while (addViewInDirection(views, r0, direction, mTmpOccupied, 1716e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen dragView, currentState) || minRuns > 0) { 1717e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen minRuns--; 1718e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen } 1719e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen boundingRect.union(r0); 1720e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen } 1721e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen 17228baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen private boolean addViewsToTempLocation(ArrayList<View> views, Rect rectOccupiedByPotentialDrop, 172319f3792523fe2d55ea791a9286398a6120920690Adam Cohen int[] direction, boolean push, View dragView, ItemConfiguration currentState) { 172447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (views.size() == 0) return true; 172547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 172647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean success = false; 172747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen Rect boundingRect = null; 17288baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // We construct a rect which represents the entire group of views passed in 172947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen for (View v: views) { 17308baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = currentState.map.get(v); 173147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (boundingRect == null) { 17328baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen boundingRect = new Rect(c.x, c.y, c.x + c.spanX, c.y + c.spanY); 173347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } else { 17348baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen boundingRect.union(c.x, c.y, c.x + c.spanX, c.y + c.spanY); 173547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 173647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 173747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 17388baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen @SuppressWarnings("unchecked") 173947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen ArrayList<View> dup = (ArrayList<View>) views.clone(); 1740e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen if (push) { 1741e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen completeSetOfViewsToMove(dup, boundingRect, direction, mTmpOccupied, dragView, 1742e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen currentState); 174347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 17448baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen 17458baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // Mark the occupied state as false for the group of views we want to move. 174647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen for (View v: dup) { 17478baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = currentState.map.get(v); 17488baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, false); 174947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 175047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 175147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean[][] blockOccupied = new boolean[boundingRect.width()][boundingRect.height()]; 175247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen int top = boundingRect.top; 175347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen int left = boundingRect.left; 17548baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // We mark more precisely which parts of the bounding rect are truly occupied, allowing 1755a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen // for interlocking. 175647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen for (View v: dup) { 17578baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = currentState.map.get(v); 17588baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen markCellsForView(c.x - left, c.y - top, c.spanX, c.spanY, blockOccupied, true); 175947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 176047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 176147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen markCellsForRect(rectOccupiedByPotentialDrop, mTmpOccupied, true); 176247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 17638baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen if (push) { 17648baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen findNearestAreaInDirection(boundingRect.left, boundingRect.top, boundingRect.width(), 17658baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen boundingRect.height(), direction, mTmpOccupied, blockOccupied, mTempLocation); 17668baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen } else { 17678baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen findNearestArea(boundingRect.left, boundingRect.top, boundingRect.width(), 17688baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen boundingRect.height(), direction, mTmpOccupied, blockOccupied, mTempLocation); 17698baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen } 177047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 17718baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // If we successfuly found a location by pushing the block of views, we commit it 177247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (mTempLocation[0] >= 0 && mTempLocation[1] >= 0) { 17738baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen int deltaX = mTempLocation[0] - boundingRect.left; 17748baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen int deltaY = mTempLocation[1] - boundingRect.top; 177547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen for (View v: dup) { 17768baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = currentState.map.get(v); 17778baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen c.x += deltaX; 17788baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen c.y += deltaY; 177947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 178047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen success = true; 178147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 1782482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 17838baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // In either case, we set the occupied array as marked for the location of the views 17848baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen for (View v: dup) { 17858baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = currentState.map.get(v); 17868baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, true); 1787482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1788482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return success; 1789482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1790482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1791482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private void markCellsForRect(Rect r, boolean[][] occupied, boolean value) { 1792482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsForView(r.left, r.top, r.width(), r.height(), occupied, value); 1793482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1794482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 17954abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // This method tries to find a reordering solution which satisfies the push mechanic by trying 17964abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // to push items in each of the cardinal directions, in an order based on the direction vector 17974abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // passed. 17984abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen private boolean attemptPushInDirection(ArrayList<View> intersectingViews, Rect occupied, 17994abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen int[] direction, View ignoreView, ItemConfiguration solution) { 18004abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen if ((Math.abs(direction[0]) + Math.abs(direction[1])) > 1) { 18014abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // If the direction vector has two non-zero components, we try pushing 18024abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // separately in each of the components. 18034abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen int temp = direction[1]; 18044abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[1] = 0; 18054abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen if (addViewsToTempLocation(intersectingViews, occupied, direction, true, 18064abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen ignoreView, solution)) { 18074abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen return true; 18084abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen } 18094abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[1] = temp; 18104abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen temp = direction[0]; 18114abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[0] = 0; 18124abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen if (addViewsToTempLocation(intersectingViews, occupied, direction, true, 18134abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen ignoreView, solution)) { 18144abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen return true; 18154abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen } 18164abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // Revert the direction 18174abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[0] = temp; 18184abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen 18194abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // Now we try pushing in each component of the opposite direction 18204abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[0] *= -1; 18214abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[1] *= -1; 18224abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen temp = direction[1]; 18234abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[1] = 0; 18244abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen if (addViewsToTempLocation(intersectingViews, occupied, direction, true, 18254abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen ignoreView, solution)) { 18264abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen return true; 18274abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen } 18284abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen 18294abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[1] = temp; 18304abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen temp = direction[0]; 18314abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[0] = 0; 18324abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen if (addViewsToTempLocation(intersectingViews, occupied, direction, true, 18334abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen ignoreView, solution)) { 18344abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen return true; 18354abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen } 18364abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // revert the direction 18374abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[0] = temp; 18384abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[0] *= -1; 18394abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[1] *= -1; 18404abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen 18414abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen } else { 18424abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // If the direction vector has a single non-zero component, we push first in the 18434abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // direction of the vector 18444abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen if (addViewsToTempLocation(intersectingViews, occupied, direction, true, 18454abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen ignoreView, solution)) { 18464abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen return true; 18474abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen } 18484abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen 18494abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // Then we try the opposite direction 18504abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[0] *= -1; 18514abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[1] *= -1; 18524abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen if (addViewsToTempLocation(intersectingViews, occupied, direction, true, 18534abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen ignoreView, solution)) { 18544abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen return true; 18554abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen } 18564abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // Switch the direction back 18574abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[0] *= -1; 18584abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[1] *= -1; 18594abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen 18604abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // If we have failed to find a push solution with the above, then we try 18614abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // to find a solution by pushing along the perpendicular axis. 18624abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen 18634abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // Swap the components 18644abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen int temp = direction[1]; 18654abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[1] = direction[0]; 18664abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[0] = temp; 18674abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen if (addViewsToTempLocation(intersectingViews, occupied, direction, true, 18684abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen ignoreView, solution)) { 18694abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen return true; 18704abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen } 18714abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen 18724abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // Then we try the opposite direction 18734abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[0] *= -1; 18744abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[1] *= -1; 18754abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen if (addViewsToTempLocation(intersectingViews, occupied, direction, true, 18764abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen ignoreView, solution)) { 18774abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen return true; 18784abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen } 18794abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // Switch the direction back 18804abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[0] *= -1; 18814abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[1] *= -1; 18824abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen 18834abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // Swap the components back 18844abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen temp = direction[1]; 18854abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[1] = direction[0]; 18864abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[0] = temp; 18874abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen } 18884abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen return false; 18894abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen } 18904abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen 1891482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private boolean rearrangementExists(int cellX, int cellY, int spanX, int spanY, int[] direction, 18928baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen View ignoreView, ItemConfiguration solution) { 1893e3e03bcd313ba8060f2832b6a16dea6fd6d532eaWinson Chung // Return early if get invalid cell positions 1894e3e03bcd313ba8060f2832b6a16dea6fd6d532eaWinson Chung if (cellX < 0 || cellY < 0) return false; 1895482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 18968baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen mIntersectingViews.clear(); 1897482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mOccupiedRect.set(cellX, cellY, cellX + spanX, cellY + spanY); 1898482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 18998baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // Mark the desired location of the view currently being dragged. 1900482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (ignoreView != null) { 19018baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = solution.map.get(ignoreView); 190219f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (c != null) { 190319f3792523fe2d55ea791a9286398a6120920690Adam Cohen c.x = cellX; 190419f3792523fe2d55ea791a9286398a6120920690Adam Cohen c.y = cellY; 190519f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 1906482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1907482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen Rect r0 = new Rect(cellX, cellY, cellX + spanX, cellY + spanY); 1908482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen Rect r1 = new Rect(); 19098baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen for (View child: solution.map.keySet()) { 1910482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (child == ignoreView) continue; 19118baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = solution.map.get(child); 1912482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen LayoutParams lp = (LayoutParams) child.getLayoutParams(); 19138baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen r1.set(c.x, c.y, c.x + c.spanX, c.y + c.spanY); 1914482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (Rect.intersects(r0, r1)) { 1915482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (!lp.canReorder) { 1916482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return false; 1917482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1918482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mIntersectingViews.add(child); 1919482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1920482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 192147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 19224abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // First we try to find a solution which respects the push mechanic. That is, 19234abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // we try to find a solution such that no displaced item travels through another item 19244abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // without also displacing that item. 19254abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen if (attemptPushInDirection(mIntersectingViews, mOccupiedRect, direction, ignoreView, 192619f3792523fe2d55ea791a9286398a6120920690Adam Cohen solution)) { 192747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen return true; 192847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 192947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 19304abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // Next we try moving the views as a block, but without requiring the push mechanic. 193119f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (addViewsToTempLocation(mIntersectingViews, mOccupiedRect, direction, false, ignoreView, 193219f3792523fe2d55ea791a9286398a6120920690Adam Cohen solution)) { 1933482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return true; 1934482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 193547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 1936482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // Ok, they couldn't move as a block, let's move them individually 1937482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (View v : mIntersectingViews) { 19388baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen if (!addViewToTempLocation(v, mOccupiedRect, direction, solution)) { 1939482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return false; 1940482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1941482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1942482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return true; 1943482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1944482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1945482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen /* 1946482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * Returns a pair (x, y), where x,y are in {-1, 0, 1} corresponding to vector between 1947482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * the provided point and the provided cell 1948482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen */ 194947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen private void computeDirectionVector(float deltaX, float deltaY, int[] result) { 1950482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen double angle = Math.atan(((float) deltaY) / deltaX); 1951482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1952482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result[0] = 0; 1953482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result[1] = 0; 1954482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (Math.abs(Math.cos(angle)) > 0.5f) { 1955482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result[0] = (int) Math.signum(deltaX); 1956482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1957482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (Math.abs(Math.sin(angle)) > 0.5f) { 1958482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result[1] = (int) Math.signum(deltaY); 1959482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1960482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1961482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 19628baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen private void copyOccupiedArray(boolean[][] occupied) { 19638baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen for (int i = 0; i < mCountX; i++) { 19648baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen for (int j = 0; j < mCountY; j++) { 19658baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen occupied[i][j] = mOccupied[i][j]; 19668baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen } 19678baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen } 19688baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen } 19698baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen 1970482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen ItemConfiguration simpleSwap(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, 1971482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int spanY, int[] direction, View dragView, boolean decX, ItemConfiguration solution) { 19728baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // Copy the current state into the solution. This solution will be manipulated as necessary. 19738baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen copyCurrentStateToSolution(solution, false); 19748baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // Copy the current occupied array into the temporary occupied array. This array will be 19758baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // manipulated as necessary to find a solution. 19768baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen copyOccupiedArray(mTmpOccupied); 1977482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1978482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // We find the nearest cell into which we would place the dragged item, assuming there's 1979482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // nothing in its way. 1980482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int result[] = new int[2]; 1981482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result = findNearestArea(pixelX, pixelY, spanX, spanY, result); 1982482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1983482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean success = false; 1984482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // First we try the exact nearest position of the item being dragged, 1985482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // we will then want to try to move this around to other neighbouring positions 19868baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen success = rearrangementExists(result[0], result[1], spanX, spanY, direction, dragView, 19878baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen solution); 1988482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1989482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (!success) { 1990482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // We try shrinking the widget down to size in an alternating pattern, shrink 1 in 1991482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // x, then 1 in y etc. 1992482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (spanX > minSpanX && (minSpanY == spanY || decX)) { 1993482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return simpleSwap(pixelX, pixelY, minSpanX, minSpanY, spanX - 1, spanY, direction, 1994482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen dragView, false, solution); 1995482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } else if (spanY > minSpanY) { 1996482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return simpleSwap(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY - 1, direction, 1997482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen dragView, true, solution); 1998482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1999482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.isSolution = false; 2000482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } else { 2001482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.isSolution = true; 2002482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewX = result[0]; 2003482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewY = result[1]; 2004482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewSpanX = spanX; 2005482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewSpanY = spanY; 2006482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2007482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return solution; 2008482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2009482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2010482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private void copyCurrentStateToSolution(ItemConfiguration solution, boolean temp) { 2011a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka int childCount = mShortcutsAndWidgets.getChildCount(); 2012482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < childCount; i++) { 2013a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka View child = mShortcutsAndWidgets.getChildAt(i); 2014482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen LayoutParams lp = (LayoutParams) child.getLayoutParams(); 20158baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c; 2016482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (temp) { 20178baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen c = new CellAndSpan(lp.tmpCellX, lp.tmpCellY, lp.cellHSpan, lp.cellVSpan); 2018482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } else { 20198baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen c = new CellAndSpan(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan); 2020482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 20218baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen solution.map.put(child, c); 2022482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2023482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2024482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2025482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private void copySolutionToTempState(ItemConfiguration solution, View dragView) { 2026482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < mCountX; i++) { 2027482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int j = 0; j < mCountY; j++) { 2028482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mTmpOccupied[i][j] = false; 2029482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2030482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2031482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2032a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka int childCount = mShortcutsAndWidgets.getChildCount(); 2033482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < childCount; i++) { 2034a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka View child = mShortcutsAndWidgets.getChildAt(i); 2035482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (child == dragView) continue; 2036482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen LayoutParams lp = (LayoutParams) child.getLayoutParams(); 20378baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = solution.map.get(child); 20388baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen if (c != null) { 20398baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen lp.tmpCellX = c.x; 20408baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen lp.tmpCellY = c.y; 20418baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen lp.cellHSpan = c.spanX; 20428baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen lp.cellVSpan = c.spanY; 20438baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, true); 2044482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2045482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2046482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsForView(solution.dragViewX, solution.dragViewY, solution.dragViewSpanX, 2047482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewSpanY, mTmpOccupied, true); 2048482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2049482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2050482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private void animateItemsToSolution(ItemConfiguration solution, View dragView, boolean 2051482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen commitDragView) { 2052482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2053482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean[][] occupied = DESTRUCTIVE_REORDER ? mOccupied : mTmpOccupied; 2054482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < mCountX; i++) { 2055482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int j = 0; j < mCountY; j++) { 2056482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen occupied[i][j] = false; 2057482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2058482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2059482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2060a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka int childCount = mShortcutsAndWidgets.getChildCount(); 2061482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < childCount; i++) { 2062a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka View child = mShortcutsAndWidgets.getChildAt(i); 2063482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (child == dragView) continue; 20648baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = solution.map.get(child); 20658baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen if (c != null) { 206619f3792523fe2d55ea791a9286398a6120920690Adam Cohen animateChildToPosition(child, c.x, c.y, REORDER_ANIMATION_DURATION, 0, 206719f3792523fe2d55ea791a9286398a6120920690Adam Cohen DESTRUCTIVE_REORDER, false); 20688baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen markCellsForView(c.x, c.y, c.spanX, c.spanY, occupied, true); 2069482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2070482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2071482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (commitDragView) { 2072482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsForView(solution.dragViewX, solution.dragViewY, solution.dragViewSpanX, 2073482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewSpanY, occupied, true); 2074482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2075482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2076482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 207719f3792523fe2d55ea791a9286398a6120920690Adam Cohen // This method starts or changes the reorder hint animations 207819f3792523fe2d55ea791a9286398a6120920690Adam Cohen private void beginOrAdjustHintAnimations(ItemConfiguration solution, View dragView, int delay) { 207919f3792523fe2d55ea791a9286398a6120920690Adam Cohen int childCount = mShortcutsAndWidgets.getChildCount(); 208019f3792523fe2d55ea791a9286398a6120920690Adam Cohen for (int i = 0; i < childCount; i++) { 208119f3792523fe2d55ea791a9286398a6120920690Adam Cohen View child = mShortcutsAndWidgets.getChildAt(i); 208219f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (child == dragView) continue; 208319f3792523fe2d55ea791a9286398a6120920690Adam Cohen CellAndSpan c = solution.map.get(child); 208419f3792523fe2d55ea791a9286398a6120920690Adam Cohen LayoutParams lp = (LayoutParams) child.getLayoutParams(); 208519f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (c != null) { 208619f3792523fe2d55ea791a9286398a6120920690Adam Cohen ReorderHintAnimation rha = new ReorderHintAnimation(child, lp.cellX, lp.cellY, 208719f3792523fe2d55ea791a9286398a6120920690Adam Cohen c.x, c.y, c.spanX, c.spanY); 2088d024f9845a0974ab525baad085f316031cd5a742Adam Cohen rha.animate(); 208919f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 209019f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 209119f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 209219f3792523fe2d55ea791a9286398a6120920690Adam Cohen 209319f3792523fe2d55ea791a9286398a6120920690Adam Cohen // Class which represents the reorder hint animations. These animations show that an item is 209419f3792523fe2d55ea791a9286398a6120920690Adam Cohen // in a temporary state, and hint at where the item will return to. 209519f3792523fe2d55ea791a9286398a6120920690Adam Cohen class ReorderHintAnimation { 209619f3792523fe2d55ea791a9286398a6120920690Adam Cohen View child; 2097d024f9845a0974ab525baad085f316031cd5a742Adam Cohen float finalDeltaX; 2098d024f9845a0974ab525baad085f316031cd5a742Adam Cohen float finalDeltaY; 2099d024f9845a0974ab525baad085f316031cd5a742Adam Cohen float initDeltaX; 2100d024f9845a0974ab525baad085f316031cd5a742Adam Cohen float initDeltaY; 2101d024f9845a0974ab525baad085f316031cd5a742Adam Cohen float finalScale; 2102d024f9845a0974ab525baad085f316031cd5a742Adam Cohen float initScale; 210350e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely private static final int DURATION = 300; 2104e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen Animator a; 210519f3792523fe2d55ea791a9286398a6120920690Adam Cohen 210619f3792523fe2d55ea791a9286398a6120920690Adam Cohen public ReorderHintAnimation(View child, int cellX0, int cellY0, int cellX1, int cellY1, 210719f3792523fe2d55ea791a9286398a6120920690Adam Cohen int spanX, int spanY) { 210819f3792523fe2d55ea791a9286398a6120920690Adam Cohen regionToCenterPoint(cellX0, cellY0, spanX, spanY, mTmpPoint); 210919f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int x0 = mTmpPoint[0]; 211019f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int y0 = mTmpPoint[1]; 211119f3792523fe2d55ea791a9286398a6120920690Adam Cohen regionToCenterPoint(cellX1, cellY1, spanX, spanY, mTmpPoint); 211219f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int x1 = mTmpPoint[0]; 211319f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int y1 = mTmpPoint[1]; 211419f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int dX = x1 - x0; 211519f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int dY = y1 - y0; 2116d024f9845a0974ab525baad085f316031cd5a742Adam Cohen finalDeltaX = 0; 2117d024f9845a0974ab525baad085f316031cd5a742Adam Cohen finalDeltaY = 0; 211819f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (dX == dY && dX == 0) { 211919f3792523fe2d55ea791a9286398a6120920690Adam Cohen } else { 212019f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (dY == 0) { 2121d024f9845a0974ab525baad085f316031cd5a742Adam Cohen finalDeltaX = - Math.signum(dX) * mReorderHintAnimationMagnitude; 212219f3792523fe2d55ea791a9286398a6120920690Adam Cohen } else if (dX == 0) { 2123d024f9845a0974ab525baad085f316031cd5a742Adam Cohen finalDeltaY = - Math.signum(dY) * mReorderHintAnimationMagnitude; 212419f3792523fe2d55ea791a9286398a6120920690Adam Cohen } else { 212519f3792523fe2d55ea791a9286398a6120920690Adam Cohen double angle = Math.atan( (float) (dY) / dX); 2126d024f9845a0974ab525baad085f316031cd5a742Adam Cohen finalDeltaX = (int) (- Math.signum(dX) * 2127fe41ac641bdef7ea96dcbac59b4f3abdbdff6cfeAdam Cohen Math.abs(Math.cos(angle) * mReorderHintAnimationMagnitude)); 2128d024f9845a0974ab525baad085f316031cd5a742Adam Cohen finalDeltaY = (int) (- Math.signum(dY) * 2129fe41ac641bdef7ea96dcbac59b4f3abdbdff6cfeAdam Cohen Math.abs(Math.sin(angle) * mReorderHintAnimationMagnitude)); 213019f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 213119f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 2132d024f9845a0974ab525baad085f316031cd5a742Adam Cohen initDeltaX = child.getTranslationX(); 2133d024f9845a0974ab525baad085f316031cd5a742Adam Cohen initDeltaY = child.getTranslationY(); 2134307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen finalScale = getChildrenScale() - 4.0f / child.getWidth(); 2135d024f9845a0974ab525baad085f316031cd5a742Adam Cohen initScale = child.getScaleX(); 213619f3792523fe2d55ea791a9286398a6120920690Adam Cohen this.child = child; 213719f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 213819f3792523fe2d55ea791a9286398a6120920690Adam Cohen 2139d024f9845a0974ab525baad085f316031cd5a742Adam Cohen void animate() { 214019f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (mShakeAnimators.containsKey(child)) { 214119f3792523fe2d55ea791a9286398a6120920690Adam Cohen ReorderHintAnimation oldAnimation = mShakeAnimators.get(child); 2142d024f9845a0974ab525baad085f316031cd5a742Adam Cohen oldAnimation.cancel(); 214319f3792523fe2d55ea791a9286398a6120920690Adam Cohen mShakeAnimators.remove(child); 2144e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen if (finalDeltaX == 0 && finalDeltaY == 0) { 2145e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen completeAnimationImmediately(); 2146e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen return; 2147e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen } 214819f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 2149d024f9845a0974ab525baad085f316031cd5a742Adam Cohen if (finalDeltaX == 0 && finalDeltaY == 0) { 215019f3792523fe2d55ea791a9286398a6120920690Adam Cohen return; 215119f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 21522ecf995e0d2d55eb71d03f7230ca87270872d1a3Michael Jurka ValueAnimator va = LauncherAnimUtils.ofFloat(0f, 1f); 2153e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen a = va; 215419f3792523fe2d55ea791a9286398a6120920690Adam Cohen va.setRepeatMode(ValueAnimator.REVERSE); 215519f3792523fe2d55ea791a9286398a6120920690Adam Cohen va.setRepeatCount(ValueAnimator.INFINITE); 21567bdfc9700b1cad043c04c757f134db1bf3df00daAdam Cohen va.setDuration(DURATION); 2157d024f9845a0974ab525baad085f316031cd5a742Adam Cohen va.setStartDelay((int) (Math.random() * 60)); 215819f3792523fe2d55ea791a9286398a6120920690Adam Cohen va.addUpdateListener(new AnimatorUpdateListener() { 215919f3792523fe2d55ea791a9286398a6120920690Adam Cohen @Override 216019f3792523fe2d55ea791a9286398a6120920690Adam Cohen public void onAnimationUpdate(ValueAnimator animation) { 216119f3792523fe2d55ea791a9286398a6120920690Adam Cohen float r = ((Float) animation.getAnimatedValue()).floatValue(); 2162d024f9845a0974ab525baad085f316031cd5a742Adam Cohen float x = r * finalDeltaX + (1 - r) * initDeltaX; 2163d024f9845a0974ab525baad085f316031cd5a742Adam Cohen float y = r * finalDeltaY + (1 - r) * initDeltaY; 216419f3792523fe2d55ea791a9286398a6120920690Adam Cohen child.setTranslationX(x); 216519f3792523fe2d55ea791a9286398a6120920690Adam Cohen child.setTranslationY(y); 2166d024f9845a0974ab525baad085f316031cd5a742Adam Cohen float s = r * finalScale + (1 - r) * initScale; 216750e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely child.setScaleX(s); 216850e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely child.setScaleY(s); 216919f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 217019f3792523fe2d55ea791a9286398a6120920690Adam Cohen }); 217119f3792523fe2d55ea791a9286398a6120920690Adam Cohen va.addListener(new AnimatorListenerAdapter() { 217219f3792523fe2d55ea791a9286398a6120920690Adam Cohen public void onAnimationRepeat(Animator animation) { 217319f3792523fe2d55ea791a9286398a6120920690Adam Cohen // We make sure to end only after a full period 2174d024f9845a0974ab525baad085f316031cd5a742Adam Cohen initDeltaX = 0; 2175d024f9845a0974ab525baad085f316031cd5a742Adam Cohen initDeltaY = 0; 2176307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen initScale = getChildrenScale(); 217719f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 217819f3792523fe2d55ea791a9286398a6120920690Adam Cohen }); 217919f3792523fe2d55ea791a9286398a6120920690Adam Cohen mShakeAnimators.put(child, this); 218019f3792523fe2d55ea791a9286398a6120920690Adam Cohen va.start(); 218119f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 218219f3792523fe2d55ea791a9286398a6120920690Adam Cohen 2183d024f9845a0974ab525baad085f316031cd5a742Adam Cohen private void cancel() { 2184e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen if (a != null) { 2185e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen a.cancel(); 2186e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen } 218719f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 2188e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen 218950e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely private void completeAnimationImmediately() { 2190e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen if (a != null) { 2191e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen a.cancel(); 2192e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen } 219350e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely 21942ecf995e0d2d55eb71d03f7230ca87270872d1a3Michael Jurka AnimatorSet s = LauncherAnimUtils.createAnimatorSet(); 2195e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen a = s; 219650e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely s.playTogether( 2197307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen LauncherAnimUtils.ofFloat(child, "scaleX", getChildrenScale()), 2198307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen LauncherAnimUtils.ofFloat(child, "scaleY", getChildrenScale()), 21992ecf995e0d2d55eb71d03f7230ca87270872d1a3Michael Jurka LauncherAnimUtils.ofFloat(child, "translationX", 0f), 22002ecf995e0d2d55eb71d03f7230ca87270872d1a3Michael Jurka LauncherAnimUtils.ofFloat(child, "translationY", 0f) 220150e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely ); 220250e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely s.setDuration(REORDER_ANIMATION_DURATION); 220350e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely s.setInterpolator(new android.view.animation.DecelerateInterpolator(1.5f)); 220450e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely s.start(); 220550e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely } 220619f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 220719f3792523fe2d55ea791a9286398a6120920690Adam Cohen 220819f3792523fe2d55ea791a9286398a6120920690Adam Cohen private void completeAndClearReorderHintAnimations() { 220919f3792523fe2d55ea791a9286398a6120920690Adam Cohen for (ReorderHintAnimation a: mShakeAnimators.values()) { 221050e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely a.completeAnimationImmediately(); 221119f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 221219f3792523fe2d55ea791a9286398a6120920690Adam Cohen mShakeAnimators.clear(); 221319f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 221419f3792523fe2d55ea791a9286398a6120920690Adam Cohen 2215482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private void commitTempPlacement() { 2216482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < mCountX; i++) { 2217482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int j = 0; j < mCountY; j++) { 2218482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mOccupied[i][j] = mTmpOccupied[i][j]; 2219482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2220482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2221a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka int childCount = mShortcutsAndWidgets.getChildCount(); 2222482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < childCount; i++) { 2223ea889a294be004f4b1c21e9b874f9e63abfb8bd6Adam Cohen View child = mShortcutsAndWidgets.getChildAt(i); 2224ea889a294be004f4b1c21e9b874f9e63abfb8bd6Adam Cohen LayoutParams lp = (LayoutParams) child.getLayoutParams(); 2225ea889a294be004f4b1c21e9b874f9e63abfb8bd6Adam Cohen ItemInfo info = (ItemInfo) child.getTag(); 22262acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen // We do a null check here because the item info can be null in the case of the 22272acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen // AllApps button in the hotseat. 22282acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen if (info != null) { 2229487f7dd3059621527eb439d7d51d34e00293f9b1Adam Cohen if (info.cellX != lp.tmpCellX || info.cellY != lp.tmpCellY || 2230487f7dd3059621527eb439d7d51d34e00293f9b1Adam Cohen info.spanX != lp.cellHSpan || info.spanY != lp.cellVSpan) { 2231487f7dd3059621527eb439d7d51d34e00293f9b1Adam Cohen info.requiresDbUpdate = true; 2232487f7dd3059621527eb439d7d51d34e00293f9b1Adam Cohen } 22332acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen info.cellX = lp.cellX = lp.tmpCellX; 22342acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen info.cellY = lp.cellY = lp.tmpCellY; 2235bebf042666cffe52039b875a549a582abd78a431Adam Cohen info.spanX = lp.cellHSpan; 2236bebf042666cffe52039b875a549a582abd78a431Adam Cohen info.spanY = lp.cellVSpan; 22372acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen } 2238482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 22392acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen mLauncher.getWorkspace().updateItemLocationsInDatabase(this); 2240482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2241482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2242482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public void setUseTempCoords(boolean useTempCoords) { 2243a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka int childCount = mShortcutsAndWidgets.getChildCount(); 2244482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < childCount; i++) { 2245a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka LayoutParams lp = (LayoutParams) mShortcutsAndWidgets.getChildAt(i).getLayoutParams(); 2246482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen lp.useTmpCoords = useTempCoords; 2247482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2248482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2249482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2250482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen ItemConfiguration findConfigurationNoShuffle(int pixelX, int pixelY, int minSpanX, int minSpanY, 2251482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int spanX, int spanY, View dragView, ItemConfiguration solution) { 2252482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int[] result = new int[2]; 2253482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int[] resultSpan = new int[2]; 2254482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen findNearestVacantArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, null, result, 2255482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen resultSpan); 2256482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (result[0] >= 0 && result[1] >= 0) { 2257482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen copyCurrentStateToSolution(solution, false); 2258482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewX = result[0]; 2259482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewY = result[1]; 2260482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewSpanX = resultSpan[0]; 2261482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewSpanY = resultSpan[1]; 2262482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.isSolution = true; 2263482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } else { 2264482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.isSolution = false; 2265482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2266482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return solution; 2267482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2268482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2269482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public void prepareChildForDrag(View child) { 2270482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsAsUnoccupiedForView(child); 2271482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2272482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 227319f3792523fe2d55ea791a9286398a6120920690Adam Cohen /* This seems like it should be obvious and straight-forward, but when the direction vector 227419f3792523fe2d55ea791a9286398a6120920690Adam Cohen needs to match with the notion of the dragView pushing other views, we have to employ 227519f3792523fe2d55ea791a9286398a6120920690Adam Cohen a slightly more subtle notion of the direction vector. The question is what two points is 227619f3792523fe2d55ea791a9286398a6120920690Adam Cohen the vector between? The center of the dragView and its desired destination? Not quite, as 227719f3792523fe2d55ea791a9286398a6120920690Adam Cohen this doesn't necessarily coincide with the interaction of the dragView and items occupying 227819f3792523fe2d55ea791a9286398a6120920690Adam Cohen those cells. Instead we use some heuristics to often lock the vector to up, down, left 227919f3792523fe2d55ea791a9286398a6120920690Adam Cohen or right, which helps make pushing feel right. 228019f3792523fe2d55ea791a9286398a6120920690Adam Cohen */ 228119f3792523fe2d55ea791a9286398a6120920690Adam Cohen private void getDirectionVectorForDrop(int dragViewCenterX, int dragViewCenterY, int spanX, 228219f3792523fe2d55ea791a9286398a6120920690Adam Cohen int spanY, View dragView, int[] resultDirection) { 228319f3792523fe2d55ea791a9286398a6120920690Adam Cohen int[] targetDestination = new int[2]; 228419f3792523fe2d55ea791a9286398a6120920690Adam Cohen 228519f3792523fe2d55ea791a9286398a6120920690Adam Cohen findNearestArea(dragViewCenterX, dragViewCenterY, spanX, spanY, targetDestination); 228619f3792523fe2d55ea791a9286398a6120920690Adam Cohen Rect dragRect = new Rect(); 228719f3792523fe2d55ea791a9286398a6120920690Adam Cohen regionToRect(targetDestination[0], targetDestination[1], spanX, spanY, dragRect); 228819f3792523fe2d55ea791a9286398a6120920690Adam Cohen dragRect.offset(dragViewCenterX - dragRect.centerX(), dragViewCenterY - dragRect.centerY()); 228919f3792523fe2d55ea791a9286398a6120920690Adam Cohen 229019f3792523fe2d55ea791a9286398a6120920690Adam Cohen Rect dropRegionRect = new Rect(); 229119f3792523fe2d55ea791a9286398a6120920690Adam Cohen getViewsIntersectingRegion(targetDestination[0], targetDestination[1], spanX, spanY, 229219f3792523fe2d55ea791a9286398a6120920690Adam Cohen dragView, dropRegionRect, mIntersectingViews); 229319f3792523fe2d55ea791a9286398a6120920690Adam Cohen 229419f3792523fe2d55ea791a9286398a6120920690Adam Cohen int dropRegionSpanX = dropRegionRect.width(); 229519f3792523fe2d55ea791a9286398a6120920690Adam Cohen int dropRegionSpanY = dropRegionRect.height(); 229619f3792523fe2d55ea791a9286398a6120920690Adam Cohen 229719f3792523fe2d55ea791a9286398a6120920690Adam Cohen regionToRect(dropRegionRect.left, dropRegionRect.top, dropRegionRect.width(), 229819f3792523fe2d55ea791a9286398a6120920690Adam Cohen dropRegionRect.height(), dropRegionRect); 229919f3792523fe2d55ea791a9286398a6120920690Adam Cohen 230019f3792523fe2d55ea791a9286398a6120920690Adam Cohen int deltaX = (dropRegionRect.centerX() - dragViewCenterX) / spanX; 230119f3792523fe2d55ea791a9286398a6120920690Adam Cohen int deltaY = (dropRegionRect.centerY() - dragViewCenterY) / spanY; 230219f3792523fe2d55ea791a9286398a6120920690Adam Cohen 230319f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (dropRegionSpanX == mCountX || spanX == mCountX) { 230419f3792523fe2d55ea791a9286398a6120920690Adam Cohen deltaX = 0; 230519f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 230619f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (dropRegionSpanY == mCountY || spanY == mCountY) { 230719f3792523fe2d55ea791a9286398a6120920690Adam Cohen deltaY = 0; 230819f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 230919f3792523fe2d55ea791a9286398a6120920690Adam Cohen 231019f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (deltaX == 0 && deltaY == 0) { 231119f3792523fe2d55ea791a9286398a6120920690Adam Cohen // No idea what to do, give a random direction. 231219f3792523fe2d55ea791a9286398a6120920690Adam Cohen resultDirection[0] = 1; 231319f3792523fe2d55ea791a9286398a6120920690Adam Cohen resultDirection[1] = 0; 231419f3792523fe2d55ea791a9286398a6120920690Adam Cohen } else { 231519f3792523fe2d55ea791a9286398a6120920690Adam Cohen computeDirectionVector(deltaX, deltaY, resultDirection); 231619f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 231719f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 231819f3792523fe2d55ea791a9286398a6120920690Adam Cohen 231919f3792523fe2d55ea791a9286398a6120920690Adam Cohen // For a given cell and span, fetch the set of views intersecting the region. 232019f3792523fe2d55ea791a9286398a6120920690Adam Cohen private void getViewsIntersectingRegion(int cellX, int cellY, int spanX, int spanY, 232119f3792523fe2d55ea791a9286398a6120920690Adam Cohen View dragView, Rect boundingRect, ArrayList<View> intersectingViews) { 232219f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (boundingRect != null) { 232319f3792523fe2d55ea791a9286398a6120920690Adam Cohen boundingRect.set(cellX, cellY, cellX + spanX, cellY + spanY); 232419f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 232519f3792523fe2d55ea791a9286398a6120920690Adam Cohen intersectingViews.clear(); 232619f3792523fe2d55ea791a9286398a6120920690Adam Cohen Rect r0 = new Rect(cellX, cellY, cellX + spanX, cellY + spanY); 232719f3792523fe2d55ea791a9286398a6120920690Adam Cohen Rect r1 = new Rect(); 232819f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int count = mShortcutsAndWidgets.getChildCount(); 232919f3792523fe2d55ea791a9286398a6120920690Adam Cohen for (int i = 0; i < count; i++) { 233019f3792523fe2d55ea791a9286398a6120920690Adam Cohen View child = mShortcutsAndWidgets.getChildAt(i); 233119f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (child == dragView) continue; 233219f3792523fe2d55ea791a9286398a6120920690Adam Cohen LayoutParams lp = (LayoutParams) child.getLayoutParams(); 233319f3792523fe2d55ea791a9286398a6120920690Adam Cohen r1.set(lp.cellX, lp.cellY, lp.cellX + lp.cellHSpan, lp.cellY + lp.cellVSpan); 233419f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (Rect.intersects(r0, r1)) { 233519f3792523fe2d55ea791a9286398a6120920690Adam Cohen mIntersectingViews.add(child); 233619f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (boundingRect != null) { 233719f3792523fe2d55ea791a9286398a6120920690Adam Cohen boundingRect.union(r1); 233819f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 233919f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 234019f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 234119f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 234219f3792523fe2d55ea791a9286398a6120920690Adam Cohen 234319f3792523fe2d55ea791a9286398a6120920690Adam Cohen boolean isNearestDropLocationOccupied(int pixelX, int pixelY, int spanX, int spanY, 234419f3792523fe2d55ea791a9286398a6120920690Adam Cohen View dragView, int[] result) { 234519f3792523fe2d55ea791a9286398a6120920690Adam Cohen result = findNearestArea(pixelX, pixelY, spanX, spanY, result); 234619f3792523fe2d55ea791a9286398a6120920690Adam Cohen getViewsIntersectingRegion(result[0], result[1], spanX, spanY, dragView, null, 234719f3792523fe2d55ea791a9286398a6120920690Adam Cohen mIntersectingViews); 234819f3792523fe2d55ea791a9286398a6120920690Adam Cohen return !mIntersectingViews.isEmpty(); 234919f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 235019f3792523fe2d55ea791a9286398a6120920690Adam Cohen 235119f3792523fe2d55ea791a9286398a6120920690Adam Cohen void revertTempState() { 235219f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (!isItemPlacementDirty() || DESTRUCTIVE_REORDER) return; 235319f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int count = mShortcutsAndWidgets.getChildCount(); 235419f3792523fe2d55ea791a9286398a6120920690Adam Cohen for (int i = 0; i < count; i++) { 235519f3792523fe2d55ea791a9286398a6120920690Adam Cohen View child = mShortcutsAndWidgets.getChildAt(i); 235619f3792523fe2d55ea791a9286398a6120920690Adam Cohen LayoutParams lp = (LayoutParams) child.getLayoutParams(); 235719f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (lp.tmpCellX != lp.cellX || lp.tmpCellY != lp.cellY) { 235819f3792523fe2d55ea791a9286398a6120920690Adam Cohen lp.tmpCellX = lp.cellX; 235919f3792523fe2d55ea791a9286398a6120920690Adam Cohen lp.tmpCellY = lp.cellY; 236019f3792523fe2d55ea791a9286398a6120920690Adam Cohen animateChildToPosition(child, lp.cellX, lp.cellY, REORDER_ANIMATION_DURATION, 236119f3792523fe2d55ea791a9286398a6120920690Adam Cohen 0, false, false); 236219f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 236319f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 236419f3792523fe2d55ea791a9286398a6120920690Adam Cohen completeAndClearReorderHintAnimations(); 236519f3792523fe2d55ea791a9286398a6120920690Adam Cohen setItemPlacementDirty(false); 236619f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 236719f3792523fe2d55ea791a9286398a6120920690Adam Cohen 2368bebf042666cffe52039b875a549a582abd78a431Adam Cohen boolean createAreaForResize(int cellX, int cellY, int spanX, int spanY, 2369bebf042666cffe52039b875a549a582abd78a431Adam Cohen View dragView, int[] direction, boolean commit) { 2370bebf042666cffe52039b875a549a582abd78a431Adam Cohen int[] pixelXY = new int[2]; 2371bebf042666cffe52039b875a549a582abd78a431Adam Cohen regionToCenterPoint(cellX, cellY, spanX, spanY, pixelXY); 2372bebf042666cffe52039b875a549a582abd78a431Adam Cohen 2373bebf042666cffe52039b875a549a582abd78a431Adam Cohen // First we determine if things have moved enough to cause a different layout 2374bebf042666cffe52039b875a549a582abd78a431Adam Cohen ItemConfiguration swapSolution = simpleSwap(pixelXY[0], pixelXY[1], spanX, spanY, 2375bebf042666cffe52039b875a549a582abd78a431Adam Cohen spanX, spanY, direction, dragView, true, new ItemConfiguration()); 2376bebf042666cffe52039b875a549a582abd78a431Adam Cohen 2377bebf042666cffe52039b875a549a582abd78a431Adam Cohen setUseTempCoords(true); 2378bebf042666cffe52039b875a549a582abd78a431Adam Cohen if (swapSolution != null && swapSolution.isSolution) { 2379bebf042666cffe52039b875a549a582abd78a431Adam Cohen // If we're just testing for a possible location (MODE_ACCEPT_DROP), we don't bother 2380bebf042666cffe52039b875a549a582abd78a431Adam Cohen // committing anything or animating anything as we just want to determine if a solution 2381bebf042666cffe52039b875a549a582abd78a431Adam Cohen // exists 2382bebf042666cffe52039b875a549a582abd78a431Adam Cohen copySolutionToTempState(swapSolution, dragView); 2383bebf042666cffe52039b875a549a582abd78a431Adam Cohen setItemPlacementDirty(true); 2384bebf042666cffe52039b875a549a582abd78a431Adam Cohen animateItemsToSolution(swapSolution, dragView, commit); 2385bebf042666cffe52039b875a549a582abd78a431Adam Cohen 2386bebf042666cffe52039b875a549a582abd78a431Adam Cohen if (commit) { 2387bebf042666cffe52039b875a549a582abd78a431Adam Cohen commitTempPlacement(); 2388bebf042666cffe52039b875a549a582abd78a431Adam Cohen completeAndClearReorderHintAnimations(); 2389bebf042666cffe52039b875a549a582abd78a431Adam Cohen setItemPlacementDirty(false); 2390bebf042666cffe52039b875a549a582abd78a431Adam Cohen } else { 2391bebf042666cffe52039b875a549a582abd78a431Adam Cohen beginOrAdjustHintAnimations(swapSolution, dragView, 2392bebf042666cffe52039b875a549a582abd78a431Adam Cohen REORDER_ANIMATION_DURATION); 2393bebf042666cffe52039b875a549a582abd78a431Adam Cohen } 2394bebf042666cffe52039b875a549a582abd78a431Adam Cohen mShortcutsAndWidgets.requestLayout(); 2395bebf042666cffe52039b875a549a582abd78a431Adam Cohen } 2396bebf042666cffe52039b875a549a582abd78a431Adam Cohen return swapSolution.isSolution; 2397bebf042666cffe52039b875a549a582abd78a431Adam Cohen } 2398bebf042666cffe52039b875a549a582abd78a431Adam Cohen 2399482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int[] createArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, int spanY, 2400482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen View dragView, int[] result, int resultSpan[], int mode) { 2401482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // First we determine if things have moved enough to cause a different layout 240247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen result = findNearestArea(pixelX, pixelY, spanX, spanY, result); 2403482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2404482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (resultSpan == null) { 2405482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen resultSpan = new int[2]; 2406482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2407482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 240819f3792523fe2d55ea791a9286398a6120920690Adam Cohen // When we are checking drop validity or actually dropping, we don't recompute the 240919f3792523fe2d55ea791a9286398a6120920690Adam Cohen // direction vector, since we want the solution to match the preview, and it's possible 241019f3792523fe2d55ea791a9286398a6120920690Adam Cohen // that the exact position of the item has changed to result in a new reordering outcome. 2411b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen if ((mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL || mode == MODE_ACCEPT_DROP) 2412b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen && mPreviousReorderDirection[0] != INVALID_DIRECTION) { 241319f3792523fe2d55ea791a9286398a6120920690Adam Cohen mDirectionVector[0] = mPreviousReorderDirection[0]; 241419f3792523fe2d55ea791a9286398a6120920690Adam Cohen mDirectionVector[1] = mPreviousReorderDirection[1]; 241519f3792523fe2d55ea791a9286398a6120920690Adam Cohen // We reset this vector after drop 2416b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen if (mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL) { 2417b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen mPreviousReorderDirection[0] = INVALID_DIRECTION; 2418b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen mPreviousReorderDirection[1] = INVALID_DIRECTION; 241919f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 242019f3792523fe2d55ea791a9286398a6120920690Adam Cohen } else { 242119f3792523fe2d55ea791a9286398a6120920690Adam Cohen getDirectionVectorForDrop(pixelX, pixelY, spanX, spanY, dragView, mDirectionVector); 242219f3792523fe2d55ea791a9286398a6120920690Adam Cohen mPreviousReorderDirection[0] = mDirectionVector[0]; 242319f3792523fe2d55ea791a9286398a6120920690Adam Cohen mPreviousReorderDirection[1] = mDirectionVector[1]; 242419f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 242519f3792523fe2d55ea791a9286398a6120920690Adam Cohen 2426482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen ItemConfiguration swapSolution = simpleSwap(pixelX, pixelY, minSpanX, minSpanY, 2427482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen spanX, spanY, mDirectionVector, dragView, true, new ItemConfiguration()); 2428482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2429482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // We attempt the approach which doesn't shuffle views at all 2430482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen ItemConfiguration noShuffleSolution = findConfigurationNoShuffle(pixelX, pixelY, minSpanX, 2431482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen minSpanY, spanX, spanY, dragView, new ItemConfiguration()); 2432482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2433482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen ItemConfiguration finalSolution = null; 2434482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (swapSolution.isSolution && swapSolution.area() >= noShuffleSolution.area()) { 2435482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen finalSolution = swapSolution; 2436482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } else if (noShuffleSolution.isSolution) { 2437482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen finalSolution = noShuffleSolution; 2438482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2439482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2440482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean foundSolution = true; 2441482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (!DESTRUCTIVE_REORDER) { 2442482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen setUseTempCoords(true); 2443482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2444482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2445482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (finalSolution != null) { 2446482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result[0] = finalSolution.dragViewX; 2447482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result[1] = finalSolution.dragViewY; 2448482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen resultSpan[0] = finalSolution.dragViewSpanX; 2449482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen resultSpan[1] = finalSolution.dragViewSpanY; 2450482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2451482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // If we're just testing for a possible location (MODE_ACCEPT_DROP), we don't bother 2452482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // committing anything or animating anything as we just want to determine if a solution 2453482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // exists 2454482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (mode == MODE_DRAG_OVER || mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL) { 2455482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (!DESTRUCTIVE_REORDER) { 2456482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen copySolutionToTempState(finalSolution, dragView); 2457482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2458482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen setItemPlacementDirty(true); 2459482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen animateItemsToSolution(finalSolution, dragView, mode == MODE_ON_DROP); 2460482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 246119f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (!DESTRUCTIVE_REORDER && 246219f3792523fe2d55ea791a9286398a6120920690Adam Cohen (mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL)) { 2463482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen commitTempPlacement(); 246419f3792523fe2d55ea791a9286398a6120920690Adam Cohen completeAndClearReorderHintAnimations(); 246519f3792523fe2d55ea791a9286398a6120920690Adam Cohen setItemPlacementDirty(false); 246619f3792523fe2d55ea791a9286398a6120920690Adam Cohen } else { 246719f3792523fe2d55ea791a9286398a6120920690Adam Cohen beginOrAdjustHintAnimations(finalSolution, dragView, 246819f3792523fe2d55ea791a9286398a6120920690Adam Cohen REORDER_ANIMATION_DURATION); 2469482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2470482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2471482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } else { 2472482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen foundSolution = false; 2473482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result[0] = result[1] = resultSpan[0] = resultSpan[1] = -1; 2474482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2475482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2476482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if ((mode == MODE_ON_DROP || !foundSolution) && !DESTRUCTIVE_REORDER) { 2477482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen setUseTempCoords(false); 2478482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2479482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2480a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.requestLayout(); 2481482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return result; 2482482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2483482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 248419f3792523fe2d55ea791a9286398a6120920690Adam Cohen void setItemPlacementDirty(boolean dirty) { 248519f3792523fe2d55ea791a9286398a6120920690Adam Cohen mItemPlacementDirty = dirty; 2486482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 248719f3792523fe2d55ea791a9286398a6120920690Adam Cohen boolean isItemPlacementDirty() { 248819f3792523fe2d55ea791a9286398a6120920690Adam Cohen return mItemPlacementDirty; 2489482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2490482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2491482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private class ItemConfiguration { 24928baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen HashMap<View, CellAndSpan> map = new HashMap<View, CellAndSpan>(); 2493482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean isSolution = false; 2494482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int dragViewX, dragViewY, dragViewSpanX, dragViewSpanY; 2495482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2496482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int area() { 2497482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return dragViewSpanX * dragViewSpanY; 2498482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 24998baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen } 25008baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen 25018baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen private class CellAndSpan { 25028baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen int x, y; 25038baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen int spanX, spanY; 25048baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen 25058baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen public CellAndSpan(int x, int y, int spanX, int spanY) { 25068baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen this.x = x; 25078baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen this.y = y; 25088baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen this.spanX = spanX; 25098baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen this.spanY = spanY; 2510482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2511482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2512482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2513df0353815c629fc678824b07a234b89a1ff94208Adam Cohen /** 2514df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * Find a vacant area that will fit the given bounds nearest the requested 2515df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * cell location. Uses Euclidean distance to score multiple vacant areas. 2516df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * 2517df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param pixelX The X location at which you want to search for a vacant area. 2518df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param pixelY The Y location at which you want to search for a vacant area. 2519df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param spanX Horizontal span of the object. 2520df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param spanY Vertical span of the object. 2521df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param ignoreView Considers space occupied by this view as unoccupied 2522df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param result Previously returned value to possibly recycle. 2523df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @return The X, Y cell of a vacant area that can contain this object, 2524df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * nearest the requested location. 2525df0353815c629fc678824b07a234b89a1ff94208Adam Cohen */ 2526df0353815c629fc678824b07a234b89a1ff94208Adam Cohen int[] findNearestVacantArea( 2527df0353815c629fc678824b07a234b89a1ff94208Adam Cohen int pixelX, int pixelY, int spanX, int spanY, View ignoreView, int[] result) { 2528df0353815c629fc678824b07a234b89a1ff94208Adam Cohen return findNearestArea(pixelX, pixelY, spanX, spanY, ignoreView, true, result); 2529df0353815c629fc678824b07a234b89a1ff94208Adam Cohen } 2530df0353815c629fc678824b07a234b89a1ff94208Adam Cohen 2531df0353815c629fc678824b07a234b89a1ff94208Adam Cohen /** 2532d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * Find a vacant area that will fit the given bounds nearest the requested 2533d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * cell location. Uses Euclidean distance to score multiple vacant areas. 2534d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * 2535d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param pixelX The X location at which you want to search for a vacant area. 2536d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param pixelY The Y location at which you want to search for a vacant area. 2537d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param minSpanX The minimum horizontal span required 2538d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param minSpanY The minimum vertical span required 2539d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param spanX Horizontal span of the object. 2540d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param spanY Vertical span of the object. 2541d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param ignoreView Considers space occupied by this view as unoccupied 2542d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param result Previously returned value to possibly recycle. 2543d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @return The X, Y cell of a vacant area that can contain this object, 2544d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * nearest the requested location. 2545d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen */ 2546d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int[] findNearestVacantArea(int pixelX, int pixelY, int minSpanX, int minSpanY, 2547d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int spanX, int spanY, View ignoreView, int[] result, int[] resultSpan) { 2548482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return findNearestArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, ignoreView, true, 2549482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result, resultSpan, mOccupied); 2550d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 2551d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen 2552d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen /** 2553df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * Find a starting cell position that will fit the given bounds nearest the requested 2554df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * cell location. Uses Euclidean distance to score multiple vacant areas. 2555df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * 2556df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param pixelX The X location at which you want to search for a vacant area. 2557df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param pixelY The Y location at which you want to search for a vacant area. 2558df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param spanX Horizontal span of the object. 2559df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param spanY Vertical span of the object. 2560df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param ignoreView Considers space occupied by this view as unoccupied 2561df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param result Previously returned value to possibly recycle. 2562df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @return The X, Y cell of a vacant area that can contain this object, 2563df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * nearest the requested location. 2564df0353815c629fc678824b07a234b89a1ff94208Adam Cohen */ 2565df0353815c629fc678824b07a234b89a1ff94208Adam Cohen int[] findNearestArea( 2566df0353815c629fc678824b07a234b89a1ff94208Adam Cohen int pixelX, int pixelY, int spanX, int spanY, int[] result) { 2567df0353815c629fc678824b07a234b89a1ff94208Adam Cohen return findNearestArea(pixelX, pixelY, spanX, spanY, null, false, result); 2568df0353815c629fc678824b07a234b89a1ff94208Adam Cohen } 2569df0353815c629fc678824b07a234b89a1ff94208Adam Cohen 25700280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka boolean existsEmptyCell() { 25710280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka return findCellForSpan(null, 1, 1); 25720280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 25730280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 25740280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka /** 25750280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * Finds the upper-left coordinate of the first rectangle in the grid that can 25760280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * hold a cell of the specified dimensions. If intersectX and intersectY are not -1, 25770280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * then this method will only return coordinates for rectangles that contain the cell 25780280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * (intersectX, intersectY) 25790280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * 25800280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param cellXY The array that will contain the position of a vacant cell if such a cell 25810280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * can be found. 25820280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param spanX The horizontal span of the cell we want to find. 25830280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param spanY The vertical span of the cell we want to find. 25840280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * 25850280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @return True if a vacant cell of the specified dimension was found, false otherwise. 25860280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka */ 25870280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka boolean findCellForSpan(int[] cellXY, int spanX, int spanY) { 2588482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return findCellForSpanThatIntersectsIgnoring(cellXY, spanX, spanY, -1, -1, null, mOccupied); 25890280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 25900280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 25910280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka /** 25920280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * Like above, but ignores any cells occupied by the item "ignoreView" 25930280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * 25940280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param cellXY The array that will contain the position of a vacant cell if such a cell 25950280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * can be found. 25960280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param spanX The horizontal span of the cell we want to find. 25970280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param spanY The vertical span of the cell we want to find. 25980280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param ignoreView The home screen item we should treat as not occupying any space 25990280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @return 26000280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka */ 26010280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka boolean findCellForSpanIgnoring(int[] cellXY, int spanX, int spanY, View ignoreView) { 2602482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return findCellForSpanThatIntersectsIgnoring(cellXY, spanX, spanY, -1, -1, 2603482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen ignoreView, mOccupied); 26040280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 26050280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 26060280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka /** 26070280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * Like above, but if intersectX and intersectY are not -1, then this method will try to 26080280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * return coordinates for rectangles that contain the cell [intersectX, intersectY] 26090280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * 26100280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param spanX The horizontal span of the cell we want to find. 26110280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param spanY The vertical span of the cell we want to find. 26120280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param ignoreView The home screen item we should treat as not occupying any space 26130280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param intersectX The X coordinate of the cell that we should try to overlap 26140280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param intersectX The Y coordinate of the cell that we should try to overlap 26150280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * 26160280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @return True if a vacant cell of the specified dimension was found, false otherwise. 26170280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka */ 26180280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka boolean findCellForSpanThatIntersects(int[] cellXY, int spanX, int spanY, 26190280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka int intersectX, int intersectY) { 26200280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka return findCellForSpanThatIntersectsIgnoring( 2621482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen cellXY, spanX, spanY, intersectX, intersectY, null, mOccupied); 26220280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 26230280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 26240280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka /** 26250280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * The superset of the above two methods 26260280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka */ 26270280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka boolean findCellForSpanThatIntersectsIgnoring(int[] cellXY, int spanX, int spanY, 2628482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int intersectX, int intersectY, View ignoreView, boolean occupied[][]) { 2629c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka // mark space take by ignoreView as available (method checks if ignoreView is null) 2630482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsAsUnoccupiedForView(ignoreView, occupied); 26310280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 263228750fba6a2d141eb9a1e566718c17236030b815Michael Jurka boolean foundCell = false; 26330280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka while (true) { 26340280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka int startX = 0; 26350280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka if (intersectX >= 0) { 26360280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka startX = Math.max(startX, intersectX - (spanX - 1)); 26370280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 26380280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka int endX = mCountX - (spanX - 1); 26390280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka if (intersectX >= 0) { 26400280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka endX = Math.min(endX, intersectX + (spanX - 1) + (spanX == 1 ? 1 : 0)); 26410280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 26420280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka int startY = 0; 26430280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka if (intersectY >= 0) { 26440280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka startY = Math.max(startY, intersectY - (spanY - 1)); 26450280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 26460280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka int endY = mCountY - (spanY - 1); 26470280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka if (intersectY >= 0) { 26480280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka endY = Math.min(endY, intersectY + (spanY - 1) + (spanY == 1 ? 1 : 0)); 26490280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 26500280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 2651bbc60d8e79416e37cbede55c159bf6aaa6c171d5Winson Chung for (int y = startY; y < endY && !foundCell; y++) { 26520280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka inner: 2653bbc60d8e79416e37cbede55c159bf6aaa6c171d5Winson Chung for (int x = startX; x < endX; x++) { 26540280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka for (int i = 0; i < spanX; i++) { 26550280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka for (int j = 0; j < spanY; j++) { 2656482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (occupied[x + i][y + j]) { 2657bbc60d8e79416e37cbede55c159bf6aaa6c171d5Winson Chung // small optimization: we can skip to after the column we just found 26580280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // an occupied cell 2659bbc60d8e79416e37cbede55c159bf6aaa6c171d5Winson Chung x += i; 26600280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka continue inner; 26610280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 26620280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 26630280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 26640280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka if (cellXY != null) { 26650280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka cellXY[0] = x; 26660280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka cellXY[1] = y; 26670280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 266828750fba6a2d141eb9a1e566718c17236030b815Michael Jurka foundCell = true; 266928750fba6a2d141eb9a1e566718c17236030b815Michael Jurka break; 26700280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 26710280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 26720280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka if (intersectX == -1 && intersectY == -1) { 26730280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka break; 26740280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } else { 26750280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // if we failed to find anything, try again but without any requirements of 26760280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // intersecting 26770280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka intersectX = -1; 26780280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka intersectY = -1; 26790280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka continue; 26800280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 26810280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 26820280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 2683c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka // re-mark space taken by ignoreView as occupied 2684482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsAsOccupiedForView(ignoreView, occupied); 268528750fba6a2d141eb9a1e566718c17236030b815Michael Jurka return foundCell; 26860280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 26870280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 268831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 2689c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung * A drag event has begun over this layout. 2690c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung * It may have begun over this layout (in which case onDragChild is called first), 2691c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung * or it may have begun on another layout. 2692c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung */ 2693c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung void onDragEnter() { 2694c6cc61d45836e4081920883cc4d448ccb0bb8417Adam Cohen mDragEnforcer.onDragEnter(); 2695c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung mDragging = true; 2696c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung } 2697c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung 2698c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung /** 26990280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * Called when drag has left this CellLayout or has been completed (successfully or not) 27006569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy */ 27010280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka void onDragExit() { 2702c6cc61d45836e4081920883cc4d448ccb0bb8417Adam Cohen mDragEnforcer.onDragExit(); 27034be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // This can actually be called when we aren't in a drag, e.g. when adding a new 27044be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // item to this layout via the customize drawer. 27054be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // Guard against that case. 27064be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato if (mDragging) { 27074be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato mDragging = false; 27084be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato } 270908ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy 271008ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy // Invalidate the drag data 2711d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen mDragCell[0] = mDragCell[1] = -1; 271208ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy mDragOutlineAnims[mDragOutlineCurrent].animateOut(); 271308ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy mDragOutlineCurrent = (mDragOutlineCurrent + 1) % mDragOutlineAnims.length; 271419f3792523fe2d55ea791a9286398a6120920690Adam Cohen revertTempState(); 271533945b21544bc98381df17726a3537c292d8c985Michael Jurka setIsDragOverlapping(false); 27166569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy } 27176569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 27186569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy /** 2719aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * Mark a child as having been dropped. 2720de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy * At the beginning of the drag operation, the child may have been on another 2721ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy * screen, but it is re-parented before this method is called. 272231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 272331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param child The child that is being dropped 272431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 2725716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen void onDropChild(View child) { 2726d94533d04a5f8f5485f106d10af60169857ea899Romain Guy if (child != null) { 2727d94533d04a5f8f5485f106d10af60169857ea899Romain Guy LayoutParams lp = (LayoutParams) child.getLayoutParams(); 272884f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy lp.dropped = true; 2729d94533d04a5f8f5485f106d10af60169857ea899Romain Guy child.requestLayout(); 2730d94533d04a5f8f5485f106d10af60169857ea899Romain Guy } 273131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 273231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 273331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 273431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Computes a bounding rectangle for a range of cells 2735aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * 273631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param cellX X coordinate of upper left corner expressed as a cell position 273731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param cellY Y coordinate of upper left corner expressed as a cell position 2738aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * @param cellHSpan Width in cells 273931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param cellVSpan Height in cells 27406569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy * @param resultRect Rect into which to put the results 274131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 2742d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen public void cellToRect(int cellX, int cellY, int cellHSpan, int cellVSpan, Rect resultRect) { 274331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int cellWidth = mCellWidth; 274431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int cellHeight = mCellHeight; 274531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int widthGap = mWidthGap; 274631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int heightGap = mHeightGap; 2747aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 27484b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung final int hStartPadding = getPaddingLeft(); 27494b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung final int vStartPadding = getPaddingTop(); 2750aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 275131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int width = cellHSpan * cellWidth + ((cellHSpan - 1) * widthGap); 275231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int height = cellVSpan * cellHeight + ((cellVSpan - 1) * heightGap); 275331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 275431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int x = hStartPadding + cellX * (cellWidth + widthGap); 275531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int y = vStartPadding + cellY * (cellHeight + heightGap); 2756aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 27576569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy resultRect.set(x, y, x + width, y + height); 275831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 2759aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 276031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 2761aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * Computes the required horizontal and vertical cell spans to always 276231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * fit the given rectangle. 2763aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * 276431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param width Width in pixels 276531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param height Height in pixels 27668f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy * @param result An array of length 2 in which to store the result (may be null). 276731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 27688f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy public int[] rectToCell(int width, int height, int[] result) { 27699987a5c45e7d01a780d73b269bdce8d8a5309219Michael Jurka return rectToCell(getResources(), width, height, result); 27709987a5c45e7d01a780d73b269bdce8d8a5309219Michael Jurka } 27719987a5c45e7d01a780d73b269bdce8d8a5309219Michael Jurka 27729987a5c45e7d01a780d73b269bdce8d8a5309219Michael Jurka public static int[] rectToCell(Resources resources, int width, int height, int[] result) { 277331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // Always assume we're working with the smallest span to make sure we 277431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // reserve enough space in both orientations. 277579e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato int actualWidth = resources.getDimensionPixelSize(R.dimen.workspace_cell_width); 277679e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato int actualHeight = resources.getDimensionPixelSize(R.dimen.workspace_cell_height); 277731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int smallerSize = Math.min(actualWidth, actualHeight); 277879e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato 277931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // Always round up to next largest cell 278054c725cc294cd43ed0650179bfae64a622547660Winson Chung int spanX = (int) Math.ceil(width / (float) smallerSize); 278154c725cc294cd43ed0650179bfae64a622547660Winson Chung int spanY = (int) Math.ceil(height / (float) smallerSize); 278279e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato 27838f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy if (result == null) { 27848f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy return new int[] { spanX, spanY }; 27858f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy } 27868f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy result[0] = spanX; 27878f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy result[1] = spanY; 27888f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy return result; 278931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 279031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 2791f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka public int[] cellSpansToSize(int hSpans, int vSpans) { 2792f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka int[] size = new int[2]; 2793f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka size[0] = hSpans * mCellWidth + (hSpans - 1) * mWidthGap; 2794f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka size[1] = vSpans * mCellHeight + (vSpans - 1) * mHeightGap; 2795f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka return size; 2796f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka } 2797f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka 279831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 2799047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy * Calculate the grid spans needed to fit given item 2800047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy */ 2801047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy public void calculateSpans(ItemInfo info) { 2802047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy final int minWidth; 2803047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy final int minHeight; 2804047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy 2805047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy if (info instanceof LauncherAppWidgetInfo) { 2806047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy minWidth = ((LauncherAppWidgetInfo) info).minWidth; 2807047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy minHeight = ((LauncherAppWidgetInfo) info).minHeight; 2808047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy } else if (info instanceof PendingAddWidgetInfo) { 2809047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy minWidth = ((PendingAddWidgetInfo) info).minWidth; 2810047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy minHeight = ((PendingAddWidgetInfo) info).minHeight; 2811047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy } else { 2812047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy // It's not a widget, so it must be 1x1 2813047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy info.spanX = info.spanY = 1; 2814047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy return; 2815047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy } 2816047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy int[] spans = rectToCell(minWidth, minHeight, null); 2817047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy info.spanX = spans[0]; 2818047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy info.spanY = spans[1]; 2819047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy } 2820047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy 2821047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy /** 282231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Find the first vacant cell, if there is one. 282331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 282431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param vacant Holds the x and y coordinate of the vacant cell 282531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param spanX Horizontal cell span. 282631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param spanY Vertical cell span. 2827aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * 282831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @return True if a vacant cell was found 282931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 283031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public boolean getVacantCell(int[] vacant, int spanX, int spanY) { 283131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 28320280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka return findVacantCell(vacant, spanX, spanY, mCountX, mCountY, mOccupied); 283331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 283431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 283531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project static boolean findVacantCell(int[] vacant, int spanX, int spanY, 283631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int xCount, int yCount, boolean[][] occupied) { 283731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 28382801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen for (int y = 0; y < yCount; y++) { 28392801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen for (int x = 0; x < xCount; x++) { 284031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project boolean available = !occupied[x][y]; 284131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectout: for (int i = x; i < x + spanX - 1 && x < xCount; i++) { 284231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int j = y; j < y + spanY - 1 && y < yCount; j++) { 284331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project available = available && !occupied[i][j]; 284431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (!available) break out; 284531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 284631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 284731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 284831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (available) { 284931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project vacant[0] = x; 285031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project vacant[1] = y; 285131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return true; 285231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 285331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 285431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 285531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 285631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return false; 285731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 285831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 28590280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka private void clearOccupiedCells() { 28600280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka for (int x = 0; x < mCountX; x++) { 28610280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka for (int y = 0; y < mCountY; y++) { 28620280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka mOccupied[x][y] = false; 286331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 286431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 28650280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 286631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 2867d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen public void onMove(View view, int newCellX, int newCellY, int newSpanX, int newSpanY) { 28680280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka markCellsAsUnoccupiedForView(view); 2869482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsForView(newCellX, newCellY, newSpanX, newSpanY, mOccupied, true); 28700280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 287131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 2872d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen public void markCellsAsOccupiedForView(View view) { 2873482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsAsOccupiedForView(view, mOccupied); 2874482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2875482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public void markCellsAsOccupiedForView(View view, boolean[][] occupied) { 2876a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka if (view == null || view.getParent() != mShortcutsAndWidgets) return; 28770280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka LayoutParams lp = (LayoutParams) view.getLayoutParams(); 2878482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, occupied, true); 28790280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 28800280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 2881d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen public void markCellsAsUnoccupiedForView(View view) { 2882482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsAsUnoccupiedForView(view, mOccupied); 2883482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2884482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public void markCellsAsUnoccupiedForView(View view, boolean occupied[][]) { 2885a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka if (view == null || view.getParent() != mShortcutsAndWidgets) return; 28860280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka LayoutParams lp = (LayoutParams) view.getLayoutParams(); 2887482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, occupied, false); 28880280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 28890280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 2890482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private void markCellsForView(int cellX, int cellY, int spanX, int spanY, boolean[][] occupied, 2891482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean value) { 2892482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (cellX < 0 || cellY < 0) return; 28930280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka for (int x = cellX; x < cellX + spanX && x < mCountX; x++) { 28940280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka for (int y = cellY; y < cellY + spanY && y < mCountY; y++) { 2895482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen occupied[x][y] = value; 289631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 289731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 289831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 289931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 29002801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen public int getDesiredWidth() { 29018b805b17158886035b38261eb611d8641701ae43Michael Jurka return getPaddingLeft() + getPaddingRight() + (mCountX * mCellWidth) + 29022801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen (Math.max((mCountX - 1), 0) * mWidthGap); 29032801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen } 29042801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen 29052801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen public int getDesiredHeight() { 29068b805b17158886035b38261eb611d8641701ae43Michael Jurka return getPaddingTop() + getPaddingBottom() + (mCountY * mCellHeight) + 29072801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen (Math.max((mCountY - 1), 0) * mHeightGap); 29082801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen } 29092801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen 291066d72178af91d455700875635473be942bc90e54Michael Jurka public boolean isOccupied(int x, int y) { 291166d72178af91d455700875635473be942bc90e54Michael Jurka if (x < mCountX && y < mCountY) { 291266d72178af91d455700875635473be942bc90e54Michael Jurka return mOccupied[x][y]; 291366d72178af91d455700875635473be942bc90e54Michael Jurka } else { 291466d72178af91d455700875635473be942bc90e54Michael Jurka throw new RuntimeException("Position exceeds the bound of this CellLayout"); 291566d72178af91d455700875635473be942bc90e54Michael Jurka } 291666d72178af91d455700875635473be942bc90e54Michael Jurka } 291766d72178af91d455700875635473be942bc90e54Michael Jurka 291831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 291931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) { 292031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return new CellLayout.LayoutParams(getContext(), attrs); 292131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 292231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 292331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 292431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { 292531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return p instanceof CellLayout.LayoutParams; 292631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 292731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 292831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 292931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { 293031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return new CellLayout.LayoutParams(p); 293131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 293231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 2933aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung public static class CellLayoutAnimationController extends LayoutAnimationController { 2934aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung public CellLayoutAnimationController(Animation animation, float delay) { 2935aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung super(animation, delay); 2936aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung } 2937aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 2938aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung @Override 2939aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung protected long getDelayForView(View view) { 2940aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung return (int) (Math.random() * 150); 2941aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung } 2942aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung } 2943aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 294431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public static class LayoutParams extends ViewGroup.MarginLayoutParams { 294531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 294631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Horizontal location of the item in the grid. 294731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 294831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @ViewDebug.ExportedProperty 294931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public int cellX; 295031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 295131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 295231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Vertical location of the item in the grid. 295331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 295431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @ViewDebug.ExportedProperty 295531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public int cellY; 295631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 295731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 2958482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * Temporary horizontal location of the item in the grid during reorder 2959482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen */ 2960482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public int tmpCellX; 2961482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2962482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen /** 2963482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * Temporary vertical location of the item in the grid during reorder 2964482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen */ 2965482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public int tmpCellY; 2966482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2967482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen /** 2968482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * Indicates that the temporary coordinates should be used to layout the items 2969482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen */ 2970482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public boolean useTmpCoords; 2971482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2972482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen /** 297331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Number of cells spanned horizontally by the item. 297431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 297531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @ViewDebug.ExportedProperty 297631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public int cellHSpan; 297731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 297831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 297931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Number of cells spanned vertically by the item. 298031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 298131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @ViewDebug.ExportedProperty 298231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public int cellVSpan; 2983aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 29841b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen /** 29851b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen * Indicates whether the item will set its x, y, width and height parameters freely, 29861b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen * or whether these will be computed based on cellX, cellY, cellHSpan and cellVSpan. 29871b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen */ 2988d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen public boolean isLockedToGrid = true; 2989d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen 2990482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen /** 2991482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * Indicates whether this item can be reordered. Always true except in the case of the 2992482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * the AllApps button. 2993482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen */ 2994482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public boolean canReorder = true; 2995482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 299631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // X coordinate of the view in the layout. 299731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @ViewDebug.ExportedProperty 299831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int x; 299931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // Y coordinate of the view in the layout. 300031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @ViewDebug.ExportedProperty 300131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int y; 300231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 300384f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy boolean dropped; 3004fcb9e7144e58614f5ae0e9b272fb7ce040848c67Romain Guy 300531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public LayoutParams(Context c, AttributeSet attrs) { 300631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project super(c, attrs); 300731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellHSpan = 1; 300831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellVSpan = 1; 300931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 301031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 301131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public LayoutParams(ViewGroup.LayoutParams source) { 301231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project super(source); 301331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellHSpan = 1; 301431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellVSpan = 1; 301531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 3016aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 3017aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung public LayoutParams(LayoutParams source) { 3018aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung super(source); 3019aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung this.cellX = source.cellX; 3020aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung this.cellY = source.cellY; 3021aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung this.cellHSpan = source.cellHSpan; 3022aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung this.cellVSpan = source.cellVSpan; 3023aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung } 3024aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 302531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public LayoutParams(int cellX, int cellY, int cellHSpan, int cellVSpan) { 30268f19cdd62f6e2be05e3890916eabd11317ae1bc2Romain Guy super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); 302731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this.cellX = cellX; 302831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this.cellY = cellY; 302931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this.cellHSpan = cellHSpan; 303031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this.cellVSpan = cellVSpan; 303131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 303231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 30337f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public void setup(int cellWidth, int cellHeight, int widthGap, int heightGap) { 3034d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen if (isLockedToGrid) { 3035d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen final int myCellHSpan = cellHSpan; 3036d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen final int myCellVSpan = cellVSpan; 3037482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int myCellX = useTmpCoords ? tmpCellX : cellX; 3038482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int myCellY = useTmpCoords ? tmpCellY : cellY; 30391b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen 3040d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen width = myCellHSpan * cellWidth + ((myCellHSpan - 1) * widthGap) - 3041d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen leftMargin - rightMargin; 3042d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen height = myCellVSpan * cellHeight + ((myCellVSpan - 1) * heightGap) - 3043d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen topMargin - bottomMargin; 3044eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung x = (int) (myCellX * (cellWidth + widthGap) + leftMargin); 3045eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung y = (int) (myCellY * (cellHeight + heightGap) + topMargin); 3046d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen } 3047d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen } 3048d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen 3049aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung public String toString() { 3050aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung return "(" + this.cellX + ", " + this.cellY + ")"; 3051aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung } 30527f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 30537f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public void setWidth(int width) { 30547f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen this.width = width; 30557f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 30567f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 30577f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public int getWidth() { 30587f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen return width; 30597f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 30607f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 30617f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public void setHeight(int height) { 30627f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen this.height = height; 30637f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 30647f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 30657f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public int getHeight() { 30667f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen return height; 30677f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 30687f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 30697f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public void setX(int x) { 30707f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen this.x = x; 30717f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 30727f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 30737f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public int getX() { 30747f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen return x; 30757f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 30767f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 30777f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public void setY(int y) { 30787f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen this.y = y; 30797f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 30807f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 30817f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public int getY() { 30827f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen return y; 30837f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 308431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 308531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 30860280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // This class stores info for two purposes: 30870280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // 1. When dragging items (mDragInfo in Workspace), we store the View, its cellX & cellY, 30880280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // its spanX, spanY, and the screen it is on 30890280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // 2. When long clicking on an empty cell in a CellLayout, we save information about the 30900280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // cellX and cellY coordinates and which page was clicked. We then set this as a tag on 30910280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // the CellLayout that was long clicked 3092e5fb0f27bca7afb996258a7163c76ca7390d7bffMichael Jurka static final class CellInfo { 309331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project View cell; 3094a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka int cellX = -1; 3095a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka int cellY = -1; 309631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int spanX; 309731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int spanY; 309831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int screen; 30993d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung long container; 310031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 310131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 310231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public String toString() { 3103aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung return "Cell[view=" + (cell == null ? "null" : cell.getClass()) 3104aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung + ", x=" + cellX + ", y=" + cellY + "]"; 310531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 310631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 3107d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka 3108d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka public boolean lastDownOnOccupiedCell() { 3109d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka return mLastDownOnOccupiedCell; 3110d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka } 311131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project} 3112