CellLayout.java revision f3900c287cd92f61863cbecab87d5513e48b7b09
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; 56f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohenimport java.util.Collections; 57f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohenimport java.util.Comparator; 58bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohenimport java.util.HashMap; 59d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohenimport java.util.Stack; 60c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen 61bdb5c5342adc550559fd723af461e53248f2fba8Michael Jurkapublic class CellLayout extends ViewGroup { 62aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung static final String TAG = "CellLayout"; 63aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 642acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen private Launcher mLauncher; 6531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private int mCellWidth; 6631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private int mCellHeight; 67aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 68d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen private int mCountX; 69d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen private int mCountY; 7031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 71234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen private int mOriginalWidthGap; 72234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen private int mOriginalHeightGap; 7331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private int mWidthGap; 7431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private int mHeightGap; 754b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung private int mMaxGap; 76ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen private boolean mScrollingTransformsDirty = false; 7731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 7831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private final Rect mRect = new Rect(); 7931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private final CellInfo mCellInfo = new CellInfo(); 80aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 81de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy // These are temporary variables to prevent having to allocate a new object just to 82de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy // return an (x, y) value from helper functions. Do NOT use them to maintain other state. 830be025d64c1f84138fe430a58875886e66aae767Winson Chung private final int[] mTmpXY = new int[2]; 84de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy private final int[] mTmpPoint = new int[2]; 8569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen int[] mTempLocation = new int[2]; 866569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 8731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project boolean[][] mOccupied; 88482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean[][] mTmpOccupied; 89d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka private boolean mLastDownOnOccupiedCell = false; 9031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 91dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka private OnTouchListener mInterceptTouchListener; 92dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka 9369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen private ArrayList<FolderRingAnimator> mFolderOuterRings = new ArrayList<FolderRingAnimator>(); 94c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen private int[] mFolderLeaveBehindCell = {-1, -1}; 9569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 96b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen private int mForegroundAlpha = 0; 975f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka private float mBackgroundAlpha; 981b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen private float mBackgroundAlphaMultiplier = 1.0f; 99f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen 10033945b21544bc98381df17726a3537c292d8c985Michael Jurka private Drawable mNormalBackground; 10133945b21544bc98381df17726a3537c292d8c985Michael Jurka private Drawable mActiveGlowBackground; 102b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen private Drawable mOverScrollForegroundDrawable; 103b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen private Drawable mOverScrollLeft; 104b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen private Drawable mOverScrollRight; 10518014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka private Rect mBackgroundRect; 106b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen private Rect mForegroundRect; 107b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen private int mForegroundPadding; 10833945b21544bc98381df17726a3537c292d8c985Michael Jurka 10933945b21544bc98381df17726a3537c292d8c985Michael Jurka // If we're actively dragging something over this screen, mIsDragOverlapping is true 11033945b21544bc98381df17726a3537c292d8c985Michael Jurka private boolean mIsDragOverlapping = false; 111de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy private final Point mDragCenter = new Point(); 1126569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 113150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung // These arrays are used to implement the drag visualization on x-large screens. 1144be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // They are used as circular arrays, indexed by mDragOutlineCurrent. 115d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen private Rect[] mDragOutlines = new Rect[4]; 116472b281d5cb4f5660df981a6c912266b9f5703feChet Haase private float[] mDragOutlineAlphas = new float[mDragOutlines.length]; 1174be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato private InterruptibleInOutAnimator[] mDragOutlineAnims = 1184be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato new InterruptibleInOutAnimator[mDragOutlines.length]; 119150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung 120150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung // Used as an index into the above 3 arrays; indicates which is the most current value. 1214be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato private int mDragOutlineCurrent = 0; 1228e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy private final Paint mDragOutlinePaint = new Paint(); 123150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung 12496864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy private BubbleTextView mPressedOrFocusedIcon; 12596864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy 126482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private HashMap<CellLayout.LayoutParams, Animator> mReorderAnimators = new 127482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen HashMap<CellLayout.LayoutParams, Animator>(); 12819f3792523fe2d55ea791a9286398a6120920690Adam Cohen private HashMap<View, ReorderHintAnimation> 12919f3792523fe2d55ea791a9286398a6120920690Adam Cohen mShakeAnimators = new HashMap<View, ReorderHintAnimation>(); 13019f3792523fe2d55ea791a9286398a6120920690Adam Cohen 13119f3792523fe2d55ea791a9286398a6120920690Adam Cohen private boolean mItemPlacementDirty = false; 132bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen 1336569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy // When a drag operation is in progress, holds the nearest cell to the touch point 1346569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy private final int[] mDragCell = new int[2]; 13531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 1364be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato private boolean mDragging = false; 1374be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato 138ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy private TimeInterpolator mEaseOutInterpolator; 139a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka private ShortcutAndWidgetContainer mShortcutsAndWidgets; 140ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy 1410dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn private boolean mIsHotseat = false; 142307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen private float mHotseatScale = 1f; 1430dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn 144482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public static final int MODE_DRAG_OVER = 0; 145482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public static final int MODE_ON_DROP = 1; 146482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public static final int MODE_ON_DROP_EXTERNAL = 2; 147482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public static final int MODE_ACCEPT_DROP = 3; 14819f3792523fe2d55ea791a9286398a6120920690Adam Cohen private static final boolean DESTRUCTIVE_REORDER = false; 149482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private static final boolean DEBUG_VISUALIZE_OCCUPIED = false; 150482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 151a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen static final int LANDSCAPE = 0; 152a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen static final int PORTRAIT = 1; 153a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen 1547bdfc9700b1cad043c04c757f134db1bf3df00daAdam Cohen private static final float REORDER_HINT_MAGNITUDE = 0.12f; 15519f3792523fe2d55ea791a9286398a6120920690Adam Cohen private static final int REORDER_ANIMATION_DURATION = 150; 15619f3792523fe2d55ea791a9286398a6120920690Adam Cohen private float mReorderHintAnimationMagnitude; 15719f3792523fe2d55ea791a9286398a6120920690Adam Cohen 158482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private ArrayList<View> mIntersectingViews = new ArrayList<View>(); 159482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private Rect mOccupiedRect = new Rect(); 160482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private int[] mDirectionVector = new int[2]; 16119f3792523fe2d55ea791a9286398a6120920690Adam Cohen int[] mPreviousReorderDirection = new int[2]; 162b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen private static final int INVALID_DIRECTION = -100; 163c6cc61d45836e4081920883cc4d448ccb0bb8417Adam Cohen private DropTarget.DragEnforcer mDragEnforcer; 164482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1658a0bff5e35f63321178bbf777ec24d42544866b3Romain Guy private final static PorterDuffXfermode sAddBlendMode = 1668a0bff5e35f63321178bbf777ec24d42544866b3Romain Guy new PorterDuffXfermode(PorterDuff.Mode.ADD); 167ca99383daef92fed673de22126875cb485be494fMichael Jurka private final static Paint sPaint = new Paint(); 1688a0bff5e35f63321178bbf777ec24d42544866b3Romain Guy 16931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public CellLayout(Context context) { 17031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this(context, null); 17131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 17231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 17331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public CellLayout(Context context, AttributeSet attrs) { 17431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this(context, attrs, 0); 17531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 17631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 17731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public CellLayout(Context context, AttributeSet attrs, int defStyle) { 17831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project super(context, attrs, defStyle); 1798b805b17158886035b38261eb611d8641701ae43Michael Jurka mDragEnforcer = new DropTarget.DragEnforcer(context); 1806569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 1816569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy // A ViewGroup usually does not draw, but CellLayout needs to draw a rectangle to show 1826569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy // the user where a dragged item will land when dropped. 1836569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy setWillNotDraw(false); 1842acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen mLauncher = (Launcher) context; 185a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka 18631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CellLayout, defStyle, 0); 18731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 188f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen mCellWidth = a.getDimensionPixelSize(R.styleable.CellLayout_cellWidth, 10); 189f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen mCellHeight = a.getDimensionPixelSize(R.styleable.CellLayout_cellHeight, 10); 190234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen mWidthGap = mOriginalWidthGap = a.getDimensionPixelSize(R.styleable.CellLayout_widthGap, 0); 191234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen mHeightGap = mOriginalHeightGap = a.getDimensionPixelSize(R.styleable.CellLayout_heightGap, 0); 1924b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung mMaxGap = a.getDimensionPixelSize(R.styleable.CellLayout_maxGap, 0); 193d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen mCountX = LauncherModel.getCellCountX(); 194d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen mCountY = LauncherModel.getCellCountY(); 1950280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka mOccupied = new boolean[mCountX][mCountY]; 196482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mTmpOccupied = new boolean[mCountX][mCountY]; 1975b53f29f809a0dad4a1e0717ba610ce737ee0f43Adam Cohen mPreviousReorderDirection[0] = INVALID_DIRECTION; 1985b53f29f809a0dad4a1e0717ba610ce737ee0f43Adam Cohen mPreviousReorderDirection[1] = INVALID_DIRECTION; 19931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 20031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project a.recycle(); 20131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 20231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project setAlwaysDrawnWithCacheEnabled(false); 20331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 204046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy final Resources res = getResources(); 205307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen mHotseatScale = (res.getInteger(R.integer.hotseat_item_scale_percentage) / 100f); 206de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy 207967289b6d5fec77f5c381d11ffb2319f3bb5e737Winson Chung mNormalBackground = res.getDrawable(R.drawable.homescreen_blue_normal_holo); 208dea74b7d12b0fcd50bfdb4274f9867ba76d75238Winson Chung mActiveGlowBackground = res.getDrawable(R.drawable.homescreen_blue_strong_holo); 209b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung 210b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mOverScrollLeft = res.getDrawable(R.drawable.overscroll_glow_left); 211b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mOverScrollRight = res.getDrawable(R.drawable.overscroll_glow_right); 212b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mForegroundPadding = 213b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen res.getDimensionPixelSize(R.dimen.workspace_overscroll_drawable_padding); 214b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung 21519f3792523fe2d55ea791a9286398a6120920690Adam Cohen mReorderHintAnimationMagnitude = (REORDER_HINT_MAGNITUDE * 21619f3792523fe2d55ea791a9286398a6120920690Adam Cohen res.getDimensionPixelSize(R.dimen.app_icon_size)); 21719f3792523fe2d55ea791a9286398a6120920690Adam Cohen 218b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung mNormalBackground.setFilterBitmap(true); 219b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung mActiveGlowBackground.setFilterBitmap(true); 220de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy 221046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy // Initialize the data structures used for the drag visualization. 222150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung 223ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy mEaseOutInterpolator = new DecelerateInterpolator(2.5f); // Quint ease out 224de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy 225046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy 226b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung mDragCell[0] = mDragCell[1] = -1; 2274be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato for (int i = 0; i < mDragOutlines.length; i++) { 228d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen mDragOutlines[i] = new Rect(-1, -1, -1, -1); 229046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy } 230046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy 231046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy // When dragging things around the home screens, we show a green outline of 232046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy // where the item will land. The outlines gradually fade out, leaving a trail 233046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy // behind the drag path. 234046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy // Set up all the animations that are used to implement this fading. 235046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy final int duration = res.getInteger(R.integer.config_dragOutlineFadeTime); 236472b281d5cb4f5660df981a6c912266b9f5703feChet Haase final float fromAlphaValue = 0; 237472b281d5cb4f5660df981a6c912266b9f5703feChet Haase final float toAlphaValue = (float)res.getInteger(R.integer.config_dragOutlineMaxAlpha); 2384be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato 2398e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy Arrays.fill(mDragOutlineAlphas, fromAlphaValue); 2404be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato 2414be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato for (int i = 0; i < mDragOutlineAnims.length; i++) { 242046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy final InterruptibleInOutAnimator anim = 243046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy new InterruptibleInOutAnimator(duration, fromAlphaValue, toAlphaValue); 244ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy anim.getAnimator().setInterpolator(mEaseOutInterpolator); 245046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy final int thisIndex = i; 246472b281d5cb4f5660df981a6c912266b9f5703feChet Haase anim.getAnimator().addUpdateListener(new AnimatorUpdateListener() { 247de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy public void onAnimationUpdate(ValueAnimator animation) { 2484be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato final Bitmap outline = (Bitmap)anim.getTag(); 2494be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato 2504be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // If an animation is started and then stopped very quickly, we can still 2514be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // get spurious updates we've cleared the tag. Guard against this. 2524be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato if (outline == null) { 2533a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka @SuppressWarnings("all") // suppress dead code warning 2543a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka final boolean debug = false; 2553a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka if (debug) { 256fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy Object val = animation.getAnimatedValue(); 257fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy Log.d(TAG, "anim " + thisIndex + " update: " + val + 258fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy ", isStopped " + anim.isStopped()); 259fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy } 2604be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // Try to prevent it from continuing to run 2614be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato animation.cancel(); 2624be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato } else { 263472b281d5cb4f5660df981a6c912266b9f5703feChet Haase mDragOutlineAlphas[thisIndex] = (Float) animation.getAnimatedValue(); 264d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen CellLayout.this.invalidate(mDragOutlines[thisIndex]); 2654be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato } 266de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy } 267de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy }); 2684be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // The animation holds a reference to the drag outline bitmap as long is it's 2694be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // running. This way the bitmap can be GCed when the animations are complete. 270472b281d5cb4f5660df981a6c912266b9f5703feChet Haase anim.getAnimator().addListener(new AnimatorListenerAdapter() { 2713c4c20fbe682cb4b3ef94f09afe0af09171583f3Michael Jurka @Override 2724be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato public void onAnimationEnd(Animator animation) { 273472b281d5cb4f5660df981a6c912266b9f5703feChet Haase if ((Float) ((ValueAnimator) animation).getAnimatedValue() == 0f) { 2744be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato anim.setTag(null); 2754be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato } 2764be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato } 2774be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato }); 2784be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato mDragOutlineAnims[i] = anim; 279de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy } 280ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy 28118014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka mBackgroundRect = new Rect(); 282b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mForegroundRect = new Rect(); 283bea15195346bab3c52b0156e92f2b71f0811b210Michael Jurka 284a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets = new ShortcutAndWidgetContainer(context); 285a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.setCellDimensions(mCellWidth, mCellHeight, mWidthGap, mHeightGap); 286a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka addView(mShortcutsAndWidgets); 28718014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka } 28818014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka 289f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka static int widthInPortrait(Resources r, int numCells) { 290f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka // We use this method from Workspace to figure out how many rows/columns Launcher should 291f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka // have. We ignore the left/right padding on CellLayout because it turns out in our design 292f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka // the padding extends outside the visible screen size, but it looked fine anyway. 293f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka int cellWidth = r.getDimensionPixelSize(R.dimen.workspace_cell_width); 2944b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung int minGap = Math.min(r.getDimensionPixelSize(R.dimen.workspace_width_gap), 2954b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung r.getDimensionPixelSize(R.dimen.workspace_height_gap)); 296f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka 2974b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung return minGap * (numCells - 1) + cellWidth * numCells; 298f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka } 299f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka 300f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka static int heightInLandscape(Resources r, int numCells) { 301f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka // We use this method from Workspace to figure out how many rows/columns Launcher should 302f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka // have. We ignore the left/right padding on CellLayout because it turns out in our design 303f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka // the padding extends outside the visible screen size, but it looked fine anyway. 304f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka int cellHeight = r.getDimensionPixelSize(R.dimen.workspace_cell_height); 3054b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung int minGap = Math.min(r.getDimensionPixelSize(R.dimen.workspace_width_gap), 3064b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung r.getDimensionPixelSize(R.dimen.workspace_height_gap)); 307f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka 3084b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung return minGap * (numCells - 1) + cellHeight * numCells; 309f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka } 310f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka 3112801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen public void enableHardwareLayers() { 312ca99383daef92fed673de22126875cb485be494fMichael Jurka mShortcutsAndWidgets.setLayerType(LAYER_TYPE_HARDWARE, sPaint); 313d51f33a6316c34fc69b8040946ed9a62519bb225Michael Jurka } 314d51f33a6316c34fc69b8040946ed9a62519bb225Michael Jurka 315d51f33a6316c34fc69b8040946ed9a62519bb225Michael Jurka public void disableHardwareLayers() { 316ca99383daef92fed673de22126875cb485be494fMichael Jurka mShortcutsAndWidgets.setLayerType(LAYER_TYPE_NONE, sPaint); 317d51f33a6316c34fc69b8040946ed9a62519bb225Michael Jurka } 318d51f33a6316c34fc69b8040946ed9a62519bb225Michael Jurka 319d51f33a6316c34fc69b8040946ed9a62519bb225Michael Jurka public void buildHardwareLayer() { 320d51f33a6316c34fc69b8040946ed9a62519bb225Michael Jurka mShortcutsAndWidgets.buildLayer(); 3212801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen } 3222801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen 323307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen public float getChildrenScale() { 324307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen return mIsHotseat ? mHotseatScale : 1.0f; 325307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen } 326307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen 3272801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen public void setGridSize(int x, int y) { 3282801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen mCountX = x; 3292801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen mCountY = y; 3302801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen mOccupied = new boolean[mCountX][mCountY]; 331482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mTmpOccupied = new boolean[mCountX][mCountY]; 3327fbec10b36818f100b631f3d73fe1ad5360975aaAdam Cohen mTempRectStack.clear(); 33376fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen requestLayout(); 3342801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen } 3352801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen 33696864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy private void invalidateBubbleTextView(BubbleTextView icon) { 33796864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy final int padding = icon.getPressedOrFocusedBackgroundPadding(); 3384b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung invalidate(icon.getLeft() + getPaddingLeft() - padding, 3394b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung icon.getTop() + getPaddingTop() - padding, 3404b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung icon.getRight() + getPaddingLeft() + padding, 3414b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung icon.getBottom() + getPaddingTop() + padding); 34296864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy } 34396864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy 344b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen void setOverScrollAmount(float r, boolean left) { 345b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen if (left && mOverScrollForegroundDrawable != mOverScrollLeft) { 346b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mOverScrollForegroundDrawable = mOverScrollLeft; 347b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen } else if (!left && mOverScrollForegroundDrawable != mOverScrollRight) { 348b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mOverScrollForegroundDrawable = mOverScrollRight; 349b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen } 350b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen 351b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mForegroundAlpha = (int) Math.round((r * 255)); 352b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mOverScrollForegroundDrawable.setAlpha(mForegroundAlpha); 353b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen invalidate(); 354b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen } 355b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen 35696864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy void setPressedOrFocusedIcon(BubbleTextView icon) { 35796864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy // We draw the pressed or focused BubbleTextView's background in CellLayout because it 35896864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy // requires an expanded clip rect (due to the glow's blur radius) 35996864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy BubbleTextView oldIcon = mPressedOrFocusedIcon; 36096864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy mPressedOrFocusedIcon = icon; 36196864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy if (oldIcon != null) { 36296864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy invalidateBubbleTextView(oldIcon); 36396864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy } 36496864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy if (mPressedOrFocusedIcon != null) { 36596864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy invalidateBubbleTextView(mPressedOrFocusedIcon); 36696864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy } 36796864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy } 36896864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy 36933945b21544bc98381df17726a3537c292d8c985Michael Jurka void setIsDragOverlapping(boolean isDragOverlapping) { 37033945b21544bc98381df17726a3537c292d8c985Michael Jurka if (mIsDragOverlapping != isDragOverlapping) { 37133945b21544bc98381df17726a3537c292d8c985Michael Jurka mIsDragOverlapping = isDragOverlapping; 37233945b21544bc98381df17726a3537c292d8c985Michael Jurka invalidate(); 37333945b21544bc98381df17726a3537c292d8c985Michael Jurka } 37433945b21544bc98381df17726a3537c292d8c985Michael Jurka } 37533945b21544bc98381df17726a3537c292d8c985Michael Jurka 37633945b21544bc98381df17726a3537c292d8c985Michael Jurka boolean getIsDragOverlapping() { 37733945b21544bc98381df17726a3537c292d8c985Michael Jurka return mIsDragOverlapping; 37833945b21544bc98381df17726a3537c292d8c985Michael Jurka } 37933945b21544bc98381df17726a3537c292d8c985Michael Jurka 380ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen protected void setOverscrollTransformsDirty(boolean dirty) { 381ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen mScrollingTransformsDirty = dirty; 382ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen } 383ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen 384ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen protected void resetOverscrollTransforms() { 385ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen if (mScrollingTransformsDirty) { 386ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen setOverscrollTransformsDirty(false); 387ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen setTranslationX(0); 388ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen setRotationY(0); 389ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen // It doesn't matter if we pass true or false here, the important thing is that we 390ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen // pass 0, which results in the overscroll drawable not being drawn any more. 391ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen setOverScrollAmount(0, false); 392ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen setPivotX(getMeasuredWidth() / 2); 393ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen setPivotY(getMeasuredHeight() / 2); 394ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen } 395ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen } 396ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen 397307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen public void scaleRect(Rect r, float scale) { 398307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen if (scale != 1.0f) { 399307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen r.left = (int) (r.left * scale + 0.5f); 400307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen r.top = (int) (r.top * scale + 0.5f); 401307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen r.right = (int) (r.right * scale + 0.5f); 402307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen r.bottom = (int) (r.bottom * scale + 0.5f); 403307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen } 404307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen } 405307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen 406307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen Rect temp = new Rect(); 407307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen void scaleRectAboutCenter(Rect in, Rect out, float scale) { 408307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen int cx = in.centerX(); 409307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen int cy = in.centerY(); 410307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen out.set(in); 411307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen out.offset(-cx, -cy); 412307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen scaleRect(out, scale); 413307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen out.offset(cx, cy); 414307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen } 415307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen 416a6abce8464b57ce91e8f083951ad263370fc2da8Romain Guy @Override 4171262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy protected void onDraw(Canvas canvas) { 4183e7c7634531302271270c8cf418abc959d621cbcMichael Jurka // When we're large, we are either drawn in a "hover" state (ie when dragging an item to 4193e7c7634531302271270c8cf418abc959d621cbcMichael Jurka // a neighboring page) or with just a normal background (if backgroundAlpha > 0.0f) 4203e7c7634531302271270c8cf418abc959d621cbcMichael Jurka // When we're small, we are either drawn normally or in the "accepts drops" state (during 4213e7c7634531302271270c8cf418abc959d621cbcMichael Jurka // a drag). However, we also drag the mini hover background *over* one of those two 4223e7c7634531302271270c8cf418abc959d621cbcMichael Jurka // backgrounds 423b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung if (mBackgroundAlpha > 0.0f) { 424f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen Drawable bg; 42533945b21544bc98381df17726a3537c292d8c985Michael Jurka 42633945b21544bc98381df17726a3537c292d8c985Michael Jurka if (mIsDragOverlapping) { 42733945b21544bc98381df17726a3537c292d8c985Michael Jurka // In the mini case, we draw the active_glow bg *over* the active background 428bdf78559f223ac11e01e3311edd5a48a80383e1eMichael Jurka bg = mActiveGlowBackground; 429f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen } else { 430bdf78559f223ac11e01e3311edd5a48a80383e1eMichael Jurka bg = mNormalBackground; 431f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen } 43233945b21544bc98381df17726a3537c292d8c985Michael Jurka 43333945b21544bc98381df17726a3537c292d8c985Michael Jurka bg.setAlpha((int) (mBackgroundAlpha * mBackgroundAlphaMultiplier * 255)); 43433945b21544bc98381df17726a3537c292d8c985Michael Jurka bg.setBounds(mBackgroundRect); 43533945b21544bc98381df17726a3537c292d8c985Michael Jurka bg.draw(canvas); 436a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka } 43731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 4388e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy final Paint paint = mDragOutlinePaint; 4394be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato for (int i = 0; i < mDragOutlines.length; i++) { 440472b281d5cb4f5660df981a6c912266b9f5703feChet Haase final float alpha = mDragOutlineAlphas[i]; 4414be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato if (alpha > 0) { 442d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen final Rect r = mDragOutlines[i]; 443307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen scaleRectAboutCenter(r, temp, getChildrenScale()); 4444be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato final Bitmap b = (Bitmap) mDragOutlineAnims[i].getTag(); 445472b281d5cb4f5660df981a6c912266b9f5703feChet Haase paint.setAlpha((int)(alpha + .5f)); 446307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen canvas.drawBitmap(b, null, temp, paint); 447150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung } 4486569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy } 44996864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy 45096864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy // We draw the pressed or focused BubbleTextView's background in CellLayout because it 45196864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy // requires an expanded clip rect (due to the glow's blur radius) 45296864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy if (mPressedOrFocusedIcon != null) { 45396864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy final int padding = mPressedOrFocusedIcon.getPressedOrFocusedBackgroundPadding(); 45496864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy final Bitmap b = mPressedOrFocusedIcon.getPressedOrFocusedBackground(); 45596864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy if (b != null) { 45696864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy canvas.drawBitmap(b, 4574b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung mPressedOrFocusedIcon.getLeft() + getPaddingLeft() - padding, 4584b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung mPressedOrFocusedIcon.getTop() + getPaddingTop() - padding, 45996864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy null); 46096864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy } 46196864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy } 46269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 463482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (DEBUG_VISUALIZE_OCCUPIED) { 464482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int[] pt = new int[2]; 465482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen ColorDrawable cd = new ColorDrawable(Color.RED); 466e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen cd.setBounds(0, 0, mCellWidth, mCellHeight); 467482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < mCountX; i++) { 468482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int j = 0; j < mCountY; j++) { 469482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (mOccupied[i][j]) { 470482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen cellToPoint(i, j, pt); 471482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen canvas.save(); 472482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen canvas.translate(pt[0], pt[1]); 473482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen cd.draw(canvas); 474482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen canvas.restore(); 475482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 476482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 477482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 478482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 479482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 480850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn int previewOffset = FolderRingAnimator.sPreviewSize; 481850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn 48269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen // The folder outer / inner ring image(s) 48369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen for (int i = 0; i < mFolderOuterRings.size(); i++) { 48469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen FolderRingAnimator fra = mFolderOuterRings.get(i); 48569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 48669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen // Draw outer ring 48769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen Drawable d = FolderRingAnimator.sSharedOuterRingDrawable; 48869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen int width = (int) fra.getOuterRingSize(); 48969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen int height = width; 49069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen cellToPoint(fra.mCellX, fra.mCellY, mTempLocation); 49169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 49269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen int centerX = mTempLocation[0] + mCellWidth / 2; 493850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn int centerY = mTempLocation[1] + previewOffset / 2; 49469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 49569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen canvas.save(); 49669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen canvas.translate(centerX - width / 2, centerY - height / 2); 49769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen d.setBounds(0, 0, width, height); 49869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen d.draw(canvas); 49969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen canvas.restore(); 50069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 50169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen // Draw inner ring 50269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen d = FolderRingAnimator.sSharedInnerRingDrawable; 50369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen width = (int) fra.getInnerRingSize(); 50469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen height = width; 50569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen cellToPoint(fra.mCellX, fra.mCellY, mTempLocation); 50669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 50769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen centerX = mTempLocation[0] + mCellWidth / 2; 508850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn centerY = mTempLocation[1] + previewOffset / 2; 50969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen canvas.save(); 51069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen canvas.translate(centerX - width / 2, centerY - width / 2); 51169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen d.setBounds(0, 0, width, height); 51269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen d.draw(canvas); 51369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen canvas.restore(); 51469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen } 515c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen 516c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen if (mFolderLeaveBehindCell[0] >= 0 && mFolderLeaveBehindCell[1] >= 0) { 517c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen Drawable d = FolderIcon.sSharedFolderLeaveBehind; 518c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen int width = d.getIntrinsicWidth(); 519c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen int height = d.getIntrinsicHeight(); 520c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen 521c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen cellToPoint(mFolderLeaveBehindCell[0], mFolderLeaveBehindCell[1], mTempLocation); 522c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen int centerX = mTempLocation[0] + mCellWidth / 2; 523850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn int centerY = mTempLocation[1] + previewOffset / 2; 524c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen 525c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen canvas.save(); 526c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen canvas.translate(centerX - width / 2, centerY - width / 2); 527c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen d.setBounds(0, 0, width, height); 528c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen d.draw(canvas); 529c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen canvas.restore(); 530c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen } 53169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen } 53269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 533b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen @Override 534b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen protected void dispatchDraw(Canvas canvas) { 535b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen super.dispatchDraw(canvas); 536b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen if (mForegroundAlpha > 0) { 537b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mOverScrollForegroundDrawable.setBounds(mForegroundRect); 538b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen Paint p = ((NinePatchDrawable) mOverScrollForegroundDrawable).getPaint(); 5398a0bff5e35f63321178bbf777ec24d42544866b3Romain Guy p.setXfermode(sAddBlendMode); 540b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mOverScrollForegroundDrawable.draw(canvas); 541b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen p.setXfermode(null); 542b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen } 543b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen } 544b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen 54569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen public void showFolderAccept(FolderRingAnimator fra) { 54669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen mFolderOuterRings.add(fra); 54769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen } 54869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 54969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen public void hideFolderAccept(FolderRingAnimator fra) { 55069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen if (mFolderOuterRings.contains(fra)) { 55169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen mFolderOuterRings.remove(fra); 55269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen } 55369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen invalidate(); 5546569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy } 5556569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 556c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen public void setFolderLeaveBehindCell(int x, int y) { 557c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen mFolderLeaveBehindCell[0] = x; 558c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen mFolderLeaveBehindCell[1] = y; 559c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen invalidate(); 560c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen } 561c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen 562c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen public void clearFolderLeaveBehind() { 563c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen mFolderLeaveBehindCell[0] = -1; 564c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen mFolderLeaveBehindCell[1] = -1; 565c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen invalidate(); 566c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen } 567c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen 5686569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy @Override 569e6235dd225404239b55c459245543f3302326112Michael Jurka public boolean shouldDelayChildPressedState() { 570e6235dd225404239b55c459245543f3302326112Michael Jurka return false; 571e6235dd225404239b55c459245543f3302326112Michael Jurka } 572e6235dd225404239b55c459245543f3302326112Michael Jurka 5731462de39f01cec0ba785386532719cb0207dd827Adam Cohen public void restoreInstanceState(SparseArray<Parcelable> states) { 5741462de39f01cec0ba785386532719cb0207dd827Adam Cohen dispatchRestoreInstanceState(states); 5751462de39f01cec0ba785386532719cb0207dd827Adam Cohen } 5761462de39f01cec0ba785386532719cb0207dd827Adam Cohen 577e6235dd225404239b55c459245543f3302326112Michael Jurka @Override 57883f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey public void cancelLongPress() { 57983f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey super.cancelLongPress(); 58083f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey 58183f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey // Cancel long press for all children 58283f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey final int count = getChildCount(); 58383f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey for (int i = 0; i < count; i++) { 58483f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey final View child = getChildAt(i); 58583f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey child.cancelLongPress(); 58683f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey } 58783f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey } 58883f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey 589dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka public void setOnInterceptTouchListener(View.OnTouchListener listener) { 590dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka mInterceptTouchListener = listener; 591dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } 592dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka 59331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int getCountX() { 594d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen return mCountX; 59531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 59631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 59731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int getCountY() { 598d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen return mCountY; 59931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 60031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 6010dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn public void setIsHotseat(boolean isHotseat) { 6020dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn mIsHotseat = isHotseat; 6030dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn } 6040dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn 6050dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn public boolean addViewToCellLayout(View child, int index, int childId, LayoutParams params, 606850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn boolean markCells) { 607aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung final LayoutParams lp = params; 608aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 609de38e42fe89fd7490221427908cd97c51da21b44Andrew Flynn // Hotseat icons - remove text 6100dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn if (child instanceof BubbleTextView) { 6110dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn BubbleTextView bubbleChild = (BubbleTextView) child; 6120dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn 613de38e42fe89fd7490221427908cd97c51da21b44Andrew Flynn Resources res = getResources(); 614de38e42fe89fd7490221427908cd97c51da21b44Andrew Flynn if (mIsHotseat) { 615de38e42fe89fd7490221427908cd97c51da21b44Andrew Flynn bubbleChild.setTextColor(res.getColor(android.R.color.transparent)); 616de38e42fe89fd7490221427908cd97c51da21b44Andrew Flynn } else { 617de38e42fe89fd7490221427908cd97c51da21b44Andrew Flynn bubbleChild.setTextColor(res.getColor(R.color.workspace_icon_text_color)); 6180dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn } 6190dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn } 6200dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn 621307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen child.setScaleX(getChildrenScale()); 622307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen child.setScaleY(getChildrenScale()); 623307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen 62431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // Generate an id for each view, this assumes we have at most 256x256 cells 62531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // per workspace screen 626d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen if (lp.cellX >= 0 && lp.cellX <= mCountX - 1 && lp.cellY >= 0 && lp.cellY <= mCountY - 1) { 627aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung // If the horizontal or vertical span is set to -1, it is taken to 628aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung // mean that it spans the extent of the CellLayout 629d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen if (lp.cellHSpan < 0) lp.cellHSpan = mCountX; 630d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen if (lp.cellVSpan < 0) lp.cellVSpan = mCountY; 631aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 632aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung child.setId(childId); 63331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 634a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.addView(child, index, lp); 635dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka 636f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka if (markCells) markCellsAsOccupiedForView(child); 6370280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 638aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung return true; 639aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung } 640aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung return false; 64131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 6423e7c7634531302271270c8cf418abc959d621cbcMichael Jurka 64331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 6440280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka public void removeAllViews() { 6450280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka clearOccupiedCells(); 646a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.removeAllViews(); 6470280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 6480280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 6490280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka @Override 6500280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka public void removeAllViewsInLayout() { 651a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka if (mShortcutsAndWidgets.getChildCount() > 0) { 6527cfc2825c3a1029f962d2fc387ae2eaa85b51798Michael Jurka clearOccupiedCells(); 653a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.removeAllViewsInLayout(); 6547cfc2825c3a1029f962d2fc387ae2eaa85b51798Michael Jurka } 6550280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 6560280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 657f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka public void removeViewWithoutMarkingCells(View view) { 658a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.removeView(view); 659f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka } 660f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka 6610280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka @Override 6620280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka public void removeView(View view) { 6630280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka markCellsAsUnoccupiedForView(view); 664a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.removeView(view); 6650280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 6660280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 6670280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka @Override 6680280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka public void removeViewAt(int index) { 669a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka markCellsAsUnoccupiedForView(mShortcutsAndWidgets.getChildAt(index)); 670a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.removeViewAt(index); 6710280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 6720280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 6730280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka @Override 6740280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka public void removeViewInLayout(View view) { 6750280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka markCellsAsUnoccupiedForView(view); 676a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.removeViewInLayout(view); 6770280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 6780280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 6790280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka @Override 6800280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka public void removeViews(int start, int count) { 6810280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka for (int i = start; i < start + count; i++) { 682a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka markCellsAsUnoccupiedForView(mShortcutsAndWidgets.getChildAt(i)); 6830280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 684a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.removeViews(start, count); 6850280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 6860280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 6870280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka @Override 6880280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka public void removeViewsInLayout(int start, int count) { 6890280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka for (int i = start; i < start + count; i++) { 690a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka markCellsAsUnoccupiedForView(mShortcutsAndWidgets.getChildAt(i)); 6910280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 692a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.removeViewsInLayout(start, count); 693abded66084680bb31cc7ea403c88f44f79a3c884Michael Jurka } 694abded66084680bb31cc7ea403c88f44f79a3c884Michael Jurka 69531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 69631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected void onAttachedToWindow() { 69731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project super.onAttachedToWindow(); 69831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mCellInfo.screen = ((ViewGroup) getParent()).indexOfChild(this); 69931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 70031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 701af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka public void setTagToCellInfoForPoint(int touchX, int touchY) { 70231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final CellInfo cellInfo = mCellInfo; 703eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung Rect frame = mRect; 7048b805b17158886035b38261eb611d8641701ae43Michael Jurka final int x = touchX + getScrollX(); 7058b805b17158886035b38261eb611d8641701ae43Michael Jurka final int y = touchY + getScrollY(); 706a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka final int count = mShortcutsAndWidgets.getChildCount(); 70731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 708af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka boolean found = false; 709af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka for (int i = count - 1; i >= 0; i--) { 710a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka final View child = mShortcutsAndWidgets.getChildAt(i); 711d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 712af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka 7131b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen if ((child.getVisibility() == VISIBLE || child.getAnimation() != null) && 7141b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen lp.isLockedToGrid) { 715af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka child.getHitRect(frame); 7160be025d64c1f84138fe430a58875886e66aae767Winson Chung 717eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung float scale = child.getScaleX(); 718eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung frame = new Rect(child.getLeft(), child.getTop(), child.getRight(), 719eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung child.getBottom()); 7200be025d64c1f84138fe430a58875886e66aae767Winson Chung // The child hit rect is relative to the CellLayoutChildren parent, so we need to 7210be025d64c1f84138fe430a58875886e66aae767Winson Chung // offset that by this CellLayout's padding to test an (x,y) point that is relative 7220be025d64c1f84138fe430a58875886e66aae767Winson Chung // to this view. 7238b805b17158886035b38261eb611d8641701ae43Michael Jurka frame.offset(getPaddingLeft(), getPaddingTop()); 724eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung frame.inset((int) (frame.width() * (1f - scale) / 2), 725eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung (int) (frame.height() * (1f - scale) / 2)); 7260be025d64c1f84138fe430a58875886e66aae767Winson Chung 727af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka if (frame.contains(x, y)) { 728af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.cell = child; 729af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.cellX = lp.cellX; 730af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.cellY = lp.cellY; 731af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.spanX = lp.cellHSpan; 732af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.spanY = lp.cellVSpan; 733af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka found = true; 734af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka break; 73531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 73631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 737af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka } 738aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 739d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka mLastDownOnOccupiedCell = found; 740d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka 741af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka if (!found) { 7420be025d64c1f84138fe430a58875886e66aae767Winson Chung final int cellXY[] = mTmpXY; 743af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka pointToCellExact(x, y, cellXY); 74431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 745af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.cell = null; 746af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.cellX = cellXY[0]; 747af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.cellY = cellXY[1]; 748af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.spanX = 1; 749af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.spanY = 1; 750af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka } 751af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka setTag(cellInfo); 752af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka } 75331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 754af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka @Override 755af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka public boolean onInterceptTouchEvent(MotionEvent ev) { 756c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen // First we clear the tag to ensure that on every touch down we start with a fresh slate, 757c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen // even in the case where we return early. Not clearing here was causing bugs whereby on 758c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen // long-press we'd end up picking up an item from a previous drag operation. 759c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen final int action = ev.getAction(); 760c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen 761c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen if (action == MotionEvent.ACTION_DOWN) { 762c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen clearTagCellInfo(); 763c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen } 764c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen 765dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka if (mInterceptTouchListener != null && mInterceptTouchListener.onTouch(this, ev)) { 766dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka return true; 767dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } 76831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 769af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka if (action == MotionEvent.ACTION_DOWN) { 770af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka setTagToCellInfoForPoint((int) ev.getX(), (int) ev.getY()); 77131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 772eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung 77331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return false; 77431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 77531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 776c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen private void clearTagCellInfo() { 777c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen final CellInfo cellInfo = mCellInfo; 778c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen cellInfo.cell = null; 779c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen cellInfo.cellX = -1; 780c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen cellInfo.cellY = -1; 781c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen cellInfo.spanX = 0; 782c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen cellInfo.spanY = 0; 783c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen setTag(cellInfo); 784c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen } 785c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen 78631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public CellInfo getTag() { 7870280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka return (CellInfo) super.getTag(); 78831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 78931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 7906569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy /** 791aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * Given a point, return the cell that strictly encloses that point 79231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param x X coordinate of the point 79331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param y Y coordinate of the point 79431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param result Array of 2 ints to hold the x and y coordinate of the cell 79531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 79631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project void pointToCellExact(int x, int y, int[] result) { 7974b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung final int hStartPadding = getPaddingLeft(); 7984b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung final int vStartPadding = getPaddingTop(); 79931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 80031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project result[0] = (x - hStartPadding) / (mCellWidth + mWidthGap); 80131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project result[1] = (y - vStartPadding) / (mCellHeight + mHeightGap); 80231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 803d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen final int xAxis = mCountX; 804d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen final int yAxis = mCountY; 80531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 80631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (result[0] < 0) result[0] = 0; 80731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (result[0] >= xAxis) result[0] = xAxis - 1; 80831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (result[1] < 0) result[1] = 0; 80931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (result[1] >= yAxis) result[1] = yAxis - 1; 81031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 811aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 81231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 81331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Given a point, return the cell that most closely encloses that point 81431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param x X coordinate of the point 81531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param y Y coordinate of the point 81631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param result Array of 2 ints to hold the x and y coordinate of the cell 81731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 81831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project void pointToCellRounded(int x, int y, int[] result) { 81931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project pointToCellExact(x + (mCellWidth / 2), y + (mCellHeight / 2), result); 82031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 82131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 82231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 82331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Given a cell coordinate, return the point that represents the upper left corner of that cell 824aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * 825aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * @param cellX X coordinate of the cell 82631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param cellY Y coordinate of the cell 827aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * 82831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param result Array of 2 ints to hold the x and y coordinate of the point 82931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 83031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project void cellToPoint(int cellX, int cellY, int[] result) { 8314b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung final int hStartPadding = getPaddingLeft(); 8324b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung final int vStartPadding = getPaddingTop(); 83331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 83431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project result[0] = hStartPadding + cellX * (mCellWidth + mWidthGap); 83531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project result[1] = vStartPadding + cellY * (mCellHeight + mHeightGap); 83631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 83731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 838e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen /** 839482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * Given a cell coordinate, return the point that represents the center of the cell 840e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen * 841e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen * @param cellX X coordinate of the cell 842e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen * @param cellY Y coordinate of the cell 843e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen * 844e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen * @param result Array of 2 ints to hold the x and y coordinate of the point 845e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen */ 846e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen void cellToCenterPoint(int cellX, int cellY, int[] result) { 84747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen regionToCenterPoint(cellX, cellY, 1, 1, result); 84847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 84947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 85047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen /** 85147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * Given a cell coordinate and span return the point that represents the center of the regio 85247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * 85347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param cellX X coordinate of the cell 85447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param cellY Y coordinate of the cell 85547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * 85647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param result Array of 2 ints to hold the x and y coordinate of the point 85747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen */ 85847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen void regionToCenterPoint(int cellX, int cellY, int spanX, int spanY, int[] result) { 8594b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung final int hStartPadding = getPaddingLeft(); 8604b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung final int vStartPadding = getPaddingTop(); 86147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen result[0] = hStartPadding + cellX * (mCellWidth + mWidthGap) + 86247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen (spanX * mCellWidth + (spanX - 1) * mWidthGap) / 2; 86347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen result[1] = vStartPadding + cellY * (mCellHeight + mHeightGap) + 86447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen (spanY * mCellHeight + (spanY - 1) * mHeightGap) / 2; 865e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen } 866e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen 86719f3792523fe2d55ea791a9286398a6120920690Adam Cohen /** 86819f3792523fe2d55ea791a9286398a6120920690Adam Cohen * Given a cell coordinate and span fills out a corresponding pixel rect 86919f3792523fe2d55ea791a9286398a6120920690Adam Cohen * 87019f3792523fe2d55ea791a9286398a6120920690Adam Cohen * @param cellX X coordinate of the cell 87119f3792523fe2d55ea791a9286398a6120920690Adam Cohen * @param cellY Y coordinate of the cell 87219f3792523fe2d55ea791a9286398a6120920690Adam Cohen * @param result Rect in which to write the result 87319f3792523fe2d55ea791a9286398a6120920690Adam Cohen */ 87419f3792523fe2d55ea791a9286398a6120920690Adam Cohen void regionToRect(int cellX, int cellY, int spanX, int spanY, Rect result) { 87519f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int hStartPadding = getPaddingLeft(); 87619f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int vStartPadding = getPaddingTop(); 87719f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int left = hStartPadding + cellX * (mCellWidth + mWidthGap); 87819f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int top = vStartPadding + cellY * (mCellHeight + mHeightGap); 87919f3792523fe2d55ea791a9286398a6120920690Adam Cohen result.set(left, top, left + (spanX * mCellWidth + (spanX - 1) * mWidthGap), 88019f3792523fe2d55ea791a9286398a6120920690Adam Cohen top + (spanY * mCellHeight + (spanY - 1) * mHeightGap)); 88119f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 88219f3792523fe2d55ea791a9286398a6120920690Adam Cohen 883482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public float getDistanceFromCell(float x, float y, int[] cell) { 884482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen cellToCenterPoint(cell[0], cell[1], mTmpPoint); 885482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen float distance = (float) Math.sqrt( Math.pow(x - mTmpPoint[0], 2) + 886482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen Math.pow(y - mTmpPoint[1], 2)); 887482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return distance; 888482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 889482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 89084f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy int getCellWidth() { 89184f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy return mCellWidth; 89284f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy } 89384f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy 89484f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy int getCellHeight() { 89584f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy return mCellHeight; 89684f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy } 89784f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy 898d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen int getWidthGap() { 899d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen return mWidthGap; 900d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen } 901d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen 902d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen int getHeightGap() { 903d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen return mHeightGap; 904d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen } 905d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen 9067f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen Rect getContentRect(Rect r) { 9077f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen if (r == null) { 9087f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen r = new Rect(); 9097f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 9107f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen int left = getPaddingLeft(); 9117f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen int top = getPaddingTop(); 9128b805b17158886035b38261eb611d8641701ae43Michael Jurka int right = left + getWidth() - getPaddingLeft() - getPaddingRight(); 9138b805b17158886035b38261eb611d8641701ae43Michael Jurka int bottom = top + getHeight() - getPaddingTop() - getPaddingBottom(); 9147f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen r.set(left, top, right, bottom); 9157f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen return r; 9167f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 9177f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 918a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen static void getMetrics(Rect metrics, Resources res, int measureWidth, int measureHeight, 919a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen int countX, int countY, int orientation) { 920a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen int numWidthGaps = countX - 1; 921a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen int numHeightGaps = countY - 1; 922f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen 923f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen int widthGap; 924f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen int heightGap; 925f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen int cellWidth; 926f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen int cellHeight; 927f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen int paddingLeft; 928f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen int paddingRight; 929f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen int paddingTop; 930f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen int paddingBottom; 931f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen 932a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen int maxGap = res.getDimensionPixelSize(R.dimen.workspace_max_gap); 933f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen if (orientation == LANDSCAPE) { 934f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen cellWidth = res.getDimensionPixelSize(R.dimen.workspace_cell_width_land); 935f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen cellHeight = res.getDimensionPixelSize(R.dimen.workspace_cell_height_land); 936f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen widthGap = res.getDimensionPixelSize(R.dimen.workspace_width_gap_land); 937f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen heightGap = res.getDimensionPixelSize(R.dimen.workspace_height_gap_land); 938f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen paddingLeft = res.getDimensionPixelSize(R.dimen.cell_layout_left_padding_land); 939f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen paddingRight = res.getDimensionPixelSize(R.dimen.cell_layout_right_padding_land); 940f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen paddingTop = res.getDimensionPixelSize(R.dimen.cell_layout_top_padding_land); 941f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen paddingBottom = res.getDimensionPixelSize(R.dimen.cell_layout_bottom_padding_land); 942f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen } else { 943f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen // PORTRAIT 944f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen cellWidth = res.getDimensionPixelSize(R.dimen.workspace_cell_width_port); 945f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen cellHeight = res.getDimensionPixelSize(R.dimen.workspace_cell_height_port); 946f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen widthGap = res.getDimensionPixelSize(R.dimen.workspace_width_gap_port); 947f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen heightGap = res.getDimensionPixelSize(R.dimen.workspace_height_gap_port); 948f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen paddingLeft = res.getDimensionPixelSize(R.dimen.cell_layout_left_padding_port); 949f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen paddingRight = res.getDimensionPixelSize(R.dimen.cell_layout_right_padding_port); 950f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen paddingTop = res.getDimensionPixelSize(R.dimen.cell_layout_top_padding_port); 951f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen paddingBottom = res.getDimensionPixelSize(R.dimen.cell_layout_bottom_padding_port); 952f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen } 953f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen 954f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen if (widthGap < 0 || heightGap < 0) { 955f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen int hSpace = measureWidth - paddingLeft - paddingRight; 956f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen int vSpace = measureHeight - paddingTop - paddingBottom; 957a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen int hFreeSpace = hSpace - (countX * cellWidth); 958a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen int vFreeSpace = vSpace - (countY * cellHeight); 959a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen widthGap = Math.min(maxGap, numWidthGaps > 0 ? (hFreeSpace / numWidthGaps) : 0); 960a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen heightGap = Math.min(maxGap, numHeightGaps > 0 ? (vFreeSpace / numHeightGaps) : 0); 961f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen } 962f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen metrics.set(cellWidth, cellHeight, widthGap, heightGap); 963f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen } 964f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen 96531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 96631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 96731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec); 968aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec); 969aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 97031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec); 97131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec); 972aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 97331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (widthSpecMode == MeasureSpec.UNSPECIFIED || heightSpecMode == MeasureSpec.UNSPECIFIED) { 97431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project throw new RuntimeException("CellLayout cannot have UNSPECIFIED dimensions"); 97531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 97631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 977d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen int numWidthGaps = mCountX - 1; 978d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen int numHeightGaps = mCountY - 1; 979d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen 980234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen if (mOriginalWidthGap < 0 || mOriginalHeightGap < 0) { 981dd13e3d0f9925b7bb80c37e21d039aab4fa7e7a1Michael Jurka int hSpace = widthSpecSize - getPaddingLeft() - getPaddingRight(); 982dd13e3d0f9925b7bb80c37e21d039aab4fa7e7a1Michael Jurka int vSpace = heightSpecSize - getPaddingTop() - getPaddingBottom(); 983f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen int hFreeSpace = hSpace - (mCountX * mCellWidth); 984f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen int vFreeSpace = vSpace - (mCountY * mCellHeight); 9854b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung mWidthGap = Math.min(mMaxGap, numWidthGaps > 0 ? (hFreeSpace / numWidthGaps) : 0); 9864b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung mHeightGap = Math.min(mMaxGap,numHeightGaps > 0 ? (vFreeSpace / numHeightGaps) : 0); 987a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.setCellDimensions(mCellWidth, mCellHeight, mWidthGap, mHeightGap); 988234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen } else { 989234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen mWidthGap = mOriginalWidthGap; 990234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen mHeightGap = mOriginalHeightGap; 991ece7f5b3b55cab646941123e03589241a61678e2Winson Chung } 9925f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka 9938c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka // Initial values correspond to widthSpecMode == MeasureSpec.EXACTLY 9948c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka int newWidth = widthSpecSize; 9958c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka int newHeight = heightSpecSize; 9968c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka if (widthSpecMode == MeasureSpec.AT_MOST) { 9978b805b17158886035b38261eb611d8641701ae43Michael Jurka newWidth = getPaddingLeft() + getPaddingRight() + (mCountX * mCellWidth) + 9988c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka ((mCountX - 1) * mWidthGap); 9998b805b17158886035b38261eb611d8641701ae43Michael Jurka newHeight = getPaddingTop() + getPaddingBottom() + (mCountY * mCellHeight) + 10008c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka ((mCountY - 1) * mHeightGap); 10018c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka setMeasuredDimension(newWidth, newHeight); 10028c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka } 100331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 10048c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka int count = getChildCount(); 100531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int i = 0; i < count; i++) { 100631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project View child = getChildAt(i); 10078b805b17158886035b38261eb611d8641701ae43Michael Jurka int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(newWidth - getPaddingLeft() - 10088b805b17158886035b38261eb611d8641701ae43Michael Jurka getPaddingRight(), MeasureSpec.EXACTLY); 10098b805b17158886035b38261eb611d8641701ae43Michael Jurka int childheightMeasureSpec = MeasureSpec.makeMeasureSpec(newHeight - getPaddingTop() - 10108b805b17158886035b38261eb611d8641701ae43Michael Jurka getPaddingBottom(), MeasureSpec.EXACTLY); 101131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project child.measure(childWidthMeasureSpec, childheightMeasureSpec); 101231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 10138c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka setMeasuredDimension(newWidth, newHeight); 101431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 101531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 101631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 101728750fba6a2d141eb9a1e566718c17236030b815Michael Jurka protected void onLayout(boolean changed, int l, int t, int r, int b) { 101831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int count = getChildCount(); 101931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int i = 0; i < count; i++) { 10208c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka View child = getChildAt(i); 10218b805b17158886035b38261eb611d8641701ae43Michael Jurka child.layout(getPaddingLeft(), getPaddingTop(), 10228b805b17158886035b38261eb611d8641701ae43Michael Jurka r - l - getPaddingRight(), b - t - getPaddingBottom()); 102331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 102431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 102531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 102631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 1027dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka protected void onSizeChanged(int w, int h, int oldw, int oldh) { 1028dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka super.onSizeChanged(w, h, oldw, oldh); 102918014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka mBackgroundRect.set(0, 0, w, h); 1030b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mForegroundRect.set(mForegroundPadding, mForegroundPadding, 1031215b416c1f7cf0234b777155b823637a0902739fAdam Cohen w - mForegroundPadding, h - mForegroundPadding); 1032dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } 1033dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka 1034dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka @Override 103531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected void setChildrenDrawingCacheEnabled(boolean enabled) { 1036a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.setChildrenDrawingCacheEnabled(enabled); 103731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 103831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 103931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 104031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected void setChildrenDrawnWithCacheEnabled(boolean enabled) { 1041a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.setChildrenDrawnWithCacheEnabled(enabled); 104231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 104331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 10445f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka public float getBackgroundAlpha() { 10455f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka return mBackgroundAlpha; 1046dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } 1047dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka 10481b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen public void setBackgroundAlphaMultiplier(float multiplier) { 1049a3d30adbfd4f013260f1f5ba3a56bc9bb4a11717Michael Jurka if (mBackgroundAlphaMultiplier != multiplier) { 1050a3d30adbfd4f013260f1f5ba3a56bc9bb4a11717Michael Jurka mBackgroundAlphaMultiplier = multiplier; 1051a3d30adbfd4f013260f1f5ba3a56bc9bb4a11717Michael Jurka invalidate(); 1052a3d30adbfd4f013260f1f5ba3a56bc9bb4a11717Michael Jurka } 10531b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen } 10541b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen 1055ddb821981e0919bbd3b4c9a2b6aa1811d6c86bb6Adam Cohen public float getBackgroundAlphaMultiplier() { 1056ddb821981e0919bbd3b4c9a2b6aa1811d6c86bb6Adam Cohen return mBackgroundAlphaMultiplier; 1057ddb821981e0919bbd3b4c9a2b6aa1811d6c86bb6Adam Cohen } 1058ddb821981e0919bbd3b4c9a2b6aa1811d6c86bb6Adam Cohen 10595f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka public void setBackgroundAlpha(float alpha) { 1060afaa05014e0bf3ed1192f9ddec2af4283bc50248Michael Jurka if (mBackgroundAlpha != alpha) { 1061afaa05014e0bf3ed1192f9ddec2af4283bc50248Michael Jurka mBackgroundAlpha = alpha; 1062afaa05014e0bf3ed1192f9ddec2af4283bc50248Michael Jurka invalidate(); 1063afaa05014e0bf3ed1192f9ddec2af4283bc50248Michael Jurka } 1064dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } 1065dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka 1066a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka public void setShortcutAndWidgetAlpha(float alpha) { 10670142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka final int childCount = getChildCount(); 10680142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka for (int i = 0; i < childCount; i++) { 1069dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka getChildAt(i).setAlpha(alpha); 1070dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } 1071dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } 1072dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka 1073a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka public ShortcutAndWidgetContainer getShortcutsAndWidgets() { 1074a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka if (getChildCount() > 0) { 1075a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka return (ShortcutAndWidgetContainer) getChildAt(0); 1076a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka } 1077a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka return null; 1078a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka } 1079a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka 1080440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy public View getChildAt(int x, int y) { 1081a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka return mShortcutsAndWidgets.getChildAt(x, y); 1082440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy } 1083440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy 108476fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen public boolean animateChildToPosition(final View child, int cellX, int cellY, int duration, 1085482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int delay, boolean permanent, boolean adjustOccupied) { 1086a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka ShortcutAndWidgetContainer clc = getShortcutsAndWidgets(); 1087482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean[][] occupied = mOccupied; 1088482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (!permanent) { 1089482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen occupied = mTmpOccupied; 1090482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1091482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 109219f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (clc.indexOfChild(child) != -1) { 1093bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 1094bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen final ItemInfo info = (ItemInfo) child.getTag(); 1095bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen 1096bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen // We cancel any existing animations 1097bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen if (mReorderAnimators.containsKey(lp)) { 1098bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen mReorderAnimators.get(lp).cancel(); 1099bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen mReorderAnimators.remove(lp); 1100bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 1101bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen 1102482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int oldX = lp.x; 1103482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int oldY = lp.y; 1104482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (adjustOccupied) { 1105482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen occupied[lp.cellX][lp.cellY] = false; 1106482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen occupied[cellX][cellY] = true; 1107482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1108bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen lp.isLockedToGrid = true; 1109482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (permanent) { 1110482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen lp.cellX = info.cellX = cellX; 1111482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen lp.cellY = info.cellY = cellY; 1112482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } else { 1113482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen lp.tmpCellX = cellX; 1114482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen lp.tmpCellY = cellY; 1115482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1116bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen clc.setupLp(lp); 1117bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen lp.isLockedToGrid = false; 1118482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int newX = lp.x; 1119482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int newY = lp.y; 1120bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen 112176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen lp.x = oldX; 112276fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen lp.y = oldY; 112376fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen 1124482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // Exit early if we're not actually moving the view 1125482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (oldX == newX && oldY == newY) { 1126482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen lp.isLockedToGrid = true; 1127482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return true; 1128482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1129482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 11302ecf995e0d2d55eb71d03f7230ca87270872d1a3Michael Jurka ValueAnimator va = LauncherAnimUtils.ofFloat(0f, 1f); 1131482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen va.setDuration(duration); 1132482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mReorderAnimators.put(lp, va); 1133482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1134482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen va.addUpdateListener(new AnimatorUpdateListener() { 1135482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen @Override 1136bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen public void onAnimationUpdate(ValueAnimator animation) { 1137482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen float r = ((Float) animation.getAnimatedValue()).floatValue(); 113819f3792523fe2d55ea791a9286398a6120920690Adam Cohen lp.x = (int) ((1 - r) * oldX + r * newX); 113919f3792523fe2d55ea791a9286398a6120920690Adam Cohen lp.y = (int) ((1 - r) * oldY + r * newY); 11406b8a02d63a5d9cab8209381993e37db6a6afb753Adam Cohen child.requestLayout(); 1141bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 1142bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen }); 1143482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen va.addListener(new AnimatorListenerAdapter() { 1144bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen boolean cancelled = false; 1145bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen public void onAnimationEnd(Animator animation) { 1146bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen // If the animation was cancelled, it means that another animation 1147bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen // has interrupted this one, and we don't want to lock the item into 1148bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen // place just yet. 1149bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen if (!cancelled) { 1150bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen lp.isLockedToGrid = true; 1151482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen child.requestLayout(); 1152bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 1153bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen if (mReorderAnimators.containsKey(lp)) { 1154bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen mReorderAnimators.remove(lp); 1155bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 1156bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 1157bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen public void onAnimationCancel(Animator animation) { 1158bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen cancelled = true; 1159bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 1160bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen }); 1161482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen va.setStartDelay(delay); 1162482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen va.start(); 1163bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen return true; 1164bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 1165bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen return false; 1166bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 1167bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen 11686569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy /** 11696569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy * Estimate where the top left cell of the dragged item will land if it is dropped. 11706569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy * 11716569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy * @param originX The X value of the top left corner of the item 11726569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy * @param originY The Y value of the top left corner of the item 11736569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy * @param spanX The number of horizontal cells that the item spans 11746569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy * @param spanY The number of vertical cells that the item spans 11756569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy * @param result The estimated drop cell X and Y. 11766569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy */ 11776569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy void estimateDropCell(int originX, int originY, int spanX, int spanY, int[] result) { 1178d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen final int countX = mCountX; 1179d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen final int countY = mCountY; 11806569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 1181a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka // pointToCellRounded takes the top left of a cell but will pad that with 1182a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka // cellWidth/2 and cellHeight/2 when finding the matching cell 1183a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka pointToCellRounded(originX, originY, result); 11846569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 11856569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy // If the item isn't fully on this screen, snap to the edges 11866569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy int rightOverhang = result[0] + spanX - countX; 11876569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy if (rightOverhang > 0) { 11886569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy result[0] -= rightOverhang; // Snap to right 11896569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy } 11906569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy result[0] = Math.max(0, result[0]); // Snap to left 11916569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy int bottomOverhang = result[1] + spanY - countY; 11926569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy if (bottomOverhang > 0) { 11936569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy result[1] -= bottomOverhang; // Snap to bottom 11946569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy } 11956569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy result[1] = Math.max(0, result[1]); // Snap to top 11966569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy } 11976569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 1198482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen void visualizeDropLocation(View v, Bitmap dragOutline, int originX, int originY, int cellX, 1199482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int cellY, int spanX, int spanY, boolean resize, Point dragOffset, Rect dragRegion) { 120008ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy final int oldDragCellX = mDragCell[0]; 120108ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy final int oldDragCellY = mDragCell[1]; 1202482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1203b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung if (v != null && dragOffset == null) { 1204a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung mDragCenter.set(originX + (v.getWidth() / 2), originY + (v.getHeight() / 2)); 1205a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung } else { 1206a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung mDragCenter.set(originX, originY); 1207a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung } 12086569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 12092801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen if (dragOutline == null && v == null) { 12102801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen return; 12112801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen } 12122801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen 1213482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (cellX != oldDragCellX || cellY != oldDragCellY) { 1214482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mDragCell[0] = cellX; 1215482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mDragCell[1] = cellY; 12166569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy // Find the top left corner of the rect the object will occupy 1217de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy final int[] topLeft = mTmpPoint; 1218482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen cellToPoint(cellX, cellY, topLeft); 1219de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy 12204be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato int left = topLeft[0]; 12214be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato int top = topLeft[1]; 12226569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 1223b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung if (v != null && dragOffset == null) { 122499e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen // When drawing the drag outline, it did not account for margin offsets 122599e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen // added by the view's parent. 122699e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen MarginLayoutParams lp = (MarginLayoutParams) v.getLayoutParams(); 122799e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen left += lp.leftMargin; 122899e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen top += lp.topMargin; 122999e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen 123099e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen // Offsets due to the size difference between the View and the dragOutline. 123199e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen // There is a size difference to account for the outer blur, which may lie 123299e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen // outside the bounds of the view. 1233a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung top += (v.getHeight() - dragOutline.getHeight()) / 2; 1234ae915cecd36af4973061a1cb0b58c5be1be699a0Adam Cohen // We center about the x axis 1235ae915cecd36af4973061a1cb0b58c5be1be699a0Adam Cohen left += ((mCellWidth * spanX) + ((spanX - 1) * mWidthGap) 1236ae915cecd36af4973061a1cb0b58c5be1be699a0Adam Cohen - dragOutline.getWidth()) / 2; 12376639687cd67bab1aeef2a75e5c6bc458b20dc082Adam Cohen } else { 1238b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung if (dragOffset != null && dragRegion != null) { 1239b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung // Center the drag region *horizontally* in the cell and apply a drag 1240b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung // outline offset 1241b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung left += dragOffset.x + ((mCellWidth * spanX) + ((spanX - 1) * mWidthGap) 1242b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung - dragRegion.width()) / 2; 1243b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung top += dragOffset.y; 1244b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung } else { 1245b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung // Center the drag outline in the cell 1246b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung left += ((mCellWidth * spanX) + ((spanX - 1) * mWidthGap) 1247b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung - dragOutline.getWidth()) / 2; 1248b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung top += ((mCellHeight * spanY) + ((spanY - 1) * mHeightGap) 1249b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung - dragOutline.getHeight()) / 2; 1250b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung } 1251a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung } 12524be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato final int oldIndex = mDragOutlineCurrent; 125308ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy mDragOutlineAnims[oldIndex].animateOut(); 125408ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy mDragOutlineCurrent = (oldIndex + 1) % mDragOutlines.length; 1255d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen Rect r = mDragOutlines[mDragOutlineCurrent]; 1256d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen r.set(left, top, left + dragOutline.getWidth(), top + dragOutline.getHeight()); 1257d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (resize) { 1258482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen cellToRect(cellX, cellY, spanX, spanY, r); 1259d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1260150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung 126108ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy mDragOutlineAnims[mDragOutlineCurrent].setTag(dragOutline); 126208ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy mDragOutlineAnims[mDragOutlineCurrent].animateIn(); 12636569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy } 12646569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy } 12656569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 1266e0310965022e7a1adb7ad489505d404186608689Adam Cohen public void clearDragOutlines() { 1267e0310965022e7a1adb7ad489505d404186608689Adam Cohen final int oldIndex = mDragOutlineCurrent; 1268e0310965022e7a1adb7ad489505d404186608689Adam Cohen mDragOutlineAnims[oldIndex].animateOut(); 1269d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen mDragCell[0] = mDragCell[1] = -1; 1270e0310965022e7a1adb7ad489505d404186608689Adam Cohen } 1271e0310965022e7a1adb7ad489505d404186608689Adam Cohen 127231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 127370864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * Find a vacant area that will fit the given bounds nearest the requested 127470864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * cell location. Uses Euclidean distance to score multiple vacant areas. 1275aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * 127651afc022fa76c79f0d1ece470ddc126c08fea8a4Romain Guy * @param pixelX The X location at which you want to search for a vacant area. 127751afc022fa76c79f0d1ece470ddc126c08fea8a4Romain Guy * @param pixelY The Y location at which you want to search for a vacant area. 127870864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * @param spanX Horizontal span of the object. 127970864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * @param spanY Vertical span of the object. 1280de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy * @param result Array in which to place the result, or null (in which case a new array will 1281de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy * be allocated) 128270864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * @return The X, Y cell of a vacant area that can contain this object, 128370864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * nearest the requested location. 128431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 1285d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int[] findNearestVacantArea(int pixelX, int pixelY, int spanX, int spanY, 1286d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int[] result) { 1287de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy return findNearestVacantArea(pixelX, pixelY, spanX, spanY, null, result); 12886a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka } 1289aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 12906a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka /** 12916a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * Find a vacant area that will fit the given bounds nearest the requested 12926a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * cell location. Uses Euclidean distance to score multiple vacant areas. 12936a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * 12946a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * @param pixelX The X location at which you want to search for a vacant area. 12956a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * @param pixelY The Y location at which you want to search for a vacant area. 1296d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param minSpanX The minimum horizontal span required 1297d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param minSpanY The minimum vertical span required 1298d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param spanX Horizontal span of the object. 1299d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param spanY Vertical span of the object. 1300d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param result Array in which to place the result, or null (in which case a new array will 1301d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * be allocated) 1302d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @return The X, Y cell of a vacant area that can contain this object, 1303d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * nearest the requested location. 1304d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen */ 1305d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int[] findNearestVacantArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, 1306d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int spanY, int[] result, int[] resultSpan) { 1307d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen return findNearestVacantArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, null, 1308d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen result, resultSpan); 1309d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1310d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen 1311d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen /** 1312d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * Find a vacant area that will fit the given bounds nearest the requested 1313d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * cell location. Uses Euclidean distance to score multiple vacant areas. 1314d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * 1315d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param pixelX The X location at which you want to search for a vacant area. 1316d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param pixelY The Y location at which you want to search for a vacant area. 13176a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * @param spanX Horizontal span of the object. 13186a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * @param spanY Vertical span of the object. 1319df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param ignoreOccupied If true, the result can be an occupied cell 1320df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param result Array in which to place the result, or null (in which case a new array will 1321df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * be allocated) 13226a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * @return The X, Y cell of a vacant area that can contain this object, 13236a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * nearest the requested location. 13246a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka */ 1325df0353815c629fc678824b07a234b89a1ff94208Adam Cohen int[] findNearestArea(int pixelX, int pixelY, int spanX, int spanY, View ignoreView, 1326df0353815c629fc678824b07a234b89a1ff94208Adam Cohen boolean ignoreOccupied, int[] result) { 1327d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen return findNearestArea(pixelX, pixelY, spanX, spanY, 1328482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen spanX, spanY, ignoreView, ignoreOccupied, result, null, mOccupied); 1329d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1330d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen 1331d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen private final Stack<Rect> mTempRectStack = new Stack<Rect>(); 1332d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen private void lazyInitTempRectStack() { 1333d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (mTempRectStack.isEmpty()) { 1334d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen for (int i = 0; i < mCountX * mCountY; i++) { 1335d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen mTempRectStack.push(new Rect()); 1336d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1337d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1338d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1339482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1340d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen private void recycleTempRects(Stack<Rect> used) { 1341d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen while (!used.isEmpty()) { 1342d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen mTempRectStack.push(used.pop()); 1343d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1344d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1345d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen 1346d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen /** 1347d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * Find a vacant area that will fit the given bounds nearest the requested 1348d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * cell location. Uses Euclidean distance to score multiple vacant areas. 1349d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * 1350d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param pixelX The X location at which you want to search for a vacant area. 1351d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param pixelY The Y location at which you want to search for a vacant area. 1352d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param minSpanX The minimum horizontal span required 1353d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param minSpanY The minimum vertical span required 1354d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param spanX Horizontal span of the object. 1355d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param spanY Vertical span of the object. 1356d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param ignoreOccupied If true, the result can be an occupied cell 1357d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param result Array in which to place the result, or null (in which case a new array will 1358d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * be allocated) 1359d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @return The X, Y cell of a vacant area that can contain this object, 1360d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * nearest the requested location. 1361d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen */ 1362d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int[] findNearestArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, int spanY, 1363482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen View ignoreView, boolean ignoreOccupied, int[] result, int[] resultSpan, 1364482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean[][] occupied) { 1365d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen lazyInitTempRectStack(); 1366c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka // mark space take by ignoreView as available (method checks if ignoreView is null) 1367482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsAsUnoccupiedForView(ignoreView, occupied); 1368c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka 1369e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen // For items with a spanX / spanY > 1, the passed in point (pixelX, pixelY) corresponds 1370e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen // to the center of the item, but we are searching based on the top-left cell, so 1371e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen // we translate the point over to correspond to the top-left. 1372e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen pixelX -= (mCellWidth + mWidthGap) * (spanX - 1) / 2f; 1373e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen pixelY -= (mCellHeight + mHeightGap) * (spanY - 1) / 2f; 1374e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen 137570864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey // Keep track of best-scoring drop area 1376de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy final int[] bestXY = result != null ? result : new int[2]; 137770864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey double bestDistance = Double.MAX_VALUE; 1378d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen final Rect bestRect = new Rect(-1, -1, -1, -1); 1379d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen final Stack<Rect> validRegions = new Stack<Rect>(); 1380aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 1381de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy final int countX = mCountX; 1382de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy final int countY = mCountY; 1383de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy 1384d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (minSpanX <= 0 || minSpanY <= 0 || spanX <= 0 || spanY <= 0 || 1385d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen spanX < minSpanX || spanY < minSpanY) { 1386d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen return bestXY; 1387d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1388d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen 1389d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen for (int y = 0; y < countY - (minSpanY - 1); y++) { 1390c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka inner: 1391d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen for (int x = 0; x < countX - (minSpanX - 1); x++) { 1392d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int ySize = -1; 1393d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int xSize = -1; 1394df0353815c629fc678824b07a234b89a1ff94208Adam Cohen if (ignoreOccupied) { 1395d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // First, let's see if this thing fits anywhere 1396d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen for (int i = 0; i < minSpanX; i++) { 1397d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen for (int j = 0; j < minSpanY; j++) { 1398df0353815c629fc678824b07a234b89a1ff94208Adam Cohen if (occupied[x + i][y + j]) { 1399df0353815c629fc678824b07a234b89a1ff94208Adam Cohen continue inner; 1400df0353815c629fc678824b07a234b89a1ff94208Adam Cohen } 1401c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka } 1402c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka } 1403d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen xSize = minSpanX; 1404d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen ySize = minSpanY; 1405d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen 1406d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // We know that the item will fit at _some_ acceptable size, now let's see 1407d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // how big we can make it. We'll alternate between incrementing x and y spans 1408d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // until we hit a limit. 1409d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen boolean incX = true; 1410d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen boolean hitMaxX = xSize >= spanX; 1411d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen boolean hitMaxY = ySize >= spanY; 1412d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen while (!(hitMaxX && hitMaxY)) { 1413d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (incX && !hitMaxX) { 1414d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen for (int j = 0; j < ySize; j++) { 1415d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (x + xSize > countX -1 || occupied[x + xSize][y + j]) { 1416d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // We can't move out horizontally 1417d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen hitMaxX = true; 1418d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1419d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1420d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (!hitMaxX) { 1421d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen xSize++; 1422d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1423d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } else if (!hitMaxY) { 1424d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen for (int i = 0; i < xSize; i++) { 1425d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (y + ySize > countY - 1 || occupied[x + i][y + ySize]) { 1426d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // We can't move out vertically 1427d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen hitMaxY = true; 1428d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1429d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1430d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (!hitMaxY) { 1431d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen ySize++; 1432d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1433d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1434d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen hitMaxX |= xSize >= spanX; 1435d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen hitMaxY |= ySize >= spanY; 1436d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen incX = !incX; 1437d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1438d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen incX = true; 1439d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen hitMaxX = xSize >= spanX; 1440d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen hitMaxY = ySize >= spanY; 1441c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka } 14420be025d64c1f84138fe430a58875886e66aae767Winson Chung final int[] cellXY = mTmpXY; 1443e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen cellToCenterPoint(x, y, cellXY); 1444c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka 1445d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // We verify that the current rect is not a sub-rect of any of our previous 1446d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // candidates. In this case, the current rect is disqualified in favour of the 1447d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // containing rect. 1448d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen Rect currentRect = mTempRectStack.pop(); 1449d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen currentRect.set(x, y, x + xSize, y + ySize); 1450d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen boolean contained = false; 1451d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen for (Rect r : validRegions) { 1452d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (r.contains(currentRect)) { 1453d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen contained = true; 1454d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen break; 1455d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1456d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1457d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen validRegions.push(currentRect); 1458c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka double distance = Math.sqrt(Math.pow(cellXY[0] - pixelX, 2) 1459c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka + Math.pow(cellXY[1] - pixelY, 2)); 1460482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1461d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if ((distance <= bestDistance && !contained) || 1462d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen currentRect.contains(bestRect)) { 1463c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka bestDistance = distance; 1464c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka bestXY[0] = x; 1465c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka bestXY[1] = y; 1466d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (resultSpan != null) { 1467d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen resultSpan[0] = xSize; 1468d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen resultSpan[1] = ySize; 1469d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1470d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen bestRect.set(currentRect); 1471c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka } 147231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 147331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 1474c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka // re-mark space taken by ignoreView as occupied 1475482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsAsOccupiedForView(ignoreView, occupied); 147631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 1477c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen // Return -1, -1 if no suitable location found 1478c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen if (bestDistance == Double.MAX_VALUE) { 1479c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen bestXY[0] = -1; 1480c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen bestXY[1] = -1; 148170864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey } 1482d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen recycleTempRects(validRegions); 1483c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen return bestXY; 148431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 1485aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 1486482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen /** 1487482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * Find a vacant area that will fit the given bounds nearest the requested 1488482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * cell location, and will also weigh in a suggested direction vector of the 1489482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * desired location. This method computers distance based on unit grid distances, 1490482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * not pixel distances. 1491482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * 149247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param cellX The X cell nearest to which you want to search for a vacant area. 149347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param cellY The Y cell nearest which you want to search for a vacant area. 1494482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * @param spanX Horizontal span of the object. 1495482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * @param spanY Vertical span of the object. 149647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param direction The favored direction in which the views should move from x, y 149747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param exactDirectionOnly If this parameter is true, then only solutions where the direction 149847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * matches exactly. Otherwise we find the best matching direction. 149947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param occoupied The array which represents which cells in the CellLayout are occupied 150047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param blockOccupied The array which represents which cells in the specified block (cellX, 150147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * cellY, spanX, spanY) are occupied. This is used when try to move a group of views. 1502482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * @param result Array in which to place the result, or null (in which case a new array will 1503482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * be allocated) 1504482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * @return The X, Y cell of a vacant area that can contain this object, 1505482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * nearest the requested location. 1506482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen */ 1507482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private int[] findNearestArea(int cellX, int cellY, int spanX, int spanY, int[] direction, 150847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean[][] occupied, boolean blockOccupied[][], int[] result) { 1509482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // Keep track of best-scoring drop area 1510482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int[] bestXY = result != null ? result : new int[2]; 1511482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen float bestDistance = Float.MAX_VALUE; 1512482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int bestDirectionScore = Integer.MIN_VALUE; 1513482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1514482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int countX = mCountX; 1515482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int countY = mCountY; 1516482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1517482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int y = 0; y < countY - (spanY - 1); y++) { 1518482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen inner: 1519482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int x = 0; x < countX - (spanX - 1); x++) { 1520482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // First, let's see if this thing fits anywhere 1521482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < spanX; i++) { 1522482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int j = 0; j < spanY; j++) { 152347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (occupied[x + i][y + j] && (blockOccupied == null || blockOccupied[i][j])) { 1524482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen continue inner; 1525482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1526482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1527482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1528482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1529482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen float distance = (float) 1530482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen Math.sqrt((x - cellX) * (x - cellX) + (y - cellY) * (y - cellY)); 1531482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int[] curDirection = mTmpPoint; 153247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen computeDirectionVector(x - cellX, y - cellY, curDirection); 153347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen // The direction score is just the dot product of the two candidate direction 153447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen // and that passed in. 1535482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int curDirectionScore = direction[0] * curDirection[0] + 1536482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen direction[1] * curDirection[1]; 153747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean exactDirectionOnly = false; 153847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean directionMatches = direction[0] == curDirection[0] && 153947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen direction[0] == curDirection[0]; 154047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if ((directionMatches || !exactDirectionOnly) && 154147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen Float.compare(distance, bestDistance) < 0 || (Float.compare(distance, 1542482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen bestDistance) == 0 && curDirectionScore > bestDirectionScore)) { 1543482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen bestDistance = distance; 1544482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen bestDirectionScore = curDirectionScore; 1545482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen bestXY[0] = x; 1546482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen bestXY[1] = y; 1547482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1548482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1549482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1550482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1551482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // Return -1, -1 if no suitable location found 1552482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (bestDistance == Float.MAX_VALUE) { 1553482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen bestXY[0] = -1; 1554482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen bestXY[1] = -1; 1555482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1556482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return bestXY; 1557482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1558482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1559482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private boolean addViewToTempLocation(View v, Rect rectOccupiedByPotentialDrop, 15608baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen int[] direction, ItemConfiguration currentState) { 15618baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = currentState.map.get(v); 1562482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean success = false; 15638baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, false); 1564482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsForRect(rectOccupiedByPotentialDrop, mTmpOccupied, true); 1565482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 15668baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen findNearestArea(c.x, c.y, c.spanX, c.spanY, direction, mTmpOccupied, null, mTempLocation); 1567482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1568482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (mTempLocation[0] >= 0 && mTempLocation[1] >= 0) { 15698baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen c.x = mTempLocation[0]; 15708baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen c.y = mTempLocation[1]; 1571482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen success = true; 1572482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 15738baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, true); 1574482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return success; 1575482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1576482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1577f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen /** 1578f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen * This helper class defines a cluster of views. It helps with defining complex edges 1579f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen * of the cluster and determining how those edges interact with other views. The edges 1580f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen * essentially define a fine-grained boundary around the cluster of views -- like a more 1581f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen * precise version of a bounding box. 1582f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen */ 1583f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen private class ViewCluster { 1584f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen final static int LEFT = 0; 1585f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen final static int TOP = 1; 1586f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen final static int RIGHT = 2; 1587f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen final static int BOTTOM = 3; 1588f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 1589f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen ArrayList<View> views; 1590f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen ItemConfiguration config; 1591f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen Rect boundingRect = new Rect(); 1592f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 1593f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen int[] leftEdge = new int[mCountY]; 1594f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen int[] rightEdge = new int[mCountY]; 1595f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen int[] topEdge = new int[mCountX]; 1596f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen int[] bottomEdge = new int[mCountX]; 1597f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen boolean leftEdgeDirty, rightEdgeDirty, topEdgeDirty, bottomEdgeDirty, boundingRectDirty; 159847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 1599f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen @SuppressWarnings("unchecked") 1600f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen public ViewCluster(ArrayList<View> views, ItemConfiguration config) { 1601f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen this.views = (ArrayList<View>) views.clone(); 1602f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen this.config = config; 1603f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen resetEdges(); 1604f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 160547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 1606f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen void resetEdges() { 1607f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen for (int i = 0; i < mCountX; i++) { 1608f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen topEdge[i] = -1; 1609f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen bottomEdge[i] = -1; 1610f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1611f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen for (int i = 0; i < mCountY; i++) { 1612f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen leftEdge[i] = -1; 1613f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen rightEdge[i] = -1; 1614f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1615f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen leftEdgeDirty = true; 1616f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen rightEdgeDirty = true; 1617f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen bottomEdgeDirty = true; 1618f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen topEdgeDirty = true; 1619f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen boundingRectDirty = true; 1620f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1621f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 1622f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen void computeEdge(int which, int[] edge) { 1623f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen int count = views.size(); 1624f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen for (int i = 0; i < count; i++) { 1625f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen CellAndSpan cs = config.map.get(views.get(i)); 1626f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen switch (which) { 1627f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen case LEFT: 1628f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen int left = cs.x; 1629f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen for (int j = cs.y; j < cs.y + cs.spanY; j++) { 1630f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (left < edge[j] || edge[j] < 0) { 1631f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen edge[j] = left; 1632f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1633f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1634f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen break; 1635f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen case RIGHT: 1636f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen int right = cs.x + cs.spanX; 1637f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen for (int j = cs.y; j < cs.y + cs.spanY; j++) { 1638f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (right > edge[j]) { 1639f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen edge[j] = right; 1640f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1641f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1642f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen break; 1643f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen case TOP: 1644f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen int top = cs.y; 1645f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen for (int j = cs.x; j < cs.x + cs.spanX; j++) { 1646f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (top < edge[j] || edge[j] < 0) { 1647f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen edge[j] = top; 1648f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1649f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1650f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen break; 1651f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen case BOTTOM: 1652f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen int bottom = cs.y + cs.spanY; 1653f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen for (int j = cs.x; j < cs.x + cs.spanX; j++) { 1654f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (bottom > edge[j]) { 1655f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen edge[j] = bottom; 1656f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1657f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1658f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen break; 1659f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1660f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 166147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 166247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 1663f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen boolean isViewTouchingEdge(View v, int whichEdge) { 1664f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen CellAndSpan cs = config.map.get(v); 166547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 1666f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen int[] edge = getEdge(whichEdge); 1667f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 1668f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen switch (whichEdge) { 1669f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen case LEFT: 1670f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen for (int i = cs.y; i < cs.y + cs.spanY; i++) { 1671f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (edge[i] == cs.x + cs.spanX) { 1672f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen return true; 167347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 167447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 1675f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen break; 1676f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen case RIGHT: 1677f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen for (int i = cs.y; i < cs.y + cs.spanY; i++) { 1678f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (edge[i] == cs.x) { 1679f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen return true; 1680f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1681f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1682f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen break; 1683f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen case TOP: 1684f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen for (int i = cs.x; i < cs.x + cs.spanX; i++) { 1685f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (edge[i] == cs.y + cs.spanY) { 1686f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen return true; 1687f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1688f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1689f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen break; 1690f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen case BOTTOM: 1691f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen for (int i = cs.x; i < cs.x + cs.spanX; i++) { 1692f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (edge[i] == cs.y) { 1693f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen return true; 1694f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1695f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1696f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen break; 1697f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1698f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen return false; 1699f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1700f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 1701f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen void shift(int whichEdge, int delta) { 1702f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen for (View v: views) { 1703f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen CellAndSpan c = config.map.get(v); 1704f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen switch (whichEdge) { 1705f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen case LEFT: 1706f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen c.x -= delta; 1707f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen break; 1708f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen case RIGHT: 1709f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen c.x += delta; 1710f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen break; 1711f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen case TOP: 1712f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen c.y -= delta; 1713f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen break; 1714f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen case BOTTOM: 1715f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen default: 1716f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen c.y += delta; 1717f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen break; 1718f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1719f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1720f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen resetEdges(); 1721f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1722f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 1723f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen public void addView(View v) { 1724f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen views.add(v); 1725f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen resetEdges(); 1726f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1727f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 1728f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen public Rect getBoundingRect() { 1729f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (boundingRectDirty) { 1730f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen boolean first = true; 1731f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen for (View v: views) { 1732f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen CellAndSpan c = config.map.get(v); 1733f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (first) { 1734f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen boundingRect.set(c.x, c.y, c.x + c.spanX, c.y + c.spanY); 1735f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen first = false; 1736f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } else { 1737a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen boundingRect.union(c.x, c.y, c.x + c.spanX, c.y + c.spanY); 1738a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen } 173947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 174047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 1741f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen return boundingRect; 1742f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1743f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 1744f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen public int[] getEdge(int which) { 1745f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen switch (which) { 1746f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen case LEFT: 1747f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen return getLeftEdge(); 1748f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen case RIGHT: 1749f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen return getRightEdge(); 1750f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen case TOP: 1751f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen return getTopEdge(); 1752f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen case BOTTOM: 1753f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen default: 1754f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen return getBottomEdge(); 1755f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1756f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1757f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 1758f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen public int[] getLeftEdge() { 1759f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (leftEdgeDirty) { 1760f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen computeEdge(LEFT, leftEdge); 1761f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1762f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen return leftEdge; 1763f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1764f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 1765f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen public int[] getRightEdge() { 1766f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (rightEdgeDirty) { 1767f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen computeEdge(RIGHT, rightEdge); 1768f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1769f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen return rightEdge; 1770f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1771f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 1772f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen public int[] getTopEdge() { 1773f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (topEdgeDirty) { 1774f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen computeEdge(TOP, topEdge); 1775f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1776f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen return topEdge; 1777f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1778f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 1779f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen public int[] getBottomEdge() { 1780f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (bottomEdgeDirty) { 1781f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen computeEdge(BOTTOM, bottomEdge); 1782f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1783f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen return bottomEdge; 1784f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1785f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 1786f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen PositionComparator comparator = new PositionComparator(); 1787f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen class PositionComparator implements Comparator<View> { 1788f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen int whichEdge = 0; 1789f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen public int compare(View left, View right) { 1790f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen CellAndSpan l = config.map.get(left); 1791f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen CellAndSpan r = config.map.get(right); 1792f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen switch (whichEdge) { 1793f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen case LEFT: 1794f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen return (r.x + r.spanX) - (l.x + l.spanX); 1795f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen case RIGHT: 1796f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen return l.x - r.x; 1797f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen case TOP: 1798f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen return (r.y + r.spanY) - (l.y + l.spanY); 1799f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen case BOTTOM: 1800f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen default: 1801f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen return l.y - r.y; 1802f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1803f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1804f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1805f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 1806f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen public void sortConfigurationForEdgePush(int edge) { 1807f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen comparator.whichEdge = edge; 1808f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen Collections.sort(config.sortedViews, comparator); 180947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 181047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 181147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 1812f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen private boolean pushViewsToTempLocation(ArrayList<View> views, Rect rectOccupiedByPotentialDrop, 1813f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen int[] direction, View dragView, ItemConfiguration currentState) { 1814f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 1815f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen ViewCluster cluster = new ViewCluster(views, currentState); 1816f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen Rect clusterRect = cluster.getBoundingRect(); 1817f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen int whichEdge; 1818f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen int pushDistance; 1819f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen boolean fail = false; 1820e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen 1821f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen // Determine the edge of the cluster that will be leading the push and how far 1822f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen // the cluster must be shifted. 1823f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (direction[0] < 0) { 1824f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen whichEdge = ViewCluster.LEFT; 1825f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen pushDistance = clusterRect.right - rectOccupiedByPotentialDrop.left; 1826e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen } else if (direction[0] > 0) { 1827f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen whichEdge = ViewCluster.RIGHT; 1828f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen pushDistance = rectOccupiedByPotentialDrop.right - clusterRect.left; 1829f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } else if (direction[1] < 0) { 1830f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen whichEdge = ViewCluster.TOP; 1831f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen pushDistance = clusterRect.bottom - rectOccupiedByPotentialDrop.top; 1832f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } else { 1833f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen whichEdge = ViewCluster.BOTTOM; 1834f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen pushDistance = rectOccupiedByPotentialDrop.bottom - clusterRect.top; 1835f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1836f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 1837f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen // Break early for invalid push distance. 1838f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (pushDistance <= 0) { 1839f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen return false; 1840f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1841f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 1842f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen // Mark the occupied state as false for the group of views we want to move. 1843f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen for (View v: views) { 1844f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen CellAndSpan c = currentState.map.get(v); 1845f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, false); 1846f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1847f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 1848f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen // We save the current configuration -- if we fail to find a solution we will revert 1849f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen // to the initial state. The process of finding a solution modifies the configuration 1850f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen // in place, hence the need for revert in the failure case. 1851f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen currentState.save(); 1852f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 1853f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen // The pushing algorithm is simplified by considering the views in the order in which 1854f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen // they would be pushed by the cluster. For example, if the cluster is leading with its 1855f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen // left edge, we consider sort the views by their right edge, from right to left. 1856f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen cluster.sortConfigurationForEdgePush(whichEdge); 1857f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 1858f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen while (pushDistance > 0 && !fail) { 1859f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen for (View v: currentState.sortedViews) { 1860f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen // For each view that isn't in the cluster, we see if the leading edge of the 1861f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen // cluster is contacting the edge of that view. If so, we add that view to the 1862f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen // cluster. 1863f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (!cluster.views.contains(v) && v != dragView) { 1864f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (cluster.isViewTouchingEdge(v, whichEdge)) { 1865f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen LayoutParams lp = (LayoutParams) v.getLayoutParams(); 1866f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (!lp.canReorder) { 1867f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen // The push solution includes the all apps button, this is not viable. 1868f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen fail = true; 1869f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen break; 1870f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1871f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen cluster.addView(v); 1872f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen CellAndSpan c = currentState.map.get(v); 1873f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 1874f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen // Adding view to cluster, mark it as not occupied. 1875f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, false); 1876f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1877f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1878f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1879f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen pushDistance--; 1880f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 1881f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen // The cluster has been completed, now we move the whole thing over in the appropriate 1882f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen // direction. 1883f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen cluster.shift(whichEdge, 1); 1884e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen } 1885e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen 1886f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen boolean foundSolution = false; 1887f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen clusterRect = cluster.getBoundingRect(); 1888f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 1889f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen // Due to the nature of the algorithm, the only check required to verify a valid solution 1890f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen // is to ensure that completed shifted cluster lies completely within the cell layout. 1891f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (!fail && clusterRect.left >= 0 && clusterRect.right <= mCountX && clusterRect.top >= 0 && 1892f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen clusterRect.bottom <= mCountY) { 1893f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen foundSolution = true; 1894f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } else { 1895f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen currentState.restore(); 1896f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1897e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen 1898f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen // In either case, we set the occupied array as marked for the location of the views 1899f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen for (View v: cluster.views) { 1900f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen CellAndSpan c = currentState.map.get(v); 1901f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, true); 1902e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen } 1903f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 1904f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen return foundSolution; 1905e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen } 1906e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen 19078baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen private boolean addViewsToTempLocation(ArrayList<View> views, Rect rectOccupiedByPotentialDrop, 1908f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen int[] direction, View dragView, ItemConfiguration currentState) { 190947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (views.size() == 0) return true; 191047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 191147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean success = false; 191247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen Rect boundingRect = null; 19138baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // We construct a rect which represents the entire group of views passed in 191447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen for (View v: views) { 19158baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = currentState.map.get(v); 191647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (boundingRect == null) { 19178baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen boundingRect = new Rect(c.x, c.y, c.x + c.spanX, c.y + c.spanY); 191847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } else { 19198baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen boundingRect.union(c.x, c.y, c.x + c.spanX, c.y + c.spanY); 192047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 192147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 192247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 19238baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // Mark the occupied state as false for the group of views we want to move. 1924f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen for (View v: views) { 19258baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = currentState.map.get(v); 19268baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, false); 192747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 192847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 192947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean[][] blockOccupied = new boolean[boundingRect.width()][boundingRect.height()]; 193047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen int top = boundingRect.top; 193147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen int left = boundingRect.left; 19328baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // We mark more precisely which parts of the bounding rect are truly occupied, allowing 1933a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen // for interlocking. 1934f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen for (View v: views) { 19358baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = currentState.map.get(v); 19368baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen markCellsForView(c.x - left, c.y - top, c.spanX, c.spanY, blockOccupied, true); 193747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 193847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 193947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen markCellsForRect(rectOccupiedByPotentialDrop, mTmpOccupied, true); 194047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 1941f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen findNearestArea(boundingRect.left, boundingRect.top, boundingRect.width(), 1942f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen boundingRect.height(), direction, mTmpOccupied, blockOccupied, mTempLocation); 194347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 19448baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // If we successfuly found a location by pushing the block of views, we commit it 194547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (mTempLocation[0] >= 0 && mTempLocation[1] >= 0) { 19468baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen int deltaX = mTempLocation[0] - boundingRect.left; 19478baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen int deltaY = mTempLocation[1] - boundingRect.top; 1948f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen for (View v: views) { 19498baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = currentState.map.get(v); 19508baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen c.x += deltaX; 19518baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen c.y += deltaY; 195247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 195347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen success = true; 195447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 1955482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 19568baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // In either case, we set the occupied array as marked for the location of the views 1957f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen for (View v: views) { 19588baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = currentState.map.get(v); 19598baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, true); 1960482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1961482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return success; 1962482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1963482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1964482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private void markCellsForRect(Rect r, boolean[][] occupied, boolean value) { 1965482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsForView(r.left, r.top, r.width(), r.height(), occupied, value); 1966482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1967482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 19684abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // This method tries to find a reordering solution which satisfies the push mechanic by trying 19694abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // to push items in each of the cardinal directions, in an order based on the direction vector 19704abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // passed. 19714abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen private boolean attemptPushInDirection(ArrayList<View> intersectingViews, Rect occupied, 19724abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen int[] direction, View ignoreView, ItemConfiguration solution) { 19734abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen if ((Math.abs(direction[0]) + Math.abs(direction[1])) > 1) { 19744abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // If the direction vector has two non-zero components, we try pushing 19754abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // separately in each of the components. 19764abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen int temp = direction[1]; 19774abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[1] = 0; 1978f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 1979f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (pushViewsToTempLocation(intersectingViews, occupied, direction, 19804abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen ignoreView, solution)) { 19814abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen return true; 19824abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen } 19834abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[1] = temp; 19844abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen temp = direction[0]; 19854abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[0] = 0; 1986f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 1987f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (pushViewsToTempLocation(intersectingViews, occupied, direction, 19884abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen ignoreView, solution)) { 19894abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen return true; 19904abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen } 19914abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // Revert the direction 19924abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[0] = temp; 19934abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen 19944abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // Now we try pushing in each component of the opposite direction 19954abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[0] *= -1; 19964abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[1] *= -1; 19974abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen temp = direction[1]; 19984abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[1] = 0; 1999f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (pushViewsToTempLocation(intersectingViews, occupied, direction, 20004abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen ignoreView, solution)) { 20014abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen return true; 20024abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen } 20034abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen 20044abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[1] = temp; 20054abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen temp = direction[0]; 20064abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[0] = 0; 2007f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (pushViewsToTempLocation(intersectingViews, occupied, direction, 20084abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen ignoreView, solution)) { 20094abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen return true; 20104abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen } 20114abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // revert the direction 20124abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[0] = temp; 20134abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[0] *= -1; 20144abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[1] *= -1; 20154abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen 20164abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen } else { 20174abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // If the direction vector has a single non-zero component, we push first in the 20184abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // direction of the vector 2019f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (pushViewsToTempLocation(intersectingViews, occupied, direction, 20204abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen ignoreView, solution)) { 20214abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen return true; 20224abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen } 20234abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // Then we try the opposite direction 20244abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[0] *= -1; 20254abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[1] *= -1; 2026f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (pushViewsToTempLocation(intersectingViews, occupied, direction, 20274abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen ignoreView, solution)) { 20284abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen return true; 20294abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen } 20304abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // Switch the direction back 20314abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[0] *= -1; 20324abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[1] *= -1; 20334abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen 20344abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // If we have failed to find a push solution with the above, then we try 20354abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // to find a solution by pushing along the perpendicular axis. 20364abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen 20374abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // Swap the components 20384abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen int temp = direction[1]; 20394abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[1] = direction[0]; 20404abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[0] = temp; 2041f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (pushViewsToTempLocation(intersectingViews, occupied, direction, 20424abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen ignoreView, solution)) { 20434abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen return true; 20444abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen } 20454abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen 20464abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // Then we try the opposite direction 20474abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[0] *= -1; 20484abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[1] *= -1; 2049f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (pushViewsToTempLocation(intersectingViews, occupied, direction, 20504abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen ignoreView, solution)) { 20514abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen return true; 20524abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen } 20534abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // Switch the direction back 20544abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[0] *= -1; 20554abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[1] *= -1; 20564abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen 20574abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // Swap the components back 20584abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen temp = direction[1]; 20594abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[1] = direction[0]; 20604abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[0] = temp; 20614abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen } 20624abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen return false; 20634abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen } 20644abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen 2065482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private boolean rearrangementExists(int cellX, int cellY, int spanX, int spanY, int[] direction, 20668baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen View ignoreView, ItemConfiguration solution) { 2067e3e03bcd313ba8060f2832b6a16dea6fd6d532eaWinson Chung // Return early if get invalid cell positions 2068e3e03bcd313ba8060f2832b6a16dea6fd6d532eaWinson Chung if (cellX < 0 || cellY < 0) return false; 2069482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 20708baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen mIntersectingViews.clear(); 2071482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mOccupiedRect.set(cellX, cellY, cellX + spanX, cellY + spanY); 2072482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 20738baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // Mark the desired location of the view currently being dragged. 2074482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (ignoreView != null) { 20758baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = solution.map.get(ignoreView); 207619f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (c != null) { 207719f3792523fe2d55ea791a9286398a6120920690Adam Cohen c.x = cellX; 207819f3792523fe2d55ea791a9286398a6120920690Adam Cohen c.y = cellY; 207919f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 2080482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2081482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen Rect r0 = new Rect(cellX, cellY, cellX + spanX, cellY + spanY); 2082482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen Rect r1 = new Rect(); 20838baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen for (View child: solution.map.keySet()) { 2084482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (child == ignoreView) continue; 20858baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = solution.map.get(child); 2086482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen LayoutParams lp = (LayoutParams) child.getLayoutParams(); 20878baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen r1.set(c.x, c.y, c.x + c.spanX, c.y + c.spanY); 2088482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (Rect.intersects(r0, r1)) { 2089482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (!lp.canReorder) { 2090482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return false; 2091482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2092482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mIntersectingViews.add(child); 2093482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2094482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 209547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 20964abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // First we try to find a solution which respects the push mechanic. That is, 20974abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // we try to find a solution such that no displaced item travels through another item 20984abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // without also displacing that item. 20994abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen if (attemptPushInDirection(mIntersectingViews, mOccupiedRect, direction, ignoreView, 210019f3792523fe2d55ea791a9286398a6120920690Adam Cohen solution)) { 210147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen return true; 210247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 210347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 21044abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // Next we try moving the views as a block, but without requiring the push mechanic. 2105f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (addViewsToTempLocation(mIntersectingViews, mOccupiedRect, direction, ignoreView, 210619f3792523fe2d55ea791a9286398a6120920690Adam Cohen solution)) { 2107482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return true; 2108482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 210947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 2110482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // Ok, they couldn't move as a block, let's move them individually 2111482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (View v : mIntersectingViews) { 21128baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen if (!addViewToTempLocation(v, mOccupiedRect, direction, solution)) { 2113482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return false; 2114482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2115482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2116482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return true; 2117482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2118482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2119482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen /* 2120482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * Returns a pair (x, y), where x,y are in {-1, 0, 1} corresponding to vector between 2121482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * the provided point and the provided cell 2122482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen */ 212347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen private void computeDirectionVector(float deltaX, float deltaY, int[] result) { 2124482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen double angle = Math.atan(((float) deltaY) / deltaX); 2125482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2126482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result[0] = 0; 2127482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result[1] = 0; 2128482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (Math.abs(Math.cos(angle)) > 0.5f) { 2129482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result[0] = (int) Math.signum(deltaX); 2130482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2131482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (Math.abs(Math.sin(angle)) > 0.5f) { 2132482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result[1] = (int) Math.signum(deltaY); 2133482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2134482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2135482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 21368baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen private void copyOccupiedArray(boolean[][] occupied) { 21378baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen for (int i = 0; i < mCountX; i++) { 21388baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen for (int j = 0; j < mCountY; j++) { 21398baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen occupied[i][j] = mOccupied[i][j]; 21408baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen } 21418baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen } 21428baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen } 21438baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen 2144482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen ItemConfiguration simpleSwap(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, 2145482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int spanY, int[] direction, View dragView, boolean decX, ItemConfiguration solution) { 21468baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // Copy the current state into the solution. This solution will be manipulated as necessary. 21478baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen copyCurrentStateToSolution(solution, false); 21488baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // Copy the current occupied array into the temporary occupied array. This array will be 21498baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // manipulated as necessary to find a solution. 21508baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen copyOccupiedArray(mTmpOccupied); 2151482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2152482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // We find the nearest cell into which we would place the dragged item, assuming there's 2153482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // nothing in its way. 2154482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int result[] = new int[2]; 2155482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result = findNearestArea(pixelX, pixelY, spanX, spanY, result); 2156482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2157482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean success = false; 2158482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // First we try the exact nearest position of the item being dragged, 2159482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // we will then want to try to move this around to other neighbouring positions 21608baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen success = rearrangementExists(result[0], result[1], spanX, spanY, direction, dragView, 21618baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen solution); 2162482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2163482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (!success) { 2164482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // We try shrinking the widget down to size in an alternating pattern, shrink 1 in 2165482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // x, then 1 in y etc. 2166482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (spanX > minSpanX && (minSpanY == spanY || decX)) { 2167482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return simpleSwap(pixelX, pixelY, minSpanX, minSpanY, spanX - 1, spanY, direction, 2168482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen dragView, false, solution); 2169482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } else if (spanY > minSpanY) { 2170482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return simpleSwap(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY - 1, direction, 2171482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen dragView, true, solution); 2172482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2173482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.isSolution = false; 2174482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } else { 2175482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.isSolution = true; 2176482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewX = result[0]; 2177482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewY = result[1]; 2178482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewSpanX = spanX; 2179482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewSpanY = spanY; 2180482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2181482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return solution; 2182482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2183482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2184482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private void copyCurrentStateToSolution(ItemConfiguration solution, boolean temp) { 2185a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka int childCount = mShortcutsAndWidgets.getChildCount(); 2186482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < childCount; i++) { 2187a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka View child = mShortcutsAndWidgets.getChildAt(i); 2188482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen LayoutParams lp = (LayoutParams) child.getLayoutParams(); 21898baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c; 2190482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (temp) { 21918baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen c = new CellAndSpan(lp.tmpCellX, lp.tmpCellY, lp.cellHSpan, lp.cellVSpan); 2192482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } else { 21938baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen c = new CellAndSpan(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan); 2194482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2195f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen solution.add(child, c); 2196482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2197482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2198482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2199482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private void copySolutionToTempState(ItemConfiguration solution, View dragView) { 2200482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < mCountX; i++) { 2201482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int j = 0; j < mCountY; j++) { 2202482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mTmpOccupied[i][j] = false; 2203482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2204482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2205482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2206a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka int childCount = mShortcutsAndWidgets.getChildCount(); 2207482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < childCount; i++) { 2208a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka View child = mShortcutsAndWidgets.getChildAt(i); 2209482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (child == dragView) continue; 2210482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen LayoutParams lp = (LayoutParams) child.getLayoutParams(); 22118baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = solution.map.get(child); 22128baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen if (c != null) { 22138baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen lp.tmpCellX = c.x; 22148baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen lp.tmpCellY = c.y; 22158baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen lp.cellHSpan = c.spanX; 22168baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen lp.cellVSpan = c.spanY; 22178baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, true); 2218482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2219482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2220482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsForView(solution.dragViewX, solution.dragViewY, solution.dragViewSpanX, 2221482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewSpanY, mTmpOccupied, true); 2222482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2223482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2224482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private void animateItemsToSolution(ItemConfiguration solution, View dragView, boolean 2225482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen commitDragView) { 2226482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2227482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean[][] occupied = DESTRUCTIVE_REORDER ? mOccupied : mTmpOccupied; 2228482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < mCountX; i++) { 2229482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int j = 0; j < mCountY; j++) { 2230482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen occupied[i][j] = false; 2231482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2232482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2233482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2234a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka int childCount = mShortcutsAndWidgets.getChildCount(); 2235482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < childCount; i++) { 2236a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka View child = mShortcutsAndWidgets.getChildAt(i); 2237482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (child == dragView) continue; 22388baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = solution.map.get(child); 22398baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen if (c != null) { 224019f3792523fe2d55ea791a9286398a6120920690Adam Cohen animateChildToPosition(child, c.x, c.y, REORDER_ANIMATION_DURATION, 0, 224119f3792523fe2d55ea791a9286398a6120920690Adam Cohen DESTRUCTIVE_REORDER, false); 22428baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen markCellsForView(c.x, c.y, c.spanX, c.spanY, occupied, true); 2243482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2244482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2245482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (commitDragView) { 2246482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsForView(solution.dragViewX, solution.dragViewY, solution.dragViewSpanX, 2247482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewSpanY, occupied, true); 2248482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2249482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2250482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 225119f3792523fe2d55ea791a9286398a6120920690Adam Cohen // This method starts or changes the reorder hint animations 225219f3792523fe2d55ea791a9286398a6120920690Adam Cohen private void beginOrAdjustHintAnimations(ItemConfiguration solution, View dragView, int delay) { 225319f3792523fe2d55ea791a9286398a6120920690Adam Cohen int childCount = mShortcutsAndWidgets.getChildCount(); 225419f3792523fe2d55ea791a9286398a6120920690Adam Cohen for (int i = 0; i < childCount; i++) { 225519f3792523fe2d55ea791a9286398a6120920690Adam Cohen View child = mShortcutsAndWidgets.getChildAt(i); 225619f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (child == dragView) continue; 225719f3792523fe2d55ea791a9286398a6120920690Adam Cohen CellAndSpan c = solution.map.get(child); 225819f3792523fe2d55ea791a9286398a6120920690Adam Cohen LayoutParams lp = (LayoutParams) child.getLayoutParams(); 225919f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (c != null) { 226019f3792523fe2d55ea791a9286398a6120920690Adam Cohen ReorderHintAnimation rha = new ReorderHintAnimation(child, lp.cellX, lp.cellY, 226119f3792523fe2d55ea791a9286398a6120920690Adam Cohen c.x, c.y, c.spanX, c.spanY); 2262d024f9845a0974ab525baad085f316031cd5a742Adam Cohen rha.animate(); 226319f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 226419f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 226519f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 226619f3792523fe2d55ea791a9286398a6120920690Adam Cohen 226719f3792523fe2d55ea791a9286398a6120920690Adam Cohen // Class which represents the reorder hint animations. These animations show that an item is 226819f3792523fe2d55ea791a9286398a6120920690Adam Cohen // in a temporary state, and hint at where the item will return to. 226919f3792523fe2d55ea791a9286398a6120920690Adam Cohen class ReorderHintAnimation { 227019f3792523fe2d55ea791a9286398a6120920690Adam Cohen View child; 2271d024f9845a0974ab525baad085f316031cd5a742Adam Cohen float finalDeltaX; 2272d024f9845a0974ab525baad085f316031cd5a742Adam Cohen float finalDeltaY; 2273d024f9845a0974ab525baad085f316031cd5a742Adam Cohen float initDeltaX; 2274d024f9845a0974ab525baad085f316031cd5a742Adam Cohen float initDeltaY; 2275d024f9845a0974ab525baad085f316031cd5a742Adam Cohen float finalScale; 2276d024f9845a0974ab525baad085f316031cd5a742Adam Cohen float initScale; 227750e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely private static final int DURATION = 300; 2278e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen Animator a; 227919f3792523fe2d55ea791a9286398a6120920690Adam Cohen 228019f3792523fe2d55ea791a9286398a6120920690Adam Cohen public ReorderHintAnimation(View child, int cellX0, int cellY0, int cellX1, int cellY1, 228119f3792523fe2d55ea791a9286398a6120920690Adam Cohen int spanX, int spanY) { 228219f3792523fe2d55ea791a9286398a6120920690Adam Cohen regionToCenterPoint(cellX0, cellY0, spanX, spanY, mTmpPoint); 228319f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int x0 = mTmpPoint[0]; 228419f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int y0 = mTmpPoint[1]; 228519f3792523fe2d55ea791a9286398a6120920690Adam Cohen regionToCenterPoint(cellX1, cellY1, spanX, spanY, mTmpPoint); 228619f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int x1 = mTmpPoint[0]; 228719f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int y1 = mTmpPoint[1]; 228819f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int dX = x1 - x0; 228919f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int dY = y1 - y0; 2290d024f9845a0974ab525baad085f316031cd5a742Adam Cohen finalDeltaX = 0; 2291d024f9845a0974ab525baad085f316031cd5a742Adam Cohen finalDeltaY = 0; 229219f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (dX == dY && dX == 0) { 229319f3792523fe2d55ea791a9286398a6120920690Adam Cohen } else { 229419f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (dY == 0) { 2295d024f9845a0974ab525baad085f316031cd5a742Adam Cohen finalDeltaX = - Math.signum(dX) * mReorderHintAnimationMagnitude; 229619f3792523fe2d55ea791a9286398a6120920690Adam Cohen } else if (dX == 0) { 2297d024f9845a0974ab525baad085f316031cd5a742Adam Cohen finalDeltaY = - Math.signum(dY) * mReorderHintAnimationMagnitude; 229819f3792523fe2d55ea791a9286398a6120920690Adam Cohen } else { 229919f3792523fe2d55ea791a9286398a6120920690Adam Cohen double angle = Math.atan( (float) (dY) / dX); 2300d024f9845a0974ab525baad085f316031cd5a742Adam Cohen finalDeltaX = (int) (- Math.signum(dX) * 2301fe41ac641bdef7ea96dcbac59b4f3abdbdff6cfeAdam Cohen Math.abs(Math.cos(angle) * mReorderHintAnimationMagnitude)); 2302d024f9845a0974ab525baad085f316031cd5a742Adam Cohen finalDeltaY = (int) (- Math.signum(dY) * 2303fe41ac641bdef7ea96dcbac59b4f3abdbdff6cfeAdam Cohen Math.abs(Math.sin(angle) * mReorderHintAnimationMagnitude)); 230419f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 230519f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 2306d024f9845a0974ab525baad085f316031cd5a742Adam Cohen initDeltaX = child.getTranslationX(); 2307d024f9845a0974ab525baad085f316031cd5a742Adam Cohen initDeltaY = child.getTranslationY(); 2308307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen finalScale = getChildrenScale() - 4.0f / child.getWidth(); 2309d024f9845a0974ab525baad085f316031cd5a742Adam Cohen initScale = child.getScaleX(); 231019f3792523fe2d55ea791a9286398a6120920690Adam Cohen this.child = child; 231119f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 231219f3792523fe2d55ea791a9286398a6120920690Adam Cohen 2313d024f9845a0974ab525baad085f316031cd5a742Adam Cohen void animate() { 231419f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (mShakeAnimators.containsKey(child)) { 231519f3792523fe2d55ea791a9286398a6120920690Adam Cohen ReorderHintAnimation oldAnimation = mShakeAnimators.get(child); 2316d024f9845a0974ab525baad085f316031cd5a742Adam Cohen oldAnimation.cancel(); 231719f3792523fe2d55ea791a9286398a6120920690Adam Cohen mShakeAnimators.remove(child); 2318e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen if (finalDeltaX == 0 && finalDeltaY == 0) { 2319e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen completeAnimationImmediately(); 2320e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen return; 2321e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen } 232219f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 2323d024f9845a0974ab525baad085f316031cd5a742Adam Cohen if (finalDeltaX == 0 && finalDeltaY == 0) { 232419f3792523fe2d55ea791a9286398a6120920690Adam Cohen return; 232519f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 23262ecf995e0d2d55eb71d03f7230ca87270872d1a3Michael Jurka ValueAnimator va = LauncherAnimUtils.ofFloat(0f, 1f); 2327e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen a = va; 232819f3792523fe2d55ea791a9286398a6120920690Adam Cohen va.setRepeatMode(ValueAnimator.REVERSE); 232919f3792523fe2d55ea791a9286398a6120920690Adam Cohen va.setRepeatCount(ValueAnimator.INFINITE); 23307bdfc9700b1cad043c04c757f134db1bf3df00daAdam Cohen va.setDuration(DURATION); 2331d024f9845a0974ab525baad085f316031cd5a742Adam Cohen va.setStartDelay((int) (Math.random() * 60)); 233219f3792523fe2d55ea791a9286398a6120920690Adam Cohen va.addUpdateListener(new AnimatorUpdateListener() { 233319f3792523fe2d55ea791a9286398a6120920690Adam Cohen @Override 233419f3792523fe2d55ea791a9286398a6120920690Adam Cohen public void onAnimationUpdate(ValueAnimator animation) { 233519f3792523fe2d55ea791a9286398a6120920690Adam Cohen float r = ((Float) animation.getAnimatedValue()).floatValue(); 2336d024f9845a0974ab525baad085f316031cd5a742Adam Cohen float x = r * finalDeltaX + (1 - r) * initDeltaX; 2337d024f9845a0974ab525baad085f316031cd5a742Adam Cohen float y = r * finalDeltaY + (1 - r) * initDeltaY; 233819f3792523fe2d55ea791a9286398a6120920690Adam Cohen child.setTranslationX(x); 233919f3792523fe2d55ea791a9286398a6120920690Adam Cohen child.setTranslationY(y); 2340d024f9845a0974ab525baad085f316031cd5a742Adam Cohen float s = r * finalScale + (1 - r) * initScale; 234150e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely child.setScaleX(s); 234250e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely child.setScaleY(s); 234319f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 234419f3792523fe2d55ea791a9286398a6120920690Adam Cohen }); 234519f3792523fe2d55ea791a9286398a6120920690Adam Cohen va.addListener(new AnimatorListenerAdapter() { 234619f3792523fe2d55ea791a9286398a6120920690Adam Cohen public void onAnimationRepeat(Animator animation) { 234719f3792523fe2d55ea791a9286398a6120920690Adam Cohen // We make sure to end only after a full period 2348d024f9845a0974ab525baad085f316031cd5a742Adam Cohen initDeltaX = 0; 2349d024f9845a0974ab525baad085f316031cd5a742Adam Cohen initDeltaY = 0; 2350307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen initScale = getChildrenScale(); 235119f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 235219f3792523fe2d55ea791a9286398a6120920690Adam Cohen }); 235319f3792523fe2d55ea791a9286398a6120920690Adam Cohen mShakeAnimators.put(child, this); 235419f3792523fe2d55ea791a9286398a6120920690Adam Cohen va.start(); 235519f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 235619f3792523fe2d55ea791a9286398a6120920690Adam Cohen 2357d024f9845a0974ab525baad085f316031cd5a742Adam Cohen private void cancel() { 2358e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen if (a != null) { 2359e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen a.cancel(); 2360e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen } 236119f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 2362e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen 236350e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely private void completeAnimationImmediately() { 2364e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen if (a != null) { 2365e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen a.cancel(); 2366e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen } 236750e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely 23682ecf995e0d2d55eb71d03f7230ca87270872d1a3Michael Jurka AnimatorSet s = LauncherAnimUtils.createAnimatorSet(); 2369e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen a = s; 237050e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely s.playTogether( 2371307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen LauncherAnimUtils.ofFloat(child, "scaleX", getChildrenScale()), 2372307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen LauncherAnimUtils.ofFloat(child, "scaleY", getChildrenScale()), 23732ecf995e0d2d55eb71d03f7230ca87270872d1a3Michael Jurka LauncherAnimUtils.ofFloat(child, "translationX", 0f), 23742ecf995e0d2d55eb71d03f7230ca87270872d1a3Michael Jurka LauncherAnimUtils.ofFloat(child, "translationY", 0f) 237550e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely ); 237650e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely s.setDuration(REORDER_ANIMATION_DURATION); 237750e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely s.setInterpolator(new android.view.animation.DecelerateInterpolator(1.5f)); 237850e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely s.start(); 237950e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely } 238019f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 238119f3792523fe2d55ea791a9286398a6120920690Adam Cohen 238219f3792523fe2d55ea791a9286398a6120920690Adam Cohen private void completeAndClearReorderHintAnimations() { 238319f3792523fe2d55ea791a9286398a6120920690Adam Cohen for (ReorderHintAnimation a: mShakeAnimators.values()) { 238450e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely a.completeAnimationImmediately(); 238519f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 238619f3792523fe2d55ea791a9286398a6120920690Adam Cohen mShakeAnimators.clear(); 238719f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 238819f3792523fe2d55ea791a9286398a6120920690Adam Cohen 2389482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private void commitTempPlacement() { 2390482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < mCountX; i++) { 2391482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int j = 0; j < mCountY; j++) { 2392482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mOccupied[i][j] = mTmpOccupied[i][j]; 2393482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2394482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2395a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka int childCount = mShortcutsAndWidgets.getChildCount(); 2396482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < childCount; i++) { 2397ea889a294be004f4b1c21e9b874f9e63abfb8bd6Adam Cohen View child = mShortcutsAndWidgets.getChildAt(i); 2398ea889a294be004f4b1c21e9b874f9e63abfb8bd6Adam Cohen LayoutParams lp = (LayoutParams) child.getLayoutParams(); 2399ea889a294be004f4b1c21e9b874f9e63abfb8bd6Adam Cohen ItemInfo info = (ItemInfo) child.getTag(); 24002acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen // We do a null check here because the item info can be null in the case of the 24012acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen // AllApps button in the hotseat. 24022acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen if (info != null) { 2403487f7dd3059621527eb439d7d51d34e00293f9b1Adam Cohen if (info.cellX != lp.tmpCellX || info.cellY != lp.tmpCellY || 2404487f7dd3059621527eb439d7d51d34e00293f9b1Adam Cohen info.spanX != lp.cellHSpan || info.spanY != lp.cellVSpan) { 2405487f7dd3059621527eb439d7d51d34e00293f9b1Adam Cohen info.requiresDbUpdate = true; 2406487f7dd3059621527eb439d7d51d34e00293f9b1Adam Cohen } 24072acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen info.cellX = lp.cellX = lp.tmpCellX; 24082acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen info.cellY = lp.cellY = lp.tmpCellY; 2409bebf042666cffe52039b875a549a582abd78a431Adam Cohen info.spanX = lp.cellHSpan; 2410bebf042666cffe52039b875a549a582abd78a431Adam Cohen info.spanY = lp.cellVSpan; 24112acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen } 2412482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 24132acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen mLauncher.getWorkspace().updateItemLocationsInDatabase(this); 2414482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2415482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2416482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public void setUseTempCoords(boolean useTempCoords) { 2417a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka int childCount = mShortcutsAndWidgets.getChildCount(); 2418482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < childCount; i++) { 2419a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka LayoutParams lp = (LayoutParams) mShortcutsAndWidgets.getChildAt(i).getLayoutParams(); 2420482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen lp.useTmpCoords = useTempCoords; 2421482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2422482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2423482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2424482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen ItemConfiguration findConfigurationNoShuffle(int pixelX, int pixelY, int minSpanX, int minSpanY, 2425482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int spanX, int spanY, View dragView, ItemConfiguration solution) { 2426482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int[] result = new int[2]; 2427482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int[] resultSpan = new int[2]; 2428482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen findNearestVacantArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, null, result, 2429482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen resultSpan); 2430482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (result[0] >= 0 && result[1] >= 0) { 2431482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen copyCurrentStateToSolution(solution, false); 2432482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewX = result[0]; 2433482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewY = result[1]; 2434482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewSpanX = resultSpan[0]; 2435482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewSpanY = resultSpan[1]; 2436482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.isSolution = true; 2437482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } else { 2438482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.isSolution = false; 2439482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2440482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return solution; 2441482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2442482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2443482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public void prepareChildForDrag(View child) { 2444482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsAsUnoccupiedForView(child); 2445482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2446482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 244719f3792523fe2d55ea791a9286398a6120920690Adam Cohen /* This seems like it should be obvious and straight-forward, but when the direction vector 244819f3792523fe2d55ea791a9286398a6120920690Adam Cohen needs to match with the notion of the dragView pushing other views, we have to employ 244919f3792523fe2d55ea791a9286398a6120920690Adam Cohen a slightly more subtle notion of the direction vector. The question is what two points is 245019f3792523fe2d55ea791a9286398a6120920690Adam Cohen the vector between? The center of the dragView and its desired destination? Not quite, as 245119f3792523fe2d55ea791a9286398a6120920690Adam Cohen this doesn't necessarily coincide with the interaction of the dragView and items occupying 245219f3792523fe2d55ea791a9286398a6120920690Adam Cohen those cells. Instead we use some heuristics to often lock the vector to up, down, left 245319f3792523fe2d55ea791a9286398a6120920690Adam Cohen or right, which helps make pushing feel right. 245419f3792523fe2d55ea791a9286398a6120920690Adam Cohen */ 245519f3792523fe2d55ea791a9286398a6120920690Adam Cohen private void getDirectionVectorForDrop(int dragViewCenterX, int dragViewCenterY, int spanX, 245619f3792523fe2d55ea791a9286398a6120920690Adam Cohen int spanY, View dragView, int[] resultDirection) { 245719f3792523fe2d55ea791a9286398a6120920690Adam Cohen int[] targetDestination = new int[2]; 245819f3792523fe2d55ea791a9286398a6120920690Adam Cohen 245919f3792523fe2d55ea791a9286398a6120920690Adam Cohen findNearestArea(dragViewCenterX, dragViewCenterY, spanX, spanY, targetDestination); 246019f3792523fe2d55ea791a9286398a6120920690Adam Cohen Rect dragRect = new Rect(); 246119f3792523fe2d55ea791a9286398a6120920690Adam Cohen regionToRect(targetDestination[0], targetDestination[1], spanX, spanY, dragRect); 246219f3792523fe2d55ea791a9286398a6120920690Adam Cohen dragRect.offset(dragViewCenterX - dragRect.centerX(), dragViewCenterY - dragRect.centerY()); 246319f3792523fe2d55ea791a9286398a6120920690Adam Cohen 246419f3792523fe2d55ea791a9286398a6120920690Adam Cohen Rect dropRegionRect = new Rect(); 246519f3792523fe2d55ea791a9286398a6120920690Adam Cohen getViewsIntersectingRegion(targetDestination[0], targetDestination[1], spanX, spanY, 246619f3792523fe2d55ea791a9286398a6120920690Adam Cohen dragView, dropRegionRect, mIntersectingViews); 246719f3792523fe2d55ea791a9286398a6120920690Adam Cohen 246819f3792523fe2d55ea791a9286398a6120920690Adam Cohen int dropRegionSpanX = dropRegionRect.width(); 246919f3792523fe2d55ea791a9286398a6120920690Adam Cohen int dropRegionSpanY = dropRegionRect.height(); 247019f3792523fe2d55ea791a9286398a6120920690Adam Cohen 247119f3792523fe2d55ea791a9286398a6120920690Adam Cohen regionToRect(dropRegionRect.left, dropRegionRect.top, dropRegionRect.width(), 247219f3792523fe2d55ea791a9286398a6120920690Adam Cohen dropRegionRect.height(), dropRegionRect); 247319f3792523fe2d55ea791a9286398a6120920690Adam Cohen 247419f3792523fe2d55ea791a9286398a6120920690Adam Cohen int deltaX = (dropRegionRect.centerX() - dragViewCenterX) / spanX; 247519f3792523fe2d55ea791a9286398a6120920690Adam Cohen int deltaY = (dropRegionRect.centerY() - dragViewCenterY) / spanY; 247619f3792523fe2d55ea791a9286398a6120920690Adam Cohen 247719f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (dropRegionSpanX == mCountX || spanX == mCountX) { 247819f3792523fe2d55ea791a9286398a6120920690Adam Cohen deltaX = 0; 247919f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 248019f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (dropRegionSpanY == mCountY || spanY == mCountY) { 248119f3792523fe2d55ea791a9286398a6120920690Adam Cohen deltaY = 0; 248219f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 248319f3792523fe2d55ea791a9286398a6120920690Adam Cohen 248419f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (deltaX == 0 && deltaY == 0) { 248519f3792523fe2d55ea791a9286398a6120920690Adam Cohen // No idea what to do, give a random direction. 248619f3792523fe2d55ea791a9286398a6120920690Adam Cohen resultDirection[0] = 1; 248719f3792523fe2d55ea791a9286398a6120920690Adam Cohen resultDirection[1] = 0; 248819f3792523fe2d55ea791a9286398a6120920690Adam Cohen } else { 248919f3792523fe2d55ea791a9286398a6120920690Adam Cohen computeDirectionVector(deltaX, deltaY, resultDirection); 249019f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 249119f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 249219f3792523fe2d55ea791a9286398a6120920690Adam Cohen 249319f3792523fe2d55ea791a9286398a6120920690Adam Cohen // For a given cell and span, fetch the set of views intersecting the region. 249419f3792523fe2d55ea791a9286398a6120920690Adam Cohen private void getViewsIntersectingRegion(int cellX, int cellY, int spanX, int spanY, 249519f3792523fe2d55ea791a9286398a6120920690Adam Cohen View dragView, Rect boundingRect, ArrayList<View> intersectingViews) { 249619f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (boundingRect != null) { 249719f3792523fe2d55ea791a9286398a6120920690Adam Cohen boundingRect.set(cellX, cellY, cellX + spanX, cellY + spanY); 249819f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 249919f3792523fe2d55ea791a9286398a6120920690Adam Cohen intersectingViews.clear(); 250019f3792523fe2d55ea791a9286398a6120920690Adam Cohen Rect r0 = new Rect(cellX, cellY, cellX + spanX, cellY + spanY); 250119f3792523fe2d55ea791a9286398a6120920690Adam Cohen Rect r1 = new Rect(); 250219f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int count = mShortcutsAndWidgets.getChildCount(); 250319f3792523fe2d55ea791a9286398a6120920690Adam Cohen for (int i = 0; i < count; i++) { 250419f3792523fe2d55ea791a9286398a6120920690Adam Cohen View child = mShortcutsAndWidgets.getChildAt(i); 250519f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (child == dragView) continue; 250619f3792523fe2d55ea791a9286398a6120920690Adam Cohen LayoutParams lp = (LayoutParams) child.getLayoutParams(); 250719f3792523fe2d55ea791a9286398a6120920690Adam Cohen r1.set(lp.cellX, lp.cellY, lp.cellX + lp.cellHSpan, lp.cellY + lp.cellVSpan); 250819f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (Rect.intersects(r0, r1)) { 250919f3792523fe2d55ea791a9286398a6120920690Adam Cohen mIntersectingViews.add(child); 251019f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (boundingRect != null) { 251119f3792523fe2d55ea791a9286398a6120920690Adam Cohen boundingRect.union(r1); 251219f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 251319f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 251419f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 251519f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 251619f3792523fe2d55ea791a9286398a6120920690Adam Cohen 251719f3792523fe2d55ea791a9286398a6120920690Adam Cohen boolean isNearestDropLocationOccupied(int pixelX, int pixelY, int spanX, int spanY, 251819f3792523fe2d55ea791a9286398a6120920690Adam Cohen View dragView, int[] result) { 251919f3792523fe2d55ea791a9286398a6120920690Adam Cohen result = findNearestArea(pixelX, pixelY, spanX, spanY, result); 252019f3792523fe2d55ea791a9286398a6120920690Adam Cohen getViewsIntersectingRegion(result[0], result[1], spanX, spanY, dragView, null, 252119f3792523fe2d55ea791a9286398a6120920690Adam Cohen mIntersectingViews); 252219f3792523fe2d55ea791a9286398a6120920690Adam Cohen return !mIntersectingViews.isEmpty(); 252319f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 252419f3792523fe2d55ea791a9286398a6120920690Adam Cohen 252519f3792523fe2d55ea791a9286398a6120920690Adam Cohen void revertTempState() { 252619f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (!isItemPlacementDirty() || DESTRUCTIVE_REORDER) return; 252719f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int count = mShortcutsAndWidgets.getChildCount(); 252819f3792523fe2d55ea791a9286398a6120920690Adam Cohen for (int i = 0; i < count; i++) { 252919f3792523fe2d55ea791a9286398a6120920690Adam Cohen View child = mShortcutsAndWidgets.getChildAt(i); 253019f3792523fe2d55ea791a9286398a6120920690Adam Cohen LayoutParams lp = (LayoutParams) child.getLayoutParams(); 253119f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (lp.tmpCellX != lp.cellX || lp.tmpCellY != lp.cellY) { 253219f3792523fe2d55ea791a9286398a6120920690Adam Cohen lp.tmpCellX = lp.cellX; 253319f3792523fe2d55ea791a9286398a6120920690Adam Cohen lp.tmpCellY = lp.cellY; 253419f3792523fe2d55ea791a9286398a6120920690Adam Cohen animateChildToPosition(child, lp.cellX, lp.cellY, REORDER_ANIMATION_DURATION, 253519f3792523fe2d55ea791a9286398a6120920690Adam Cohen 0, false, false); 253619f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 253719f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 253819f3792523fe2d55ea791a9286398a6120920690Adam Cohen completeAndClearReorderHintAnimations(); 253919f3792523fe2d55ea791a9286398a6120920690Adam Cohen setItemPlacementDirty(false); 254019f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 254119f3792523fe2d55ea791a9286398a6120920690Adam Cohen 2542bebf042666cffe52039b875a549a582abd78a431Adam Cohen boolean createAreaForResize(int cellX, int cellY, int spanX, int spanY, 2543bebf042666cffe52039b875a549a582abd78a431Adam Cohen View dragView, int[] direction, boolean commit) { 2544bebf042666cffe52039b875a549a582abd78a431Adam Cohen int[] pixelXY = new int[2]; 2545bebf042666cffe52039b875a549a582abd78a431Adam Cohen regionToCenterPoint(cellX, cellY, spanX, spanY, pixelXY); 2546bebf042666cffe52039b875a549a582abd78a431Adam Cohen 2547bebf042666cffe52039b875a549a582abd78a431Adam Cohen // First we determine if things have moved enough to cause a different layout 2548bebf042666cffe52039b875a549a582abd78a431Adam Cohen ItemConfiguration swapSolution = simpleSwap(pixelXY[0], pixelXY[1], spanX, spanY, 2549bebf042666cffe52039b875a549a582abd78a431Adam Cohen spanX, spanY, direction, dragView, true, new ItemConfiguration()); 2550bebf042666cffe52039b875a549a582abd78a431Adam Cohen 2551bebf042666cffe52039b875a549a582abd78a431Adam Cohen setUseTempCoords(true); 2552bebf042666cffe52039b875a549a582abd78a431Adam Cohen if (swapSolution != null && swapSolution.isSolution) { 2553bebf042666cffe52039b875a549a582abd78a431Adam Cohen // If we're just testing for a possible location (MODE_ACCEPT_DROP), we don't bother 2554bebf042666cffe52039b875a549a582abd78a431Adam Cohen // committing anything or animating anything as we just want to determine if a solution 2555bebf042666cffe52039b875a549a582abd78a431Adam Cohen // exists 2556bebf042666cffe52039b875a549a582abd78a431Adam Cohen copySolutionToTempState(swapSolution, dragView); 2557bebf042666cffe52039b875a549a582abd78a431Adam Cohen setItemPlacementDirty(true); 2558bebf042666cffe52039b875a549a582abd78a431Adam Cohen animateItemsToSolution(swapSolution, dragView, commit); 2559bebf042666cffe52039b875a549a582abd78a431Adam Cohen 2560bebf042666cffe52039b875a549a582abd78a431Adam Cohen if (commit) { 2561bebf042666cffe52039b875a549a582abd78a431Adam Cohen commitTempPlacement(); 2562bebf042666cffe52039b875a549a582abd78a431Adam Cohen completeAndClearReorderHintAnimations(); 2563bebf042666cffe52039b875a549a582abd78a431Adam Cohen setItemPlacementDirty(false); 2564bebf042666cffe52039b875a549a582abd78a431Adam Cohen } else { 2565bebf042666cffe52039b875a549a582abd78a431Adam Cohen beginOrAdjustHintAnimations(swapSolution, dragView, 2566bebf042666cffe52039b875a549a582abd78a431Adam Cohen REORDER_ANIMATION_DURATION); 2567bebf042666cffe52039b875a549a582abd78a431Adam Cohen } 2568bebf042666cffe52039b875a549a582abd78a431Adam Cohen mShortcutsAndWidgets.requestLayout(); 2569bebf042666cffe52039b875a549a582abd78a431Adam Cohen } 2570bebf042666cffe52039b875a549a582abd78a431Adam Cohen return swapSolution.isSolution; 2571bebf042666cffe52039b875a549a582abd78a431Adam Cohen } 2572bebf042666cffe52039b875a549a582abd78a431Adam Cohen 2573482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int[] createArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, int spanY, 2574482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen View dragView, int[] result, int resultSpan[], int mode) { 2575482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // First we determine if things have moved enough to cause a different layout 257647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen result = findNearestArea(pixelX, pixelY, spanX, spanY, result); 2577482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2578482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (resultSpan == null) { 2579482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen resultSpan = new int[2]; 2580482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2581482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 258219f3792523fe2d55ea791a9286398a6120920690Adam Cohen // When we are checking drop validity or actually dropping, we don't recompute the 258319f3792523fe2d55ea791a9286398a6120920690Adam Cohen // direction vector, since we want the solution to match the preview, and it's possible 258419f3792523fe2d55ea791a9286398a6120920690Adam Cohen // that the exact position of the item has changed to result in a new reordering outcome. 2585b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen if ((mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL || mode == MODE_ACCEPT_DROP) 2586b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen && mPreviousReorderDirection[0] != INVALID_DIRECTION) { 258719f3792523fe2d55ea791a9286398a6120920690Adam Cohen mDirectionVector[0] = mPreviousReorderDirection[0]; 258819f3792523fe2d55ea791a9286398a6120920690Adam Cohen mDirectionVector[1] = mPreviousReorderDirection[1]; 258919f3792523fe2d55ea791a9286398a6120920690Adam Cohen // We reset this vector after drop 2590b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen if (mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL) { 2591b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen mPreviousReorderDirection[0] = INVALID_DIRECTION; 2592b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen mPreviousReorderDirection[1] = INVALID_DIRECTION; 259319f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 259419f3792523fe2d55ea791a9286398a6120920690Adam Cohen } else { 259519f3792523fe2d55ea791a9286398a6120920690Adam Cohen getDirectionVectorForDrop(pixelX, pixelY, spanX, spanY, dragView, mDirectionVector); 259619f3792523fe2d55ea791a9286398a6120920690Adam Cohen mPreviousReorderDirection[0] = mDirectionVector[0]; 259719f3792523fe2d55ea791a9286398a6120920690Adam Cohen mPreviousReorderDirection[1] = mDirectionVector[1]; 259819f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 259919f3792523fe2d55ea791a9286398a6120920690Adam Cohen 2600482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen ItemConfiguration swapSolution = simpleSwap(pixelX, pixelY, minSpanX, minSpanY, 2601482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen spanX, spanY, mDirectionVector, dragView, true, new ItemConfiguration()); 2602482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2603482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // We attempt the approach which doesn't shuffle views at all 2604482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen ItemConfiguration noShuffleSolution = findConfigurationNoShuffle(pixelX, pixelY, minSpanX, 2605482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen minSpanY, spanX, spanY, dragView, new ItemConfiguration()); 2606482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2607482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen ItemConfiguration finalSolution = null; 2608482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (swapSolution.isSolution && swapSolution.area() >= noShuffleSolution.area()) { 2609482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen finalSolution = swapSolution; 2610482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } else if (noShuffleSolution.isSolution) { 2611482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen finalSolution = noShuffleSolution; 2612482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2613482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2614482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean foundSolution = true; 2615482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (!DESTRUCTIVE_REORDER) { 2616482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen setUseTempCoords(true); 2617482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2618482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2619482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (finalSolution != null) { 2620482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result[0] = finalSolution.dragViewX; 2621482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result[1] = finalSolution.dragViewY; 2622482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen resultSpan[0] = finalSolution.dragViewSpanX; 2623482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen resultSpan[1] = finalSolution.dragViewSpanY; 2624482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2625482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // If we're just testing for a possible location (MODE_ACCEPT_DROP), we don't bother 2626482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // committing anything or animating anything as we just want to determine if a solution 2627482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // exists 2628482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (mode == MODE_DRAG_OVER || mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL) { 2629482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (!DESTRUCTIVE_REORDER) { 2630482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen copySolutionToTempState(finalSolution, dragView); 2631482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2632482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen setItemPlacementDirty(true); 2633482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen animateItemsToSolution(finalSolution, dragView, mode == MODE_ON_DROP); 2634482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 263519f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (!DESTRUCTIVE_REORDER && 263619f3792523fe2d55ea791a9286398a6120920690Adam Cohen (mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL)) { 2637482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen commitTempPlacement(); 263819f3792523fe2d55ea791a9286398a6120920690Adam Cohen completeAndClearReorderHintAnimations(); 263919f3792523fe2d55ea791a9286398a6120920690Adam Cohen setItemPlacementDirty(false); 264019f3792523fe2d55ea791a9286398a6120920690Adam Cohen } else { 264119f3792523fe2d55ea791a9286398a6120920690Adam Cohen beginOrAdjustHintAnimations(finalSolution, dragView, 264219f3792523fe2d55ea791a9286398a6120920690Adam Cohen REORDER_ANIMATION_DURATION); 2643482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2644482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2645482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } else { 2646482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen foundSolution = false; 2647482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result[0] = result[1] = resultSpan[0] = resultSpan[1] = -1; 2648482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2649482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2650482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if ((mode == MODE_ON_DROP || !foundSolution) && !DESTRUCTIVE_REORDER) { 2651482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen setUseTempCoords(false); 2652482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2653482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2654a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.requestLayout(); 2655482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return result; 2656482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2657482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 265819f3792523fe2d55ea791a9286398a6120920690Adam Cohen void setItemPlacementDirty(boolean dirty) { 265919f3792523fe2d55ea791a9286398a6120920690Adam Cohen mItemPlacementDirty = dirty; 2660482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 266119f3792523fe2d55ea791a9286398a6120920690Adam Cohen boolean isItemPlacementDirty() { 266219f3792523fe2d55ea791a9286398a6120920690Adam Cohen return mItemPlacementDirty; 2663482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2664482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2665482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private class ItemConfiguration { 26668baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen HashMap<View, CellAndSpan> map = new HashMap<View, CellAndSpan>(); 2667f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen private HashMap<View, CellAndSpan> savedMap = new HashMap<View, CellAndSpan>(); 2668f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen ArrayList<View> sortedViews = new ArrayList<View>(); 2669482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean isSolution = false; 2670482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int dragViewX, dragViewY, dragViewSpanX, dragViewSpanY; 2671482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2672f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen void save() { 2673f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen // Copy current state into savedMap 2674f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen for (View v: map.keySet()) { 2675f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen map.get(v).copy(savedMap.get(v)); 2676f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 2677f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 2678f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 2679f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen void restore() { 2680f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen // Restore current state from savedMap 2681f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen for (View v: savedMap.keySet()) { 2682f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen savedMap.get(v).copy(map.get(v)); 2683f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 2684f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 2685f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 2686f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen void add(View v, CellAndSpan cs) { 2687f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen map.put(v, cs); 2688f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen savedMap.put(v, new CellAndSpan()); 2689f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen sortedViews.add(v); 2690f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 2691f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 2692482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int area() { 2693482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return dragViewSpanX * dragViewSpanY; 2694482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 26958baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen } 26968baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen 26978baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen private class CellAndSpan { 26988baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen int x, y; 26998baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen int spanX, spanY; 27008baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen 2701f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen public CellAndSpan() { 2702f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 2703f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 2704f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen public void copy(CellAndSpan copy) { 2705f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen copy.x = x; 2706f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen copy.y = y; 2707f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen copy.spanX = spanX; 2708f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen copy.spanY = spanY; 2709f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 2710f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 27118baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen public CellAndSpan(int x, int y, int spanX, int spanY) { 27128baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen this.x = x; 27138baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen this.y = y; 27148baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen this.spanX = spanX; 27158baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen this.spanY = spanY; 2716482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2717f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 2718f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen public String toString() { 2719f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen return "(" + x + ", " + y + ": " + spanX + ", " + spanY + ")"; 2720f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 2721f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 2722482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2723482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2724df0353815c629fc678824b07a234b89a1ff94208Adam Cohen /** 2725df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * Find a vacant area that will fit the given bounds nearest the requested 2726df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * cell location. Uses Euclidean distance to score multiple vacant areas. 2727df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * 2728df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param pixelX The X location at which you want to search for a vacant area. 2729df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param pixelY The Y location at which you want to search for a vacant area. 2730df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param spanX Horizontal span of the object. 2731df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param spanY Vertical span of the object. 2732df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param ignoreView Considers space occupied by this view as unoccupied 2733df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param result Previously returned value to possibly recycle. 2734df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @return The X, Y cell of a vacant area that can contain this object, 2735df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * nearest the requested location. 2736df0353815c629fc678824b07a234b89a1ff94208Adam Cohen */ 2737df0353815c629fc678824b07a234b89a1ff94208Adam Cohen int[] findNearestVacantArea( 2738df0353815c629fc678824b07a234b89a1ff94208Adam Cohen int pixelX, int pixelY, int spanX, int spanY, View ignoreView, int[] result) { 2739df0353815c629fc678824b07a234b89a1ff94208Adam Cohen return findNearestArea(pixelX, pixelY, spanX, spanY, ignoreView, true, result); 2740df0353815c629fc678824b07a234b89a1ff94208Adam Cohen } 2741df0353815c629fc678824b07a234b89a1ff94208Adam Cohen 2742df0353815c629fc678824b07a234b89a1ff94208Adam Cohen /** 2743d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * Find a vacant area that will fit the given bounds nearest the requested 2744d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * cell location. Uses Euclidean distance to score multiple vacant areas. 2745d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * 2746d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param pixelX The X location at which you want to search for a vacant area. 2747d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param pixelY The Y location at which you want to search for a vacant area. 2748d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param minSpanX The minimum horizontal span required 2749d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param minSpanY The minimum vertical span required 2750d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param spanX Horizontal span of the object. 2751d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param spanY Vertical span of the object. 2752d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param ignoreView Considers space occupied by this view as unoccupied 2753d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param result Previously returned value to possibly recycle. 2754d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @return The X, Y cell of a vacant area that can contain this object, 2755d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * nearest the requested location. 2756d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen */ 2757d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int[] findNearestVacantArea(int pixelX, int pixelY, int minSpanX, int minSpanY, 2758d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int spanX, int spanY, View ignoreView, int[] result, int[] resultSpan) { 2759482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return findNearestArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, ignoreView, true, 2760482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result, resultSpan, mOccupied); 2761d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 2762d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen 2763d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen /** 2764df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * Find a starting cell position that will fit the given bounds nearest the requested 2765df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * cell location. Uses Euclidean distance to score multiple vacant areas. 2766df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * 2767df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param pixelX The X location at which you want to search for a vacant area. 2768df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param pixelY The Y location at which you want to search for a vacant area. 2769df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param spanX Horizontal span of the object. 2770df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param spanY Vertical span of the object. 2771df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param ignoreView Considers space occupied by this view as unoccupied 2772df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param result Previously returned value to possibly recycle. 2773df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @return The X, Y cell of a vacant area that can contain this object, 2774df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * nearest the requested location. 2775df0353815c629fc678824b07a234b89a1ff94208Adam Cohen */ 2776df0353815c629fc678824b07a234b89a1ff94208Adam Cohen int[] findNearestArea( 2777df0353815c629fc678824b07a234b89a1ff94208Adam Cohen int pixelX, int pixelY, int spanX, int spanY, int[] result) { 2778df0353815c629fc678824b07a234b89a1ff94208Adam Cohen return findNearestArea(pixelX, pixelY, spanX, spanY, null, false, result); 2779df0353815c629fc678824b07a234b89a1ff94208Adam Cohen } 2780df0353815c629fc678824b07a234b89a1ff94208Adam Cohen 27810280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka boolean existsEmptyCell() { 27820280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka return findCellForSpan(null, 1, 1); 27830280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 27840280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 27850280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka /** 27860280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * Finds the upper-left coordinate of the first rectangle in the grid that can 27870280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * hold a cell of the specified dimensions. If intersectX and intersectY are not -1, 27880280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * then this method will only return coordinates for rectangles that contain the cell 27890280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * (intersectX, intersectY) 27900280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * 27910280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param cellXY The array that will contain the position of a vacant cell if such a cell 27920280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * can be found. 27930280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param spanX The horizontal span of the cell we want to find. 27940280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param spanY The vertical span of the cell we want to find. 27950280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * 27960280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @return True if a vacant cell of the specified dimension was found, false otherwise. 27970280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka */ 27980280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka boolean findCellForSpan(int[] cellXY, int spanX, int spanY) { 2799482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return findCellForSpanThatIntersectsIgnoring(cellXY, spanX, spanY, -1, -1, null, mOccupied); 28000280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 28010280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 28020280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka /** 28030280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * Like above, but ignores any cells occupied by the item "ignoreView" 28040280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * 28050280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param cellXY The array that will contain the position of a vacant cell if such a cell 28060280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * can be found. 28070280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param spanX The horizontal span of the cell we want to find. 28080280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param spanY The vertical span of the cell we want to find. 28090280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param ignoreView The home screen item we should treat as not occupying any space 28100280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @return 28110280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka */ 28120280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka boolean findCellForSpanIgnoring(int[] cellXY, int spanX, int spanY, View ignoreView) { 2813482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return findCellForSpanThatIntersectsIgnoring(cellXY, spanX, spanY, -1, -1, 2814482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen ignoreView, mOccupied); 28150280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 28160280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 28170280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka /** 28180280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * Like above, but if intersectX and intersectY are not -1, then this method will try to 28190280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * return coordinates for rectangles that contain the cell [intersectX, intersectY] 28200280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * 28210280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param spanX The horizontal span of the cell we want to find. 28220280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param spanY The vertical span of the cell we want to find. 28230280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param ignoreView The home screen item we should treat as not occupying any space 28240280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param intersectX The X coordinate of the cell that we should try to overlap 28250280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param intersectX The Y coordinate of the cell that we should try to overlap 28260280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * 28270280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @return True if a vacant cell of the specified dimension was found, false otherwise. 28280280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka */ 28290280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka boolean findCellForSpanThatIntersects(int[] cellXY, int spanX, int spanY, 28300280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka int intersectX, int intersectY) { 28310280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka return findCellForSpanThatIntersectsIgnoring( 2832482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen cellXY, spanX, spanY, intersectX, intersectY, null, mOccupied); 28330280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 28340280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 28350280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka /** 28360280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * The superset of the above two methods 28370280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka */ 28380280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka boolean findCellForSpanThatIntersectsIgnoring(int[] cellXY, int spanX, int spanY, 2839482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int intersectX, int intersectY, View ignoreView, boolean occupied[][]) { 2840c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka // mark space take by ignoreView as available (method checks if ignoreView is null) 2841482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsAsUnoccupiedForView(ignoreView, occupied); 28420280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 284328750fba6a2d141eb9a1e566718c17236030b815Michael Jurka boolean foundCell = false; 28440280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka while (true) { 28450280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka int startX = 0; 28460280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka if (intersectX >= 0) { 28470280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka startX = Math.max(startX, intersectX - (spanX - 1)); 28480280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 28490280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka int endX = mCountX - (spanX - 1); 28500280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka if (intersectX >= 0) { 28510280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka endX = Math.min(endX, intersectX + (spanX - 1) + (spanX == 1 ? 1 : 0)); 28520280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 28530280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka int startY = 0; 28540280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka if (intersectY >= 0) { 28550280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka startY = Math.max(startY, intersectY - (spanY - 1)); 28560280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 28570280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka int endY = mCountY - (spanY - 1); 28580280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka if (intersectY >= 0) { 28590280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka endY = Math.min(endY, intersectY + (spanY - 1) + (spanY == 1 ? 1 : 0)); 28600280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 28610280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 2862bbc60d8e79416e37cbede55c159bf6aaa6c171d5Winson Chung for (int y = startY; y < endY && !foundCell; y++) { 28630280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka inner: 2864bbc60d8e79416e37cbede55c159bf6aaa6c171d5Winson Chung for (int x = startX; x < endX; x++) { 28650280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka for (int i = 0; i < spanX; i++) { 28660280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka for (int j = 0; j < spanY; j++) { 2867482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (occupied[x + i][y + j]) { 2868bbc60d8e79416e37cbede55c159bf6aaa6c171d5Winson Chung // small optimization: we can skip to after the column we just found 28690280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // an occupied cell 2870bbc60d8e79416e37cbede55c159bf6aaa6c171d5Winson Chung x += i; 28710280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka continue inner; 28720280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 28730280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 28740280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 28750280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka if (cellXY != null) { 28760280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka cellXY[0] = x; 28770280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka cellXY[1] = y; 28780280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 287928750fba6a2d141eb9a1e566718c17236030b815Michael Jurka foundCell = true; 288028750fba6a2d141eb9a1e566718c17236030b815Michael Jurka break; 28810280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 28820280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 28830280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka if (intersectX == -1 && intersectY == -1) { 28840280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka break; 28850280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } else { 28860280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // if we failed to find anything, try again but without any requirements of 28870280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // intersecting 28880280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka intersectX = -1; 28890280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka intersectY = -1; 28900280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka continue; 28910280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 28920280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 28930280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 2894c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka // re-mark space taken by ignoreView as occupied 2895482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsAsOccupiedForView(ignoreView, occupied); 289628750fba6a2d141eb9a1e566718c17236030b815Michael Jurka return foundCell; 28970280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 28980280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 289931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 2900c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung * A drag event has begun over this layout. 2901c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung * It may have begun over this layout (in which case onDragChild is called first), 2902c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung * or it may have begun on another layout. 2903c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung */ 2904c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung void onDragEnter() { 2905c6cc61d45836e4081920883cc4d448ccb0bb8417Adam Cohen mDragEnforcer.onDragEnter(); 2906c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung mDragging = true; 2907c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung } 2908c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung 2909c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung /** 29100280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * Called when drag has left this CellLayout or has been completed (successfully or not) 29116569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy */ 29120280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka void onDragExit() { 2913c6cc61d45836e4081920883cc4d448ccb0bb8417Adam Cohen mDragEnforcer.onDragExit(); 29144be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // This can actually be called when we aren't in a drag, e.g. when adding a new 29154be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // item to this layout via the customize drawer. 29164be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // Guard against that case. 29174be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato if (mDragging) { 29184be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato mDragging = false; 29194be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato } 292008ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy 292108ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy // Invalidate the drag data 2922d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen mDragCell[0] = mDragCell[1] = -1; 292308ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy mDragOutlineAnims[mDragOutlineCurrent].animateOut(); 292408ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy mDragOutlineCurrent = (mDragOutlineCurrent + 1) % mDragOutlineAnims.length; 292519f3792523fe2d55ea791a9286398a6120920690Adam Cohen revertTempState(); 292633945b21544bc98381df17726a3537c292d8c985Michael Jurka setIsDragOverlapping(false); 29276569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy } 29286569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 29296569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy /** 2930aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * Mark a child as having been dropped. 2931de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy * At the beginning of the drag operation, the child may have been on another 2932ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy * screen, but it is re-parented before this method is called. 293331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 293431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param child The child that is being dropped 293531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 2936716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen void onDropChild(View child) { 2937d94533d04a5f8f5485f106d10af60169857ea899Romain Guy if (child != null) { 2938d94533d04a5f8f5485f106d10af60169857ea899Romain Guy LayoutParams lp = (LayoutParams) child.getLayoutParams(); 293984f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy lp.dropped = true; 2940d94533d04a5f8f5485f106d10af60169857ea899Romain Guy child.requestLayout(); 2941d94533d04a5f8f5485f106d10af60169857ea899Romain Guy } 294231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 294331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 294431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 294531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Computes a bounding rectangle for a range of cells 2946aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * 294731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param cellX X coordinate of upper left corner expressed as a cell position 294831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param cellY Y coordinate of upper left corner expressed as a cell position 2949aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * @param cellHSpan Width in cells 295031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param cellVSpan Height in cells 29516569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy * @param resultRect Rect into which to put the results 295231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 2953d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen public void cellToRect(int cellX, int cellY, int cellHSpan, int cellVSpan, Rect resultRect) { 295431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int cellWidth = mCellWidth; 295531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int cellHeight = mCellHeight; 295631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int widthGap = mWidthGap; 295731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int heightGap = mHeightGap; 2958aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 29594b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung final int hStartPadding = getPaddingLeft(); 29604b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung final int vStartPadding = getPaddingTop(); 2961aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 296231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int width = cellHSpan * cellWidth + ((cellHSpan - 1) * widthGap); 296331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int height = cellVSpan * cellHeight + ((cellVSpan - 1) * heightGap); 296431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 296531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int x = hStartPadding + cellX * (cellWidth + widthGap); 296631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int y = vStartPadding + cellY * (cellHeight + heightGap); 2967aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 29686569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy resultRect.set(x, y, x + width, y + height); 296931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 2970aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 297131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 2972aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * Computes the required horizontal and vertical cell spans to always 297331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * fit the given rectangle. 2974aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * 297531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param width Width in pixels 297631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param height Height in pixels 29778f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy * @param result An array of length 2 in which to store the result (may be null). 297831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 29798f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy public int[] rectToCell(int width, int height, int[] result) { 29809987a5c45e7d01a780d73b269bdce8d8a5309219Michael Jurka return rectToCell(getResources(), width, height, result); 29819987a5c45e7d01a780d73b269bdce8d8a5309219Michael Jurka } 29829987a5c45e7d01a780d73b269bdce8d8a5309219Michael Jurka 29839987a5c45e7d01a780d73b269bdce8d8a5309219Michael Jurka public static int[] rectToCell(Resources resources, int width, int height, int[] result) { 298431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // Always assume we're working with the smallest span to make sure we 298531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // reserve enough space in both orientations. 298679e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato int actualWidth = resources.getDimensionPixelSize(R.dimen.workspace_cell_width); 298779e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato int actualHeight = resources.getDimensionPixelSize(R.dimen.workspace_cell_height); 298831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int smallerSize = Math.min(actualWidth, actualHeight); 298979e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato 299031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // Always round up to next largest cell 299154c725cc294cd43ed0650179bfae64a622547660Winson Chung int spanX = (int) Math.ceil(width / (float) smallerSize); 299254c725cc294cd43ed0650179bfae64a622547660Winson Chung int spanY = (int) Math.ceil(height / (float) smallerSize); 299379e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato 29948f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy if (result == null) { 29958f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy return new int[] { spanX, spanY }; 29968f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy } 29978f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy result[0] = spanX; 29988f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy result[1] = spanY; 29998f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy return result; 300031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 300131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 3002f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka public int[] cellSpansToSize(int hSpans, int vSpans) { 3003f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka int[] size = new int[2]; 3004f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka size[0] = hSpans * mCellWidth + (hSpans - 1) * mWidthGap; 3005f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka size[1] = vSpans * mCellHeight + (vSpans - 1) * mHeightGap; 3006f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka return size; 3007f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka } 3008f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka 300931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 3010047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy * Calculate the grid spans needed to fit given item 3011047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy */ 3012047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy public void calculateSpans(ItemInfo info) { 3013047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy final int minWidth; 3014047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy final int minHeight; 3015047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy 3016047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy if (info instanceof LauncherAppWidgetInfo) { 3017047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy minWidth = ((LauncherAppWidgetInfo) info).minWidth; 3018047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy minHeight = ((LauncherAppWidgetInfo) info).minHeight; 3019047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy } else if (info instanceof PendingAddWidgetInfo) { 3020047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy minWidth = ((PendingAddWidgetInfo) info).minWidth; 3021047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy minHeight = ((PendingAddWidgetInfo) info).minHeight; 3022047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy } else { 3023047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy // It's not a widget, so it must be 1x1 3024047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy info.spanX = info.spanY = 1; 3025047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy return; 3026047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy } 3027047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy int[] spans = rectToCell(minWidth, minHeight, null); 3028047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy info.spanX = spans[0]; 3029047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy info.spanY = spans[1]; 3030047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy } 3031047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy 3032047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy /** 303331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Find the first vacant cell, if there is one. 303431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 303531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param vacant Holds the x and y coordinate of the vacant cell 303631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param spanX Horizontal cell span. 303731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param spanY Vertical cell span. 3038aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * 303931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @return True if a vacant cell was found 304031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 304131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public boolean getVacantCell(int[] vacant, int spanX, int spanY) { 304231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 30430280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka return findVacantCell(vacant, spanX, spanY, mCountX, mCountY, mOccupied); 304431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 304531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 304631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project static boolean findVacantCell(int[] vacant, int spanX, int spanY, 304731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int xCount, int yCount, boolean[][] occupied) { 304831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 30492801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen for (int y = 0; y < yCount; y++) { 30502801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen for (int x = 0; x < xCount; x++) { 305131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project boolean available = !occupied[x][y]; 305231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectout: for (int i = x; i < x + spanX - 1 && x < xCount; i++) { 305331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int j = y; j < y + spanY - 1 && y < yCount; j++) { 305431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project available = available && !occupied[i][j]; 305531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (!available) break out; 305631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 305731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 305831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 305931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (available) { 306031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project vacant[0] = x; 306131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project vacant[1] = y; 306231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return true; 306331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 306431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 306531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 306631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 306731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return false; 306831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 306931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 30700280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka private void clearOccupiedCells() { 30710280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka for (int x = 0; x < mCountX; x++) { 30720280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka for (int y = 0; y < mCountY; y++) { 30730280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka mOccupied[x][y] = false; 307431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 307531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 30760280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 307731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 3078d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen public void onMove(View view, int newCellX, int newCellY, int newSpanX, int newSpanY) { 30790280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka markCellsAsUnoccupiedForView(view); 3080482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsForView(newCellX, newCellY, newSpanX, newSpanY, mOccupied, true); 30810280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 308231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 3083d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen public void markCellsAsOccupiedForView(View view) { 3084482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsAsOccupiedForView(view, mOccupied); 3085482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 3086482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public void markCellsAsOccupiedForView(View view, boolean[][] occupied) { 3087a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka if (view == null || view.getParent() != mShortcutsAndWidgets) return; 30880280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka LayoutParams lp = (LayoutParams) view.getLayoutParams(); 3089482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, occupied, true); 30900280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 30910280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 3092d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen public void markCellsAsUnoccupiedForView(View view) { 3093482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsAsUnoccupiedForView(view, mOccupied); 3094482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 3095482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public void markCellsAsUnoccupiedForView(View view, boolean occupied[][]) { 3096a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka if (view == null || view.getParent() != mShortcutsAndWidgets) return; 30970280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka LayoutParams lp = (LayoutParams) view.getLayoutParams(); 3098482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, occupied, false); 30990280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 31000280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 3101482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private void markCellsForView(int cellX, int cellY, int spanX, int spanY, boolean[][] occupied, 3102482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean value) { 3103482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (cellX < 0 || cellY < 0) return; 31040280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka for (int x = cellX; x < cellX + spanX && x < mCountX; x++) { 31050280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka for (int y = cellY; y < cellY + spanY && y < mCountY; y++) { 3106482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen occupied[x][y] = value; 310731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 310831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 310931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 311031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 31112801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen public int getDesiredWidth() { 31128b805b17158886035b38261eb611d8641701ae43Michael Jurka return getPaddingLeft() + getPaddingRight() + (mCountX * mCellWidth) + 31132801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen (Math.max((mCountX - 1), 0) * mWidthGap); 31142801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen } 31152801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen 31162801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen public int getDesiredHeight() { 31178b805b17158886035b38261eb611d8641701ae43Michael Jurka return getPaddingTop() + getPaddingBottom() + (mCountY * mCellHeight) + 31182801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen (Math.max((mCountY - 1), 0) * mHeightGap); 31192801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen } 31202801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen 312166d72178af91d455700875635473be942bc90e54Michael Jurka public boolean isOccupied(int x, int y) { 312266d72178af91d455700875635473be942bc90e54Michael Jurka if (x < mCountX && y < mCountY) { 312366d72178af91d455700875635473be942bc90e54Michael Jurka return mOccupied[x][y]; 312466d72178af91d455700875635473be942bc90e54Michael Jurka } else { 312566d72178af91d455700875635473be942bc90e54Michael Jurka throw new RuntimeException("Position exceeds the bound of this CellLayout"); 312666d72178af91d455700875635473be942bc90e54Michael Jurka } 312766d72178af91d455700875635473be942bc90e54Michael Jurka } 312866d72178af91d455700875635473be942bc90e54Michael Jurka 312931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 313031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) { 313131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return new CellLayout.LayoutParams(getContext(), attrs); 313231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 313331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 313431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 313531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { 313631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return p instanceof CellLayout.LayoutParams; 313731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 313831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 313931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 314031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { 314131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return new CellLayout.LayoutParams(p); 314231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 314331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 3144aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung public static class CellLayoutAnimationController extends LayoutAnimationController { 3145aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung public CellLayoutAnimationController(Animation animation, float delay) { 3146aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung super(animation, delay); 3147aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung } 3148aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 3149aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung @Override 3150aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung protected long getDelayForView(View view) { 3151aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung return (int) (Math.random() * 150); 3152aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung } 3153aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung } 3154aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 315531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public static class LayoutParams extends ViewGroup.MarginLayoutParams { 315631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 315731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Horizontal location of the item in the grid. 315831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 315931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @ViewDebug.ExportedProperty 316031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public int cellX; 316131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 316231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 316331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Vertical location of the item in the grid. 316431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 316531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @ViewDebug.ExportedProperty 316631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public int cellY; 316731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 316831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 3169482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * Temporary horizontal location of the item in the grid during reorder 3170482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen */ 3171482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public int tmpCellX; 3172482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 3173482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen /** 3174482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * Temporary vertical location of the item in the grid during reorder 3175482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen */ 3176482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public int tmpCellY; 3177482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 3178482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen /** 3179482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * Indicates that the temporary coordinates should be used to layout the items 3180482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen */ 3181482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public boolean useTmpCoords; 3182482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 3183482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen /** 318431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Number of cells spanned horizontally by the item. 318531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 318631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @ViewDebug.ExportedProperty 318731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public int cellHSpan; 318831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 318931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 319031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Number of cells spanned vertically by the item. 319131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 319231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @ViewDebug.ExportedProperty 319331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public int cellVSpan; 3194aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 31951b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen /** 31961b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen * Indicates whether the item will set its x, y, width and height parameters freely, 31971b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen * or whether these will be computed based on cellX, cellY, cellHSpan and cellVSpan. 31981b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen */ 3199d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen public boolean isLockedToGrid = true; 3200d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen 3201482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen /** 3202482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * Indicates whether this item can be reordered. Always true except in the case of the 3203482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * the AllApps button. 3204482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen */ 3205482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public boolean canReorder = true; 3206482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 320731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // X coordinate of the view in the layout. 320831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @ViewDebug.ExportedProperty 320931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int x; 321031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // Y coordinate of the view in the layout. 321131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @ViewDebug.ExportedProperty 321231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int y; 321331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 321484f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy boolean dropped; 3215fcb9e7144e58614f5ae0e9b272fb7ce040848c67Romain Guy 321631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public LayoutParams(Context c, AttributeSet attrs) { 321731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project super(c, attrs); 321831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellHSpan = 1; 321931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellVSpan = 1; 322031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 322131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 322231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public LayoutParams(ViewGroup.LayoutParams source) { 322331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project super(source); 322431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellHSpan = 1; 322531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellVSpan = 1; 322631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 3227aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 3228aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung public LayoutParams(LayoutParams source) { 3229aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung super(source); 3230aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung this.cellX = source.cellX; 3231aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung this.cellY = source.cellY; 3232aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung this.cellHSpan = source.cellHSpan; 3233aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung this.cellVSpan = source.cellVSpan; 3234aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung } 3235aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 323631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public LayoutParams(int cellX, int cellY, int cellHSpan, int cellVSpan) { 32378f19cdd62f6e2be05e3890916eabd11317ae1bc2Romain Guy super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); 323831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this.cellX = cellX; 323931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this.cellY = cellY; 324031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this.cellHSpan = cellHSpan; 324131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this.cellVSpan = cellVSpan; 324231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 324331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 32447f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public void setup(int cellWidth, int cellHeight, int widthGap, int heightGap) { 3245d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen if (isLockedToGrid) { 3246d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen final int myCellHSpan = cellHSpan; 3247d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen final int myCellVSpan = cellVSpan; 3248482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int myCellX = useTmpCoords ? tmpCellX : cellX; 3249482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int myCellY = useTmpCoords ? tmpCellY : cellY; 32501b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen 3251d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen width = myCellHSpan * cellWidth + ((myCellHSpan - 1) * widthGap) - 3252d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen leftMargin - rightMargin; 3253d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen height = myCellVSpan * cellHeight + ((myCellVSpan - 1) * heightGap) - 3254d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen topMargin - bottomMargin; 3255eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung x = (int) (myCellX * (cellWidth + widthGap) + leftMargin); 3256eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung y = (int) (myCellY * (cellHeight + heightGap) + topMargin); 3257d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen } 3258d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen } 3259d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen 3260aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung public String toString() { 3261aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung return "(" + this.cellX + ", " + this.cellY + ")"; 3262aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung } 32637f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 32647f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public void setWidth(int width) { 32657f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen this.width = width; 32667f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 32677f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 32687f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public int getWidth() { 32697f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen return width; 32707f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 32717f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 32727f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public void setHeight(int height) { 32737f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen this.height = height; 32747f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 32757f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 32767f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public int getHeight() { 32777f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen return height; 32787f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 32797f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 32807f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public void setX(int x) { 32817f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen this.x = x; 32827f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 32837f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 32847f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public int getX() { 32857f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen return x; 32867f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 32877f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 32887f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public void setY(int y) { 32897f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen this.y = y; 32907f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 32917f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 32927f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public int getY() { 32937f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen return y; 32947f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 329531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 329631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 32970280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // This class stores info for two purposes: 32980280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // 1. When dragging items (mDragInfo in Workspace), we store the View, its cellX & cellY, 32990280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // its spanX, spanY, and the screen it is on 33000280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // 2. When long clicking on an empty cell in a CellLayout, we save information about the 33010280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // cellX and cellY coordinates and which page was clicked. We then set this as a tag on 33020280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // the CellLayout that was long clicked 3303e5fb0f27bca7afb996258a7163c76ca7390d7bffMichael Jurka static final class CellInfo { 330431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project View cell; 3305a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka int cellX = -1; 3306a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka int cellY = -1; 330731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int spanX; 330831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int spanY; 330931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int screen; 33103d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung long container; 331131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 331231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 331331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public String toString() { 3314aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung return "Cell[view=" + (cell == null ? "null" : cell.getClass()) 3315aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung + ", x=" + cellX + ", y=" + cellY + "]"; 331631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 331731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 3318d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka 3319d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka public boolean lastDownOnOccupiedCell() { 3320d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka return mLastDownOnOccupiedCell; 3321d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka } 332231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project} 3323