CellLayout.java revision e3e03bcd313ba8060f2832b6a16dea6fd6d532ea
131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project/* 231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project 331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * you may not use this file except in compliance with the License. 631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * You may obtain a copy of the License at 731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 1031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 1131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 1231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * See the License for the specific language governing permissions and 1431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * limitations under the License. 1531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 1631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 17a5902524d4403885eb4c50360bf3465c6be796efJoe Onoratopackage com.android.launcher2; 1831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 194be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onoratoimport android.animation.Animator; 204be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onoratoimport android.animation.AnimatorListenerAdapter; 2100397b1d9233409d9d6b233b077ae12d09768ce8Chet Haaseimport android.animation.TimeInterpolator; 22de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroyimport android.animation.ValueAnimator; 23de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroyimport android.animation.ValueAnimator.AnimatorUpdateListener; 2431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.content.Context; 2579e56263dbcbe85dc434df372bc6e6730aa13477Joe Onoratoimport android.content.res.Resources; 26aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chungimport android.content.res.TypedArray; 274be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onoratoimport android.graphics.Bitmap; 28aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chungimport android.graphics.Canvas; 290dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynnimport android.graphics.Color; 304be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onoratoimport android.graphics.Paint; 31de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroyimport android.graphics.Point; 32de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroyimport android.graphics.PointF; 33b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohenimport android.graphics.PorterDuff; 34b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohenimport android.graphics.PorterDuffXfermode; 3531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.graphics.Rect; 36482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohenimport android.graphics.drawable.ColorDrawable; 376569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroyimport android.graphics.drawable.Drawable; 38b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohenimport android.graphics.drawable.NinePatchDrawable; 3931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.util.AttributeSet; 404be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onoratoimport android.util.Log; 4131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.MotionEvent; 4231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.View; 4331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.ViewDebug; 4431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.ViewGroup; 45aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chungimport android.view.animation.Animation; 46150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chungimport android.view.animation.DecelerateInterpolator; 47aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chungimport android.view.animation.LayoutAnimationController; 4831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 496639687cd67bab1aeef2a75e5c6bc458b20dc082Adam Cohenimport com.android.launcher.R; 5069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohenimport com.android.launcher2.FolderIcon.FolderRingAnimator; 518e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy 5269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohenimport java.util.ArrayList; 53c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohenimport java.util.Arrays; 54bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohenimport java.util.HashMap; 55d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohenimport java.util.Stack; 56c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen 57bdb5c5342adc550559fd723af461e53248f2fba8Michael Jurkapublic class CellLayout extends ViewGroup { 58aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung static final String TAG = "CellLayout"; 59aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 602acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen private Launcher mLauncher; 6131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private int mCellWidth; 6231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private int mCellHeight; 63aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 64d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen private int mCountX; 65d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen private int mCountY; 6631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 67234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen private int mOriginalWidthGap; 68234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen private int mOriginalHeightGap; 6931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private int mWidthGap; 7031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private int mHeightGap; 714b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung private int mMaxGap; 72ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen private boolean mScrollingTransformsDirty = false; 7331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 7431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private final Rect mRect = new Rect(); 7531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private final CellInfo mCellInfo = new CellInfo(); 76aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 77de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy // These are temporary variables to prevent having to allocate a new object just to 78de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy // return an (x, y) value from helper functions. Do NOT use them to maintain other state. 790be025d64c1f84138fe430a58875886e66aae767Winson Chung private final int[] mTmpXY = new int[2]; 80de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy private final int[] mTmpPoint = new int[2]; 81de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy private final PointF mTmpPointF = new PointF(); 8269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen int[] mTempLocation = new int[2]; 836569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 8431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project boolean[][] mOccupied; 85482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean[][] mTmpOccupied; 86d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka private boolean mLastDownOnOccupiedCell = false; 8731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 88dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka private OnTouchListener mInterceptTouchListener; 89dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka 9069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen private ArrayList<FolderRingAnimator> mFolderOuterRings = new ArrayList<FolderRingAnimator>(); 91c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen private int[] mFolderLeaveBehindCell = {-1, -1}; 9269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 93b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen private int mForegroundAlpha = 0; 945f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka private float mBackgroundAlpha; 951b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen private float mBackgroundAlphaMultiplier = 1.0f; 96f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen 9733945b21544bc98381df17726a3537c292d8c985Michael Jurka private Drawable mNormalBackground; 9833945b21544bc98381df17726a3537c292d8c985Michael Jurka private Drawable mActiveGlowBackground; 99b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen private Drawable mOverScrollForegroundDrawable; 100b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen private Drawable mOverScrollLeft; 101b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen private Drawable mOverScrollRight; 10218014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka private Rect mBackgroundRect; 103b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen private Rect mForegroundRect; 104b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen private int mForegroundPadding; 10533945b21544bc98381df17726a3537c292d8c985Michael Jurka 10633945b21544bc98381df17726a3537c292d8c985Michael Jurka // If we're actively dragging something over this screen, mIsDragOverlapping is true 10733945b21544bc98381df17726a3537c292d8c985Michael Jurka private boolean mIsDragOverlapping = false; 108de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy private final Point mDragCenter = new Point(); 1096569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 110150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung // These arrays are used to implement the drag visualization on x-large screens. 1114be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // They are used as circular arrays, indexed by mDragOutlineCurrent. 112d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen private Rect[] mDragOutlines = new Rect[4]; 113472b281d5cb4f5660df981a6c912266b9f5703feChet Haase private float[] mDragOutlineAlphas = new float[mDragOutlines.length]; 1144be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato private InterruptibleInOutAnimator[] mDragOutlineAnims = 1154be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato new InterruptibleInOutAnimator[mDragOutlines.length]; 116150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung 117150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung // Used as an index into the above 3 arrays; indicates which is the most current value. 1184be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato private int mDragOutlineCurrent = 0; 1198e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy private final Paint mDragOutlinePaint = new Paint(); 120150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung 12196864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy private BubbleTextView mPressedOrFocusedIcon; 12296864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy 123482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private HashMap<CellLayout.LayoutParams, Animator> mReorderAnimators = new 124482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen HashMap<CellLayout.LayoutParams, Animator>(); 12519f3792523fe2d55ea791a9286398a6120920690Adam Cohen private HashMap<View, ReorderHintAnimation> 12619f3792523fe2d55ea791a9286398a6120920690Adam Cohen mShakeAnimators = new HashMap<View, ReorderHintAnimation>(); 12719f3792523fe2d55ea791a9286398a6120920690Adam Cohen 12819f3792523fe2d55ea791a9286398a6120920690Adam Cohen private boolean mItemPlacementDirty = false; 129bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen 1306569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy // When a drag operation is in progress, holds the nearest cell to the touch point 1316569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy private final int[] mDragCell = new int[2]; 13231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 1334be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato private boolean mDragging = false; 1344be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato 135ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy private TimeInterpolator mEaseOutInterpolator; 136a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka private ShortcutAndWidgetContainer mShortcutsAndWidgets; 137ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy 1380dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn private boolean mIsHotseat = false; 139eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung private float mChildScale = 1f; 140eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung private float mHotseatChildScale = 1f; 1410dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn 142482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public static final int MODE_DRAG_OVER = 0; 143482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public static final int MODE_ON_DROP = 1; 144482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public static final int MODE_ON_DROP_EXTERNAL = 2; 145482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public static final int MODE_ACCEPT_DROP = 3; 14619f3792523fe2d55ea791a9286398a6120920690Adam Cohen private static final boolean DESTRUCTIVE_REORDER = false; 147482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private static final boolean DEBUG_VISUALIZE_OCCUPIED = false; 148482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 149a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen static final int LANDSCAPE = 0; 150a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen static final int PORTRAIT = 1; 151a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen 15219f3792523fe2d55ea791a9286398a6120920690Adam Cohen private static final float REORDER_HINT_MAGNITUDE = 0.27f; 15319f3792523fe2d55ea791a9286398a6120920690Adam Cohen private static final int REORDER_ANIMATION_DURATION = 150; 15419f3792523fe2d55ea791a9286398a6120920690Adam Cohen private float mReorderHintAnimationMagnitude; 15519f3792523fe2d55ea791a9286398a6120920690Adam Cohen 156482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private ArrayList<View> mIntersectingViews = new ArrayList<View>(); 157482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private Rect mOccupiedRect = new Rect(); 158482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private int[] mDirectionVector = new int[2]; 15919f3792523fe2d55ea791a9286398a6120920690Adam Cohen int[] mPreviousReorderDirection = new int[2]; 160b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen private static final int INVALID_DIRECTION = -100; 161c6cc61d45836e4081920883cc4d448ccb0bb8417Adam Cohen private DropTarget.DragEnforcer mDragEnforcer; 162482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 16331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public CellLayout(Context context) { 16431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this(context, null); 16531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 16631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 16731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public CellLayout(Context context, AttributeSet attrs) { 16831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this(context, attrs, 0); 16931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 17031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 17131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public CellLayout(Context context, AttributeSet attrs, int defStyle) { 17231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project super(context, attrs, defStyle); 1738b805b17158886035b38261eb611d8641701ae43Michael Jurka mDragEnforcer = new DropTarget.DragEnforcer(context); 1746569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 1756569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy // A ViewGroup usually does not draw, but CellLayout needs to draw a rectangle to show 1766569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy // the user where a dragged item will land when dropped. 1776569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy setWillNotDraw(false); 1782acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen mLauncher = (Launcher) context; 179a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka 18031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CellLayout, defStyle, 0); 18131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 182f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen mCellWidth = a.getDimensionPixelSize(R.styleable.CellLayout_cellWidth, 10); 183f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen mCellHeight = a.getDimensionPixelSize(R.styleable.CellLayout_cellHeight, 10); 184234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen mWidthGap = mOriginalWidthGap = a.getDimensionPixelSize(R.styleable.CellLayout_widthGap, 0); 185234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen mHeightGap = mOriginalHeightGap = a.getDimensionPixelSize(R.styleable.CellLayout_heightGap, 0); 1864b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung mMaxGap = a.getDimensionPixelSize(R.styleable.CellLayout_maxGap, 0); 187d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen mCountX = LauncherModel.getCellCountX(); 188d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen mCountY = LauncherModel.getCellCountY(); 1890280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka mOccupied = new boolean[mCountX][mCountY]; 190482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mTmpOccupied = new boolean[mCountX][mCountY]; 1915b53f29f809a0dad4a1e0717ba610ce737ee0f43Adam Cohen mPreviousReorderDirection[0] = INVALID_DIRECTION; 1925b53f29f809a0dad4a1e0717ba610ce737ee0f43Adam Cohen mPreviousReorderDirection[1] = INVALID_DIRECTION; 19331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 19431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project a.recycle(); 19531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 19631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project setAlwaysDrawnWithCacheEnabled(false); 19731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 198046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy final Resources res = getResources(); 199de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy 200967289b6d5fec77f5c381d11ffb2319f3bb5e737Winson Chung mNormalBackground = res.getDrawable(R.drawable.homescreen_blue_normal_holo); 201dea74b7d12b0fcd50bfdb4274f9867ba76d75238Winson Chung mActiveGlowBackground = res.getDrawable(R.drawable.homescreen_blue_strong_holo); 202b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung 203b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mOverScrollLeft = res.getDrawable(R.drawable.overscroll_glow_left); 204b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mOverScrollRight = res.getDrawable(R.drawable.overscroll_glow_right); 205b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mForegroundPadding = 206b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen res.getDimensionPixelSize(R.dimen.workspace_overscroll_drawable_padding); 207b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung 20819f3792523fe2d55ea791a9286398a6120920690Adam Cohen mReorderHintAnimationMagnitude = (REORDER_HINT_MAGNITUDE * 20919f3792523fe2d55ea791a9286398a6120920690Adam Cohen res.getDimensionPixelSize(R.dimen.app_icon_size)); 21019f3792523fe2d55ea791a9286398a6120920690Adam Cohen 211b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung mNormalBackground.setFilterBitmap(true); 212b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung mActiveGlowBackground.setFilterBitmap(true); 213de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy 214eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung int iconScale = res.getInteger(R.integer.app_icon_scale_percent); 215eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung if (iconScale >= 0) { 216eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung mChildScale = iconScale / 100f; 217eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung } 218eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung int hotseatIconScale = res.getInteger(R.integer.app_icon_hotseat_scale_percent); 219eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung if (hotseatIconScale >= 0) { 220eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung mHotseatChildScale = hotseatIconScale / 100f; 221eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung } 2220dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn 223046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy // Initialize the data structures used for the drag visualization. 224150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung 225ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy mEaseOutInterpolator = new DecelerateInterpolator(2.5f); // Quint ease out 226de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy 227046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy 228b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung mDragCell[0] = mDragCell[1] = -1; 2294be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato for (int i = 0; i < mDragOutlines.length; i++) { 230d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen mDragOutlines[i] = new Rect(-1, -1, -1, -1); 231046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy } 232046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy 233046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy // When dragging things around the home screens, we show a green outline of 234046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy // where the item will land. The outlines gradually fade out, leaving a trail 235046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy // behind the drag path. 236046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy // Set up all the animations that are used to implement this fading. 237046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy final int duration = res.getInteger(R.integer.config_dragOutlineFadeTime); 238472b281d5cb4f5660df981a6c912266b9f5703feChet Haase final float fromAlphaValue = 0; 239472b281d5cb4f5660df981a6c912266b9f5703feChet Haase final float toAlphaValue = (float)res.getInteger(R.integer.config_dragOutlineMaxAlpha); 2404be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato 2418e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy Arrays.fill(mDragOutlineAlphas, fromAlphaValue); 2424be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato 2434be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato for (int i = 0; i < mDragOutlineAnims.length; i++) { 244046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy final InterruptibleInOutAnimator anim = 245046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy new InterruptibleInOutAnimator(duration, fromAlphaValue, toAlphaValue); 246ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy anim.getAnimator().setInterpolator(mEaseOutInterpolator); 247046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy final int thisIndex = i; 248472b281d5cb4f5660df981a6c912266b9f5703feChet Haase anim.getAnimator().addUpdateListener(new AnimatorUpdateListener() { 249de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy public void onAnimationUpdate(ValueAnimator animation) { 2504be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato final Bitmap outline = (Bitmap)anim.getTag(); 2514be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato 2524be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // If an animation is started and then stopped very quickly, we can still 2534be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // get spurious updates we've cleared the tag. Guard against this. 2544be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato if (outline == null) { 2553a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka @SuppressWarnings("all") // suppress dead code warning 2563a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka final boolean debug = false; 2573a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka if (debug) { 258fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy Object val = animation.getAnimatedValue(); 259fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy Log.d(TAG, "anim " + thisIndex + " update: " + val + 260fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy ", isStopped " + anim.isStopped()); 261fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy } 2624be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // Try to prevent it from continuing to run 2634be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato animation.cancel(); 2644be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato } else { 265472b281d5cb4f5660df981a6c912266b9f5703feChet Haase mDragOutlineAlphas[thisIndex] = (Float) animation.getAnimatedValue(); 266d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen CellLayout.this.invalidate(mDragOutlines[thisIndex]); 2674be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato } 268de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy } 269de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy }); 2704be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // The animation holds a reference to the drag outline bitmap as long is it's 2714be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // running. This way the bitmap can be GCed when the animations are complete. 272472b281d5cb4f5660df981a6c912266b9f5703feChet Haase anim.getAnimator().addListener(new AnimatorListenerAdapter() { 2733c4c20fbe682cb4b3ef94f09afe0af09171583f3Michael Jurka @Override 2744be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato public void onAnimationEnd(Animator animation) { 275472b281d5cb4f5660df981a6c912266b9f5703feChet Haase if ((Float) ((ValueAnimator) animation).getAnimatedValue() == 0f) { 2764be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato anim.setTag(null); 2774be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato } 2784be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato } 2794be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato }); 2804be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato mDragOutlineAnims[i] = anim; 281de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy } 282ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy 28318014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka mBackgroundRect = new Rect(); 284b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mForegroundRect = new Rect(); 285bea15195346bab3c52b0156e92f2b71f0811b210Michael Jurka 286a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets = new ShortcutAndWidgetContainer(context); 287a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.setCellDimensions(mCellWidth, mCellHeight, mWidthGap, mHeightGap); 288a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka addView(mShortcutsAndWidgets); 28918014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka } 29018014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka 291f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka static int widthInPortrait(Resources r, int numCells) { 292f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka // We use this method from Workspace to figure out how many rows/columns Launcher should 293f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka // have. We ignore the left/right padding on CellLayout because it turns out in our design 294f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka // the padding extends outside the visible screen size, but it looked fine anyway. 295f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka int cellWidth = r.getDimensionPixelSize(R.dimen.workspace_cell_width); 2964b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung int minGap = Math.min(r.getDimensionPixelSize(R.dimen.workspace_width_gap), 2974b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung r.getDimensionPixelSize(R.dimen.workspace_height_gap)); 298f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka 2994b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung return minGap * (numCells - 1) + cellWidth * numCells; 300f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka } 301f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka 302f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka static int heightInLandscape(Resources r, int numCells) { 303f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka // We use this method from Workspace to figure out how many rows/columns Launcher should 304f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka // have. We ignore the left/right padding on CellLayout because it turns out in our design 305f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka // the padding extends outside the visible screen size, but it looked fine anyway. 306f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka int cellHeight = r.getDimensionPixelSize(R.dimen.workspace_cell_height); 3074b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung int minGap = Math.min(r.getDimensionPixelSize(R.dimen.workspace_width_gap), 3084b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung r.getDimensionPixelSize(R.dimen.workspace_height_gap)); 309f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka 3104b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung return minGap * (numCells - 1) + cellHeight * numCells; 311f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka } 312f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka 3132801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen public void enableHardwareLayers() { 314a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.enableHardwareLayers(); 3152801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen } 3162801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen 3172801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen public void setGridSize(int x, int y) { 3182801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen mCountX = x; 3192801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen mCountY = y; 3202801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen mOccupied = new boolean[mCountX][mCountY]; 321482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mTmpOccupied = new boolean[mCountX][mCountY]; 3227fbec10b36818f100b631f3d73fe1ad5360975aaAdam Cohen mTempRectStack.clear(); 32376fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen requestLayout(); 3242801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen } 3252801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen 32696864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy private void invalidateBubbleTextView(BubbleTextView icon) { 32796864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy final int padding = icon.getPressedOrFocusedBackgroundPadding(); 3284b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung invalidate(icon.getLeft() + getPaddingLeft() - padding, 3294b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung icon.getTop() + getPaddingTop() - padding, 3304b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung icon.getRight() + getPaddingLeft() + padding, 3314b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung icon.getBottom() + getPaddingTop() + padding); 33296864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy } 33396864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy 334b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen void setOverScrollAmount(float r, boolean left) { 335b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen if (left && mOverScrollForegroundDrawable != mOverScrollLeft) { 336b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mOverScrollForegroundDrawable = mOverScrollLeft; 337b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen } else if (!left && mOverScrollForegroundDrawable != mOverScrollRight) { 338b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mOverScrollForegroundDrawable = mOverScrollRight; 339b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen } 340b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen 341b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mForegroundAlpha = (int) Math.round((r * 255)); 342b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mOverScrollForegroundDrawable.setAlpha(mForegroundAlpha); 343b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen invalidate(); 344b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen } 345b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen 34696864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy void setPressedOrFocusedIcon(BubbleTextView icon) { 34796864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy // We draw the pressed or focused BubbleTextView's background in CellLayout because it 34896864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy // requires an expanded clip rect (due to the glow's blur radius) 34996864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy BubbleTextView oldIcon = mPressedOrFocusedIcon; 35096864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy mPressedOrFocusedIcon = icon; 35196864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy if (oldIcon != null) { 35296864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy invalidateBubbleTextView(oldIcon); 35396864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy } 35496864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy if (mPressedOrFocusedIcon != null) { 35596864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy invalidateBubbleTextView(mPressedOrFocusedIcon); 35696864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy } 35796864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy } 35896864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy 35933945b21544bc98381df17726a3537c292d8c985Michael Jurka void setIsDragOverlapping(boolean isDragOverlapping) { 36033945b21544bc98381df17726a3537c292d8c985Michael Jurka if (mIsDragOverlapping != isDragOverlapping) { 36133945b21544bc98381df17726a3537c292d8c985Michael Jurka mIsDragOverlapping = isDragOverlapping; 36233945b21544bc98381df17726a3537c292d8c985Michael Jurka invalidate(); 36333945b21544bc98381df17726a3537c292d8c985Michael Jurka } 36433945b21544bc98381df17726a3537c292d8c985Michael Jurka } 36533945b21544bc98381df17726a3537c292d8c985Michael Jurka 36633945b21544bc98381df17726a3537c292d8c985Michael Jurka boolean getIsDragOverlapping() { 36733945b21544bc98381df17726a3537c292d8c985Michael Jurka return mIsDragOverlapping; 36833945b21544bc98381df17726a3537c292d8c985Michael Jurka } 36933945b21544bc98381df17726a3537c292d8c985Michael Jurka 370ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen protected void setOverscrollTransformsDirty(boolean dirty) { 371ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen mScrollingTransformsDirty = dirty; 372ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen } 373ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen 374ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen protected void resetOverscrollTransforms() { 375ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen if (mScrollingTransformsDirty) { 376ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen setOverscrollTransformsDirty(false); 377ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen setTranslationX(0); 378ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen setRotationY(0); 379ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen // It doesn't matter if we pass true or false here, the important thing is that we 380ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen // pass 0, which results in the overscroll drawable not being drawn any more. 381ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen setOverScrollAmount(0, false); 382ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen setPivotX(getMeasuredWidth() / 2); 383ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen setPivotY(getMeasuredHeight() / 2); 384ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen } 385ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen } 386ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen 387a6abce8464b57ce91e8f083951ad263370fc2da8Romain Guy @Override 3881262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy protected void onDraw(Canvas canvas) { 3893e7c7634531302271270c8cf418abc959d621cbcMichael Jurka // When we're large, we are either drawn in a "hover" state (ie when dragging an item to 3903e7c7634531302271270c8cf418abc959d621cbcMichael Jurka // a neighboring page) or with just a normal background (if backgroundAlpha > 0.0f) 3913e7c7634531302271270c8cf418abc959d621cbcMichael Jurka // When we're small, we are either drawn normally or in the "accepts drops" state (during 3923e7c7634531302271270c8cf418abc959d621cbcMichael Jurka // a drag). However, we also drag the mini hover background *over* one of those two 3933e7c7634531302271270c8cf418abc959d621cbcMichael Jurka // backgrounds 394b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung if (mBackgroundAlpha > 0.0f) { 395f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen Drawable bg; 39633945b21544bc98381df17726a3537c292d8c985Michael Jurka 39733945b21544bc98381df17726a3537c292d8c985Michael Jurka if (mIsDragOverlapping) { 39833945b21544bc98381df17726a3537c292d8c985Michael Jurka // In the mini case, we draw the active_glow bg *over* the active background 399bdf78559f223ac11e01e3311edd5a48a80383e1eMichael Jurka bg = mActiveGlowBackground; 400f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen } else { 401bdf78559f223ac11e01e3311edd5a48a80383e1eMichael Jurka bg = mNormalBackground; 402f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen } 40333945b21544bc98381df17726a3537c292d8c985Michael Jurka 40433945b21544bc98381df17726a3537c292d8c985Michael Jurka bg.setAlpha((int) (mBackgroundAlpha * mBackgroundAlphaMultiplier * 255)); 40533945b21544bc98381df17726a3537c292d8c985Michael Jurka bg.setBounds(mBackgroundRect); 40633945b21544bc98381df17726a3537c292d8c985Michael Jurka bg.draw(canvas); 407a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka } 40831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 4098e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy final Paint paint = mDragOutlinePaint; 4104be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato for (int i = 0; i < mDragOutlines.length; i++) { 411472b281d5cb4f5660df981a6c912266b9f5703feChet Haase final float alpha = mDragOutlineAlphas[i]; 4124be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato if (alpha > 0) { 413d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen final Rect r = mDragOutlines[i]; 4144be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato final Bitmap b = (Bitmap) mDragOutlineAnims[i].getTag(); 415472b281d5cb4f5660df981a6c912266b9f5703feChet Haase paint.setAlpha((int)(alpha + .5f)); 416d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen canvas.drawBitmap(b, null, r, paint); 417150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung } 4186569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy } 41996864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy 42096864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy // We draw the pressed or focused BubbleTextView's background in CellLayout because it 42196864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy // requires an expanded clip rect (due to the glow's blur radius) 42296864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy if (mPressedOrFocusedIcon != null) { 42396864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy final int padding = mPressedOrFocusedIcon.getPressedOrFocusedBackgroundPadding(); 42496864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy final Bitmap b = mPressedOrFocusedIcon.getPressedOrFocusedBackground(); 42596864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy if (b != null) { 42696864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy canvas.drawBitmap(b, 4274b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung mPressedOrFocusedIcon.getLeft() + getPaddingLeft() - padding, 4284b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung mPressedOrFocusedIcon.getTop() + getPaddingTop() - padding, 42996864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy null); 43096864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy } 43196864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy } 43269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 433482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (DEBUG_VISUALIZE_OCCUPIED) { 434482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int[] pt = new int[2]; 435482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen ColorDrawable cd = new ColorDrawable(Color.RED); 436482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen cd.setBounds(0, 0, 80, 80); 437482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < mCountX; i++) { 438482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int j = 0; j < mCountY; j++) { 439482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (mOccupied[i][j]) { 440482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen cellToPoint(i, j, pt); 441482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen canvas.save(); 442482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen canvas.translate(pt[0], pt[1]); 443482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen cd.draw(canvas); 444482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen canvas.restore(); 445482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 446482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 447482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 448482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 449482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 45069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen // The folder outer / inner ring image(s) 45169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen for (int i = 0; i < mFolderOuterRings.size(); i++) { 45269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen FolderRingAnimator fra = mFolderOuterRings.get(i); 45369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 45469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen // Draw outer ring 45569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen Drawable d = FolderRingAnimator.sSharedOuterRingDrawable; 45669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen int width = (int) fra.getOuterRingSize(); 45769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen int height = width; 45869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen cellToPoint(fra.mCellX, fra.mCellY, mTempLocation); 45969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 46069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen int centerX = mTempLocation[0] + mCellWidth / 2; 46169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen int centerY = mTempLocation[1] + FolderRingAnimator.sPreviewSize / 2; 46269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 46369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen canvas.save(); 46469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen canvas.translate(centerX - width / 2, centerY - height / 2); 46569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen d.setBounds(0, 0, width, height); 46669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen d.draw(canvas); 46769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen canvas.restore(); 46869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 46969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen // Draw inner ring 47069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen d = FolderRingAnimator.sSharedInnerRingDrawable; 47169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen width = (int) fra.getInnerRingSize(); 47269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen height = width; 47369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen cellToPoint(fra.mCellX, fra.mCellY, mTempLocation); 47469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 47569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen centerX = mTempLocation[0] + mCellWidth / 2; 47669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen centerY = mTempLocation[1] + FolderRingAnimator.sPreviewSize / 2; 47769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen canvas.save(); 47869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen canvas.translate(centerX - width / 2, centerY - width / 2); 47969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen d.setBounds(0, 0, width, height); 48069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen d.draw(canvas); 48169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen canvas.restore(); 48269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen } 483c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen 484c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen if (mFolderLeaveBehindCell[0] >= 0 && mFolderLeaveBehindCell[1] >= 0) { 485c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen Drawable d = FolderIcon.sSharedFolderLeaveBehind; 486c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen int width = d.getIntrinsicWidth(); 487c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen int height = d.getIntrinsicHeight(); 488c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen 489c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen cellToPoint(mFolderLeaveBehindCell[0], mFolderLeaveBehindCell[1], mTempLocation); 490c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen int centerX = mTempLocation[0] + mCellWidth / 2; 491c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen int centerY = mTempLocation[1] + FolderRingAnimator.sPreviewSize / 2; 492c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen 493c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen canvas.save(); 494c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen canvas.translate(centerX - width / 2, centerY - width / 2); 495c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen d.setBounds(0, 0, width, height); 496c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen d.draw(canvas); 497c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen canvas.restore(); 498c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen } 49969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen } 50069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 501b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen @Override 502b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen protected void dispatchDraw(Canvas canvas) { 503b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen super.dispatchDraw(canvas); 504b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen if (mForegroundAlpha > 0) { 505b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mOverScrollForegroundDrawable.setBounds(mForegroundRect); 506b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen Paint p = ((NinePatchDrawable) mOverScrollForegroundDrawable).getPaint(); 507b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen p.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.ADD)); 508b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mOverScrollForegroundDrawable.draw(canvas); 509b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen p.setXfermode(null); 510b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen } 511b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen } 512b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen 51369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen public void showFolderAccept(FolderRingAnimator fra) { 51469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen mFolderOuterRings.add(fra); 51569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen } 51669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 51769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen public void hideFolderAccept(FolderRingAnimator fra) { 51869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen if (mFolderOuterRings.contains(fra)) { 51969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen mFolderOuterRings.remove(fra); 52069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen } 52169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen invalidate(); 5226569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy } 5236569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 524c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen public void setFolderLeaveBehindCell(int x, int y) { 525c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen mFolderLeaveBehindCell[0] = x; 526c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen mFolderLeaveBehindCell[1] = y; 527c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen invalidate(); 528c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen } 529c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen 530c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen public void clearFolderLeaveBehind() { 531c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen mFolderLeaveBehindCell[0] = -1; 532c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen mFolderLeaveBehindCell[1] = -1; 533c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen invalidate(); 534c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen } 535c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen 5366569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy @Override 537e6235dd225404239b55c459245543f3302326112Michael Jurka public boolean shouldDelayChildPressedState() { 538e6235dd225404239b55c459245543f3302326112Michael Jurka return false; 539e6235dd225404239b55c459245543f3302326112Michael Jurka } 540e6235dd225404239b55c459245543f3302326112Michael Jurka 541e6235dd225404239b55c459245543f3302326112Michael Jurka @Override 54283f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey public void cancelLongPress() { 54383f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey super.cancelLongPress(); 54483f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey 54583f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey // Cancel long press for all children 54683f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey final int count = getChildCount(); 54783f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey for (int i = 0; i < count; i++) { 54883f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey final View child = getChildAt(i); 54983f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey child.cancelLongPress(); 55083f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey } 55183f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey } 55283f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey 553dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka public void setOnInterceptTouchListener(View.OnTouchListener listener) { 554dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka mInterceptTouchListener = listener; 555dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } 556dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka 55731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int getCountX() { 558d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen return mCountX; 55931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 56031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 56131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int getCountY() { 562d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen return mCountY; 56331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 56431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 5650dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn public void setIsHotseat(boolean isHotseat) { 5660dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn mIsHotseat = isHotseat; 5670dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn } 5680dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn 569eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung public float getChildrenScale() { 570eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung return mIsHotseat ? mHotseatChildScale : mChildScale; 571eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung } 572eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung 573f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka public boolean addViewToCellLayout( 574f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka View child, int index, int childId, LayoutParams params, boolean markCells) { 5750dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn return addViewToCellLayout(child, index, childId, params, markCells, false); 5760dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn } 5770dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn 578eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung private void scaleChild(BubbleTextView bubbleChild, float pivot, float scale) { 579bc239a15464f543a41b960b946aa77258454efafAndrew Flynn // If we haven't measured the child yet, do it now 580bc239a15464f543a41b960b946aa77258454efafAndrew Flynn // (this happens if we're being dropped from all-apps 581bc239a15464f543a41b960b946aa77258454efafAndrew Flynn if (bubbleChild.getLayoutParams() instanceof LayoutParams && 582bc239a15464f543a41b960b946aa77258454efafAndrew Flynn (bubbleChild.getMeasuredWidth() | bubbleChild.getMeasuredHeight()) == 0) { 583a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka getShortcutsAndWidgets().measureChild(bubbleChild); 584bc239a15464f543a41b960b946aa77258454efafAndrew Flynn } 585bc239a15464f543a41b960b946aa77258454efafAndrew Flynn 586bc239a15464f543a41b960b946aa77258454efafAndrew Flynn bubbleChild.setScaleX(scale); 587bc239a15464f543a41b960b946aa77258454efafAndrew Flynn bubbleChild.setScaleY(scale); 588bc239a15464f543a41b960b946aa77258454efafAndrew Flynn } 589bc239a15464f543a41b960b946aa77258454efafAndrew Flynn 590bc239a15464f543a41b960b946aa77258454efafAndrew Flynn private void resetChild(BubbleTextView bubbleChild) { 591bc239a15464f543a41b960b946aa77258454efafAndrew Flynn bubbleChild.setScaleX(1f); 592bc239a15464f543a41b960b946aa77258454efafAndrew Flynn bubbleChild.setScaleY(1f); 593bc239a15464f543a41b960b946aa77258454efafAndrew Flynn 594bc239a15464f543a41b960b946aa77258454efafAndrew Flynn bubbleChild.setTextColor(getResources().getColor(R.color.workspace_icon_text_color)); 595bc239a15464f543a41b960b946aa77258454efafAndrew Flynn } 596bc239a15464f543a41b960b946aa77258454efafAndrew Flynn 5970dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn public boolean addViewToCellLayout(View child, int index, int childId, LayoutParams params, 5980dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn boolean markCells, boolean allApps) { 599aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung final LayoutParams lp = params; 600aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 6010dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn // Hotseat icons - scale down and remove text 6020dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn // Don't scale the all apps button 6030dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn // scale percent set to -1 means do not scale 6040dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn // Only scale BubbleTextViews 6050dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn if (child instanceof BubbleTextView) { 6060dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn BubbleTextView bubbleChild = (BubbleTextView) child; 6070dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn 608bc239a15464f543a41b960b946aa77258454efafAndrew Flynn // Start the child with 100% scale and visible text 609bc239a15464f543a41b960b946aa77258454efafAndrew Flynn resetChild(bubbleChild); 610bc239a15464f543a41b960b946aa77258454efafAndrew Flynn 611eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung if (mIsHotseat && !allApps && mHotseatChildScale >= 0) { 612bc239a15464f543a41b960b946aa77258454efafAndrew Flynn // Scale/make transparent for a hotseat 613eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung scaleChild(bubbleChild, 0f, mHotseatChildScale); 6140dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn 615bc239a15464f543a41b960b946aa77258454efafAndrew Flynn bubbleChild.setTextColor(getResources().getColor(android.R.color.transparent)); 616eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung } else if (mChildScale >= 0) { 617bc239a15464f543a41b960b946aa77258454efafAndrew Flynn // Else possibly still scale it if we need to for smaller icons 618eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung scaleChild(bubbleChild, 0f, mChildScale); 6190dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn } 6200dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn } 6210dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn 62231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // Generate an id for each view, this assumes we have at most 256x256 cells 62331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // per workspace screen 624d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen if (lp.cellX >= 0 && lp.cellX <= mCountX - 1 && lp.cellY >= 0 && lp.cellY <= mCountY - 1) { 625aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung // If the horizontal or vertical span is set to -1, it is taken to 626aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung // mean that it spans the extent of the CellLayout 627d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen if (lp.cellHSpan < 0) lp.cellHSpan = mCountX; 628d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen if (lp.cellVSpan < 0) lp.cellVSpan = mCountY; 629aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 630aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung child.setId(childId); 63131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 632a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.addView(child, index, lp); 633dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka 634f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka if (markCells) markCellsAsOccupiedForView(child); 6350280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 636aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung return true; 637aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung } 638aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung return false; 63931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 6403e7c7634531302271270c8cf418abc959d621cbcMichael Jurka 64131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 6420280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka public void removeAllViews() { 6430280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka clearOccupiedCells(); 644a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.removeAllViews(); 6450280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 6460280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 6470280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka @Override 6480280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka public void removeAllViewsInLayout() { 649a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka if (mShortcutsAndWidgets.getChildCount() > 0) { 6507cfc2825c3a1029f962d2fc387ae2eaa85b51798Michael Jurka clearOccupiedCells(); 651a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.removeAllViewsInLayout(); 6527cfc2825c3a1029f962d2fc387ae2eaa85b51798Michael Jurka } 6530280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 6540280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 655f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka public void removeViewWithoutMarkingCells(View view) { 656a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.removeView(view); 657f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka } 658f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka 6590280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka @Override 6600280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka public void removeView(View view) { 6610280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka markCellsAsUnoccupiedForView(view); 662a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.removeView(view); 6630280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 6640280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 6650280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka @Override 6660280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka public void removeViewAt(int index) { 667a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka markCellsAsUnoccupiedForView(mShortcutsAndWidgets.getChildAt(index)); 668a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.removeViewAt(index); 6690280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 6700280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 6710280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka @Override 6720280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka public void removeViewInLayout(View view) { 6730280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka markCellsAsUnoccupiedForView(view); 674a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.removeViewInLayout(view); 6750280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 6760280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 6770280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka @Override 6780280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka public void removeViews(int start, int count) { 6790280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka for (int i = start; i < start + count; i++) { 680a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka markCellsAsUnoccupiedForView(mShortcutsAndWidgets.getChildAt(i)); 6810280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 682a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.removeViews(start, count); 6830280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 6840280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 6850280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka @Override 6860280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka public void removeViewsInLayout(int start, int count) { 6870280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka for (int i = start; i < start + count; i++) { 688a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka markCellsAsUnoccupiedForView(mShortcutsAndWidgets.getChildAt(i)); 6890280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 690a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.removeViewsInLayout(start, count); 691abded66084680bb31cc7ea403c88f44f79a3c884Michael Jurka } 692abded66084680bb31cc7ea403c88f44f79a3c884Michael Jurka 69331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 69431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected void onAttachedToWindow() { 69531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project super.onAttachedToWindow(); 69631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mCellInfo.screen = ((ViewGroup) getParent()).indexOfChild(this); 69731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 69831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 699af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka public void setTagToCellInfoForPoint(int touchX, int touchY) { 70031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final CellInfo cellInfo = mCellInfo; 701eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung Rect frame = mRect; 7028b805b17158886035b38261eb611d8641701ae43Michael Jurka final int x = touchX + getScrollX(); 7038b805b17158886035b38261eb611d8641701ae43Michael Jurka final int y = touchY + getScrollY(); 704a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka final int count = mShortcutsAndWidgets.getChildCount(); 70531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 706af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka boolean found = false; 707af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka for (int i = count - 1; i >= 0; i--) { 708a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka final View child = mShortcutsAndWidgets.getChildAt(i); 709d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 710af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka 7111b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen if ((child.getVisibility() == VISIBLE || child.getAnimation() != null) && 7121b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen lp.isLockedToGrid) { 713af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka child.getHitRect(frame); 7140be025d64c1f84138fe430a58875886e66aae767Winson Chung 715eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung float scale = child.getScaleX(); 716eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung frame = new Rect(child.getLeft(), child.getTop(), child.getRight(), 717eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung child.getBottom()); 7180be025d64c1f84138fe430a58875886e66aae767Winson Chung // The child hit rect is relative to the CellLayoutChildren parent, so we need to 7190be025d64c1f84138fe430a58875886e66aae767Winson Chung // offset that by this CellLayout's padding to test an (x,y) point that is relative 7200be025d64c1f84138fe430a58875886e66aae767Winson Chung // to this view. 7218b805b17158886035b38261eb611d8641701ae43Michael Jurka frame.offset(getPaddingLeft(), getPaddingTop()); 722eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung frame.inset((int) (frame.width() * (1f - scale) / 2), 723eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung (int) (frame.height() * (1f - scale) / 2)); 7240be025d64c1f84138fe430a58875886e66aae767Winson Chung 725af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka if (frame.contains(x, y)) { 726af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.cell = child; 727af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.cellX = lp.cellX; 728af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.cellY = lp.cellY; 729af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.spanX = lp.cellHSpan; 730af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.spanY = lp.cellVSpan; 731af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka found = true; 732af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka break; 73331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 73431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 735af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka } 736aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 737d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka mLastDownOnOccupiedCell = found; 738d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka 739af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka if (!found) { 7400be025d64c1f84138fe430a58875886e66aae767Winson Chung final int cellXY[] = mTmpXY; 741af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka pointToCellExact(x, y, cellXY); 74231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 743af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.cell = null; 744af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.cellX = cellXY[0]; 745af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.cellY = cellXY[1]; 746af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.spanX = 1; 747af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.spanY = 1; 748af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka } 749af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka setTag(cellInfo); 750af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka } 75131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 752af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka @Override 753af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka public boolean onInterceptTouchEvent(MotionEvent ev) { 754c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen // First we clear the tag to ensure that on every touch down we start with a fresh slate, 755c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen // even in the case where we return early. Not clearing here was causing bugs whereby on 756c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen // long-press we'd end up picking up an item from a previous drag operation. 757c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen final int action = ev.getAction(); 758c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen 759c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen if (action == MotionEvent.ACTION_DOWN) { 760c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen clearTagCellInfo(); 761c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen } 762c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen 763dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka if (mInterceptTouchListener != null && mInterceptTouchListener.onTouch(this, ev)) { 764dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka return true; 765dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } 76631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 767af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka if (action == MotionEvent.ACTION_DOWN) { 768af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka setTagToCellInfoForPoint((int) ev.getX(), (int) ev.getY()); 76931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 770eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung 77131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return false; 77231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 77331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 774c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen private void clearTagCellInfo() { 775c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen final CellInfo cellInfo = mCellInfo; 776c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen cellInfo.cell = null; 777c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen cellInfo.cellX = -1; 778c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen cellInfo.cellY = -1; 779c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen cellInfo.spanX = 0; 780c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen cellInfo.spanY = 0; 781c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen setTag(cellInfo); 782c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen } 783c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen 78431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public CellInfo getTag() { 7850280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka return (CellInfo) super.getTag(); 78631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 78731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 7886569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy /** 789aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * Given a point, return the cell that strictly encloses that point 79031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param x X coordinate of the point 79131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param y Y coordinate of the point 79231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param result Array of 2 ints to hold the x and y coordinate of the cell 79331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 79431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project void pointToCellExact(int x, int y, int[] result) { 7954b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung final int hStartPadding = getPaddingLeft(); 7964b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung final int vStartPadding = getPaddingTop(); 79731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 79831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project result[0] = (x - hStartPadding) / (mCellWidth + mWidthGap); 79931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project result[1] = (y - vStartPadding) / (mCellHeight + mHeightGap); 80031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 801d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen final int xAxis = mCountX; 802d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen final int yAxis = mCountY; 80331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 80431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (result[0] < 0) result[0] = 0; 80531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (result[0] >= xAxis) result[0] = xAxis - 1; 80631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (result[1] < 0) result[1] = 0; 80731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (result[1] >= yAxis) result[1] = yAxis - 1; 80831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 809aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 81031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 81131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Given a point, return the cell that most closely encloses that point 81231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param x X coordinate of the point 81331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param y Y coordinate of the point 81431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param result Array of 2 ints to hold the x and y coordinate of the cell 81531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 81631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project void pointToCellRounded(int x, int y, int[] result) { 81731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project pointToCellExact(x + (mCellWidth / 2), y + (mCellHeight / 2), result); 81831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 81931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 82031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 82131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Given a cell coordinate, return the point that represents the upper left corner of that cell 822aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * 823aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * @param cellX X coordinate of the cell 82431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param cellY Y coordinate of the cell 825aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * 82631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param result Array of 2 ints to hold the x and y coordinate of the point 82731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 82831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project void cellToPoint(int cellX, int cellY, int[] result) { 8294b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung final int hStartPadding = getPaddingLeft(); 8304b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung final int vStartPadding = getPaddingTop(); 83131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 83231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project result[0] = hStartPadding + cellX * (mCellWidth + mWidthGap); 83331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project result[1] = vStartPadding + cellY * (mCellHeight + mHeightGap); 83431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 83531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 836e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen /** 837482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * Given a cell coordinate, return the point that represents the center of the cell 838e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen * 839e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen * @param cellX X coordinate of the cell 840e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen * @param cellY Y coordinate of the cell 841e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen * 842e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen * @param result Array of 2 ints to hold the x and y coordinate of the point 843e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen */ 844e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen void cellToCenterPoint(int cellX, int cellY, int[] result) { 84547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen regionToCenterPoint(cellX, cellY, 1, 1, result); 84647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 84747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 84847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen /** 84947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * Given a cell coordinate and span return the point that represents the center of the regio 85047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * 85147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param cellX X coordinate of the cell 85247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param cellY Y coordinate of the cell 85347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * 85447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param result Array of 2 ints to hold the x and y coordinate of the point 85547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen */ 85647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen void regionToCenterPoint(int cellX, int cellY, int spanX, int spanY, int[] result) { 8574b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung final int hStartPadding = getPaddingLeft(); 8584b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung final int vStartPadding = getPaddingTop(); 85947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen result[0] = hStartPadding + cellX * (mCellWidth + mWidthGap) + 86047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen (spanX * mCellWidth + (spanX - 1) * mWidthGap) / 2; 86147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen result[1] = vStartPadding + cellY * (mCellHeight + mHeightGap) + 86247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen (spanY * mCellHeight + (spanY - 1) * mHeightGap) / 2; 863e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen } 864e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen 86519f3792523fe2d55ea791a9286398a6120920690Adam Cohen /** 86619f3792523fe2d55ea791a9286398a6120920690Adam Cohen * Given a cell coordinate and span fills out a corresponding pixel rect 86719f3792523fe2d55ea791a9286398a6120920690Adam Cohen * 86819f3792523fe2d55ea791a9286398a6120920690Adam Cohen * @param cellX X coordinate of the cell 86919f3792523fe2d55ea791a9286398a6120920690Adam Cohen * @param cellY Y coordinate of the cell 87019f3792523fe2d55ea791a9286398a6120920690Adam Cohen * @param result Rect in which to write the result 87119f3792523fe2d55ea791a9286398a6120920690Adam Cohen */ 87219f3792523fe2d55ea791a9286398a6120920690Adam Cohen void regionToRect(int cellX, int cellY, int spanX, int spanY, Rect result) { 87319f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int hStartPadding = getPaddingLeft(); 87419f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int vStartPadding = getPaddingTop(); 87519f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int left = hStartPadding + cellX * (mCellWidth + mWidthGap); 87619f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int top = vStartPadding + cellY * (mCellHeight + mHeightGap); 87719f3792523fe2d55ea791a9286398a6120920690Adam Cohen result.set(left, top, left + (spanX * mCellWidth + (spanX - 1) * mWidthGap), 87819f3792523fe2d55ea791a9286398a6120920690Adam Cohen top + (spanY * mCellHeight + (spanY - 1) * mHeightGap)); 87919f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 88019f3792523fe2d55ea791a9286398a6120920690Adam Cohen 881482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public float getDistanceFromCell(float x, float y, int[] cell) { 882482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen cellToCenterPoint(cell[0], cell[1], mTmpPoint); 883482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen float distance = (float) Math.sqrt( Math.pow(x - mTmpPoint[0], 2) + 884482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen Math.pow(y - mTmpPoint[1], 2)); 885482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return distance; 886482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 887482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 88884f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy int getCellWidth() { 88984f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy return mCellWidth; 89084f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy } 89184f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy 89284f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy int getCellHeight() { 89384f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy return mCellHeight; 89484f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy } 89584f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy 896d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen int getWidthGap() { 897d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen return mWidthGap; 898d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen } 899d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen 900d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen int getHeightGap() { 901d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen return mHeightGap; 902d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen } 903d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen 9047f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen Rect getContentRect(Rect r) { 9057f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen if (r == null) { 9067f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen r = new Rect(); 9077f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 9087f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen int left = getPaddingLeft(); 9097f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen int top = getPaddingTop(); 9108b805b17158886035b38261eb611d8641701ae43Michael Jurka int right = left + getWidth() - getPaddingLeft() - getPaddingRight(); 9118b805b17158886035b38261eb611d8641701ae43Michael Jurka int bottom = top + getHeight() - getPaddingTop() - getPaddingBottom(); 9127f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen r.set(left, top, right, bottom); 9137f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen return r; 9147f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 9157f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 916a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen static void getMetrics(Rect metrics, Resources res, int measureWidth, int measureHeight, 917a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen int countX, int countY, int orientation) { 918a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen int numWidthGaps = countX - 1; 919a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen int numHeightGaps = countY - 1; 920f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen 921f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen int widthGap; 922f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen int heightGap; 923f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen int cellWidth; 924f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen int cellHeight; 925f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen int paddingLeft; 926f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen int paddingRight; 927f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen int paddingTop; 928f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen int paddingBottom; 929f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen 930a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen int maxGap = res.getDimensionPixelSize(R.dimen.workspace_max_gap); 931f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen if (orientation == LANDSCAPE) { 932f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen cellWidth = res.getDimensionPixelSize(R.dimen.workspace_cell_width_land); 933f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen cellHeight = res.getDimensionPixelSize(R.dimen.workspace_cell_height_land); 934f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen widthGap = res.getDimensionPixelSize(R.dimen.workspace_width_gap_land); 935f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen heightGap = res.getDimensionPixelSize(R.dimen.workspace_height_gap_land); 936f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen paddingLeft = res.getDimensionPixelSize(R.dimen.cell_layout_left_padding_land); 937f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen paddingRight = res.getDimensionPixelSize(R.dimen.cell_layout_right_padding_land); 938f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen paddingTop = res.getDimensionPixelSize(R.dimen.cell_layout_top_padding_land); 939f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen paddingBottom = res.getDimensionPixelSize(R.dimen.cell_layout_bottom_padding_land); 940f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen } else { 941f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen // PORTRAIT 942f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen cellWidth = res.getDimensionPixelSize(R.dimen.workspace_cell_width_port); 943f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen cellHeight = res.getDimensionPixelSize(R.dimen.workspace_cell_height_port); 944f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen widthGap = res.getDimensionPixelSize(R.dimen.workspace_width_gap_port); 945f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen heightGap = res.getDimensionPixelSize(R.dimen.workspace_height_gap_port); 946f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen paddingLeft = res.getDimensionPixelSize(R.dimen.cell_layout_left_padding_port); 947f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen paddingRight = res.getDimensionPixelSize(R.dimen.cell_layout_right_padding_port); 948f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen paddingTop = res.getDimensionPixelSize(R.dimen.cell_layout_top_padding_port); 949f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen paddingBottom = res.getDimensionPixelSize(R.dimen.cell_layout_bottom_padding_port); 950f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen } 951f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen 952f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen if (widthGap < 0 || heightGap < 0) { 953f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen int hSpace = measureWidth - paddingLeft - paddingRight; 954f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen int vSpace = measureHeight - paddingTop - paddingBottom; 955a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen int hFreeSpace = hSpace - (countX * cellWidth); 956a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen int vFreeSpace = vSpace - (countY * cellHeight); 957a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen widthGap = Math.min(maxGap, numWidthGaps > 0 ? (hFreeSpace / numWidthGaps) : 0); 958a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen heightGap = Math.min(maxGap, numHeightGaps > 0 ? (vFreeSpace / numHeightGaps) : 0); 959f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen } 960f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen metrics.set(cellWidth, cellHeight, widthGap, heightGap); 961f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen } 962f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen 96331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 96431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 96531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec); 966aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec); 967aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 96831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec); 96931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec); 970aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 97131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (widthSpecMode == MeasureSpec.UNSPECIFIED || heightSpecMode == MeasureSpec.UNSPECIFIED) { 97231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project throw new RuntimeException("CellLayout cannot have UNSPECIFIED dimensions"); 97331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 97431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 975d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen int numWidthGaps = mCountX - 1; 976d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen int numHeightGaps = mCountY - 1; 977d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen 978234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen if (mOriginalWidthGap < 0 || mOriginalHeightGap < 0) { 979dd13e3d0f9925b7bb80c37e21d039aab4fa7e7a1Michael Jurka int hSpace = widthSpecSize - getPaddingLeft() - getPaddingRight(); 980dd13e3d0f9925b7bb80c37e21d039aab4fa7e7a1Michael Jurka int vSpace = heightSpecSize - getPaddingTop() - getPaddingBottom(); 981f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen int hFreeSpace = hSpace - (mCountX * mCellWidth); 982f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen int vFreeSpace = vSpace - (mCountY * mCellHeight); 9834b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung mWidthGap = Math.min(mMaxGap, numWidthGaps > 0 ? (hFreeSpace / numWidthGaps) : 0); 9844b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung mHeightGap = Math.min(mMaxGap,numHeightGaps > 0 ? (vFreeSpace / numHeightGaps) : 0); 985a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.setCellDimensions(mCellWidth, mCellHeight, mWidthGap, mHeightGap); 986234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen } else { 987234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen mWidthGap = mOriginalWidthGap; 988234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen mHeightGap = mOriginalHeightGap; 989ece7f5b3b55cab646941123e03589241a61678e2Winson Chung } 9905f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka 9918c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka // Initial values correspond to widthSpecMode == MeasureSpec.EXACTLY 9928c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka int newWidth = widthSpecSize; 9938c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka int newHeight = heightSpecSize; 9948c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka if (widthSpecMode == MeasureSpec.AT_MOST) { 9958b805b17158886035b38261eb611d8641701ae43Michael Jurka newWidth = getPaddingLeft() + getPaddingRight() + (mCountX * mCellWidth) + 9968c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka ((mCountX - 1) * mWidthGap); 9978b805b17158886035b38261eb611d8641701ae43Michael Jurka newHeight = getPaddingTop() + getPaddingBottom() + (mCountY * mCellHeight) + 9988c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka ((mCountY - 1) * mHeightGap); 9998c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka setMeasuredDimension(newWidth, newHeight); 10008c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka } 100131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 10028c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka int count = getChildCount(); 100331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int i = 0; i < count; i++) { 100431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project View child = getChildAt(i); 10058b805b17158886035b38261eb611d8641701ae43Michael Jurka int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(newWidth - getPaddingLeft() - 10068b805b17158886035b38261eb611d8641701ae43Michael Jurka getPaddingRight(), MeasureSpec.EXACTLY); 10078b805b17158886035b38261eb611d8641701ae43Michael Jurka int childheightMeasureSpec = MeasureSpec.makeMeasureSpec(newHeight - getPaddingTop() - 10088b805b17158886035b38261eb611d8641701ae43Michael Jurka getPaddingBottom(), MeasureSpec.EXACTLY); 100931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project child.measure(childWidthMeasureSpec, childheightMeasureSpec); 101031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 10118c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka setMeasuredDimension(newWidth, newHeight); 101231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 101331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 101431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 101528750fba6a2d141eb9a1e566718c17236030b815Michael Jurka protected void onLayout(boolean changed, int l, int t, int r, int b) { 101631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int count = getChildCount(); 101731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int i = 0; i < count; i++) { 10188c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka View child = getChildAt(i); 10198b805b17158886035b38261eb611d8641701ae43Michael Jurka child.layout(getPaddingLeft(), getPaddingTop(), 10208b805b17158886035b38261eb611d8641701ae43Michael Jurka r - l - getPaddingRight(), b - t - getPaddingBottom()); 102131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 102231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 102331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 102431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 1025dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka protected void onSizeChanged(int w, int h, int oldw, int oldh) { 1026dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka super.onSizeChanged(w, h, oldw, oldh); 102718014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka mBackgroundRect.set(0, 0, w, h); 1028b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mForegroundRect.set(mForegroundPadding, mForegroundPadding, 1029b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen w - 2 * mForegroundPadding, h - 2 * mForegroundPadding); 1030dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } 1031dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka 1032dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka @Override 103331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected void setChildrenDrawingCacheEnabled(boolean enabled) { 1034a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.setChildrenDrawingCacheEnabled(enabled); 103531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 103631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 103731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 103831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected void setChildrenDrawnWithCacheEnabled(boolean enabled) { 1039a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.setChildrenDrawnWithCacheEnabled(enabled); 104031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 104131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 10425f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka public float getBackgroundAlpha() { 10435f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka return mBackgroundAlpha; 1044dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } 1045dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka 10461b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen public void setBackgroundAlphaMultiplier(float multiplier) { 10471b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen mBackgroundAlphaMultiplier = multiplier; 10481b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen } 10491b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen 1050ddb821981e0919bbd3b4c9a2b6aa1811d6c86bb6Adam Cohen public float getBackgroundAlphaMultiplier() { 1051ddb821981e0919bbd3b4c9a2b6aa1811d6c86bb6Adam Cohen return mBackgroundAlphaMultiplier; 1052ddb821981e0919bbd3b4c9a2b6aa1811d6c86bb6Adam Cohen } 1053ddb821981e0919bbd3b4c9a2b6aa1811d6c86bb6Adam Cohen 10545f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka public void setBackgroundAlpha(float alpha) { 1055afaa05014e0bf3ed1192f9ddec2af4283bc50248Michael Jurka if (mBackgroundAlpha != alpha) { 1056afaa05014e0bf3ed1192f9ddec2af4283bc50248Michael Jurka mBackgroundAlpha = alpha; 1057afaa05014e0bf3ed1192f9ddec2af4283bc50248Michael Jurka invalidate(); 1058afaa05014e0bf3ed1192f9ddec2af4283bc50248Michael Jurka } 1059dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } 1060dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka 1061a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka public void setShortcutAndWidgetAlpha(float alpha) { 10620142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka final int childCount = getChildCount(); 10630142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka for (int i = 0; i < childCount; i++) { 1064dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka getChildAt(i).setAlpha(alpha); 1065dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } 1066dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } 1067dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka 1068a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka public ShortcutAndWidgetContainer getShortcutsAndWidgets() { 1069a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka if (getChildCount() > 0) { 1070a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka return (ShortcutAndWidgetContainer) getChildAt(0); 1071a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka } 1072a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka return null; 1073a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka } 1074a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka 1075440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy public View getChildAt(int x, int y) { 1076a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka return mShortcutsAndWidgets.getChildAt(x, y); 1077440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy } 1078440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy 107976fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen public boolean animateChildToPosition(final View child, int cellX, int cellY, int duration, 1080482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int delay, boolean permanent, boolean adjustOccupied) { 1081a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka ShortcutAndWidgetContainer clc = getShortcutsAndWidgets(); 1082482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean[][] occupied = mOccupied; 1083482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (!permanent) { 1084482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen occupied = mTmpOccupied; 1085482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1086482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 108719f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (clc.indexOfChild(child) != -1) { 1088bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 1089bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen final ItemInfo info = (ItemInfo) child.getTag(); 1090bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen 1091bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen // We cancel any existing animations 1092bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen if (mReorderAnimators.containsKey(lp)) { 1093bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen mReorderAnimators.get(lp).cancel(); 1094bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen mReorderAnimators.remove(lp); 1095bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 1096bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen 1097482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int oldX = lp.x; 1098482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int oldY = lp.y; 1099482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (adjustOccupied) { 1100482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen occupied[lp.cellX][lp.cellY] = false; 1101482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen occupied[cellX][cellY] = true; 1102482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1103bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen lp.isLockedToGrid = true; 1104482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (permanent) { 1105482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen lp.cellX = info.cellX = cellX; 1106482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen lp.cellY = info.cellY = cellY; 1107482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } else { 1108482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen lp.tmpCellX = cellX; 1109482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen lp.tmpCellY = cellY; 1110482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1111bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen clc.setupLp(lp); 1112bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen lp.isLockedToGrid = false; 1113482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int newX = lp.x; 1114482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int newY = lp.y; 1115bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen 111676fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen lp.x = oldX; 111776fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen lp.y = oldY; 111876fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen 1119482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // Exit early if we're not actually moving the view 1120482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (oldX == newX && oldY == newY) { 1121482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen lp.isLockedToGrid = true; 1122482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return true; 1123482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1124482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1125482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen ValueAnimator va = ValueAnimator.ofFloat(0f, 1f); 1126482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen va.setDuration(duration); 1127482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mReorderAnimators.put(lp, va); 1128482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1129482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen va.addUpdateListener(new AnimatorUpdateListener() { 1130482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen @Override 1131bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen public void onAnimationUpdate(ValueAnimator animation) { 1132482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen float r = ((Float) animation.getAnimatedValue()).floatValue(); 113319f3792523fe2d55ea791a9286398a6120920690Adam Cohen lp.x = (int) ((1 - r) * oldX + r * newX); 113419f3792523fe2d55ea791a9286398a6120920690Adam Cohen lp.y = (int) ((1 - r) * oldY + r * newY); 11356b8a02d63a5d9cab8209381993e37db6a6afb753Adam Cohen child.requestLayout(); 1136bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 1137bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen }); 1138482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen va.addListener(new AnimatorListenerAdapter() { 1139bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen boolean cancelled = false; 1140bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen public void onAnimationEnd(Animator animation) { 1141bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen // If the animation was cancelled, it means that another animation 1142bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen // has interrupted this one, and we don't want to lock the item into 1143bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen // place just yet. 1144bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen if (!cancelled) { 1145bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen lp.isLockedToGrid = true; 1146482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen child.requestLayout(); 1147bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 1148bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen if (mReorderAnimators.containsKey(lp)) { 1149bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen mReorderAnimators.remove(lp); 1150bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 1151bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 1152bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen public void onAnimationCancel(Animator animation) { 1153bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen cancelled = true; 1154bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 1155bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen }); 1156482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen va.setStartDelay(delay); 1157482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen va.start(); 1158bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen return true; 1159bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 1160bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen return false; 1161bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 1162bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen 11636569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy /** 11646569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy * Estimate where the top left cell of the dragged item will land if it is dropped. 11656569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy * 11666569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy * @param originX The X value of the top left corner of the item 11676569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy * @param originY The Y value of the top left corner of the item 11686569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy * @param spanX The number of horizontal cells that the item spans 11696569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy * @param spanY The number of vertical cells that the item spans 11706569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy * @param result The estimated drop cell X and Y. 11716569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy */ 11726569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy void estimateDropCell(int originX, int originY, int spanX, int spanY, int[] result) { 1173d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen final int countX = mCountX; 1174d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen final int countY = mCountY; 11756569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 1176a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka // pointToCellRounded takes the top left of a cell but will pad that with 1177a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka // cellWidth/2 and cellHeight/2 when finding the matching cell 1178a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka pointToCellRounded(originX, originY, result); 11796569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 11806569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy // If the item isn't fully on this screen, snap to the edges 11816569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy int rightOverhang = result[0] + spanX - countX; 11826569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy if (rightOverhang > 0) { 11836569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy result[0] -= rightOverhang; // Snap to right 11846569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy } 11856569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy result[0] = Math.max(0, result[0]); // Snap to left 11866569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy int bottomOverhang = result[1] + spanY - countY; 11876569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy if (bottomOverhang > 0) { 11886569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy result[1] -= bottomOverhang; // Snap to bottom 11896569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy } 11906569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy result[1] = Math.max(0, result[1]); // Snap to top 11916569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy } 11926569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 1193482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen void visualizeDropLocation(View v, Bitmap dragOutline, int originX, int originY, int cellX, 1194482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int cellY, int spanX, int spanY, boolean resize, Point dragOffset, Rect dragRegion) { 119508ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy final int oldDragCellX = mDragCell[0]; 119608ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy final int oldDragCellY = mDragCell[1]; 1197482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1198b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung if (v != null && dragOffset == null) { 1199a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung mDragCenter.set(originX + (v.getWidth() / 2), originY + (v.getHeight() / 2)); 1200a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung } else { 1201a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung mDragCenter.set(originX, originY); 1202a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung } 12036569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 12042801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen if (dragOutline == null && v == null) { 12052801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen return; 12062801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen } 12072801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen 1208482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (cellX != oldDragCellX || cellY != oldDragCellY) { 1209482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mDragCell[0] = cellX; 1210482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mDragCell[1] = cellY; 12116569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy // Find the top left corner of the rect the object will occupy 1212de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy final int[] topLeft = mTmpPoint; 1213482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen cellToPoint(cellX, cellY, topLeft); 1214de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy 12154be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato int left = topLeft[0]; 12164be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato int top = topLeft[1]; 12176569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 1218b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung if (v != null && dragOffset == null) { 121999e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen // When drawing the drag outline, it did not account for margin offsets 122099e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen // added by the view's parent. 122199e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen MarginLayoutParams lp = (MarginLayoutParams) v.getLayoutParams(); 122299e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen left += lp.leftMargin; 122399e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen top += lp.topMargin; 122499e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen 122599e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen // Offsets due to the size difference between the View and the dragOutline. 122699e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen // There is a size difference to account for the outer blur, which may lie 122799e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen // outside the bounds of the view. 1228a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung top += (v.getHeight() - dragOutline.getHeight()) / 2; 1229ae915cecd36af4973061a1cb0b58c5be1be699a0Adam Cohen // We center about the x axis 1230ae915cecd36af4973061a1cb0b58c5be1be699a0Adam Cohen left += ((mCellWidth * spanX) + ((spanX - 1) * mWidthGap) 1231ae915cecd36af4973061a1cb0b58c5be1be699a0Adam Cohen - dragOutline.getWidth()) / 2; 12326639687cd67bab1aeef2a75e5c6bc458b20dc082Adam Cohen } else { 1233b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung if (dragOffset != null && dragRegion != null) { 1234b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung // Center the drag region *horizontally* in the cell and apply a drag 1235b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung // outline offset 1236b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung left += dragOffset.x + ((mCellWidth * spanX) + ((spanX - 1) * mWidthGap) 1237b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung - dragRegion.width()) / 2; 1238b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung top += dragOffset.y; 1239b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung } else { 1240b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung // Center the drag outline in the cell 1241b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung left += ((mCellWidth * spanX) + ((spanX - 1) * mWidthGap) 1242b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung - dragOutline.getWidth()) / 2; 1243b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung top += ((mCellHeight * spanY) + ((spanY - 1) * mHeightGap) 1244b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung - dragOutline.getHeight()) / 2; 1245b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung } 1246a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung } 12474be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato final int oldIndex = mDragOutlineCurrent; 124808ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy mDragOutlineAnims[oldIndex].animateOut(); 124908ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy mDragOutlineCurrent = (oldIndex + 1) % mDragOutlines.length; 1250d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen Rect r = mDragOutlines[mDragOutlineCurrent]; 1251d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen r.set(left, top, left + dragOutline.getWidth(), top + dragOutline.getHeight()); 1252d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (resize) { 1253482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen cellToRect(cellX, cellY, spanX, spanY, r); 1254d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1255150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung 125608ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy mDragOutlineAnims[mDragOutlineCurrent].setTag(dragOutline); 125708ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy mDragOutlineAnims[mDragOutlineCurrent].animateIn(); 12586569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy } 12596569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy } 12606569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 1261e0310965022e7a1adb7ad489505d404186608689Adam Cohen public void clearDragOutlines() { 1262e0310965022e7a1adb7ad489505d404186608689Adam Cohen final int oldIndex = mDragOutlineCurrent; 1263e0310965022e7a1adb7ad489505d404186608689Adam Cohen mDragOutlineAnims[oldIndex].animateOut(); 1264d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen mDragCell[0] = mDragCell[1] = -1; 1265e0310965022e7a1adb7ad489505d404186608689Adam Cohen } 1266e0310965022e7a1adb7ad489505d404186608689Adam Cohen 126731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 126870864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * Find a vacant area that will fit the given bounds nearest the requested 126970864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * cell location. Uses Euclidean distance to score multiple vacant areas. 1270aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * 127151afc022fa76c79f0d1ece470ddc126c08fea8a4Romain Guy * @param pixelX The X location at which you want to search for a vacant area. 127251afc022fa76c79f0d1ece470ddc126c08fea8a4Romain Guy * @param pixelY The Y location at which you want to search for a vacant area. 127370864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * @param spanX Horizontal span of the object. 127470864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * @param spanY Vertical span of the object. 1275de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy * @param result Array in which to place the result, or null (in which case a new array will 1276de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy * be allocated) 127770864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * @return The X, Y cell of a vacant area that can contain this object, 127870864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * nearest the requested location. 127931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 1280d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int[] findNearestVacantArea(int pixelX, int pixelY, int spanX, int spanY, 1281d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int[] result) { 1282de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy return findNearestVacantArea(pixelX, pixelY, spanX, spanY, null, result); 12836a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka } 1284aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 12856a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka /** 12866a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * Find a vacant area that will fit the given bounds nearest the requested 12876a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * cell location. Uses Euclidean distance to score multiple vacant areas. 12886a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * 12896a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * @param pixelX The X location at which you want to search for a vacant area. 12906a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * @param pixelY The Y location at which you want to search for a vacant area. 1291d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param minSpanX The minimum horizontal span required 1292d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param minSpanY The minimum vertical span required 1293d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param spanX Horizontal span of the object. 1294d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param spanY Vertical span of the object. 1295d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param result Array in which to place the result, or null (in which case a new array will 1296d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * be allocated) 1297d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @return The X, Y cell of a vacant area that can contain this object, 1298d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * nearest the requested location. 1299d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen */ 1300d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int[] findNearestVacantArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, 1301d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int spanY, int[] result, int[] resultSpan) { 1302d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen return findNearestVacantArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, null, 1303d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen result, resultSpan); 1304d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1305d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen 1306d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen /** 1307d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * Find a vacant area that will fit the given bounds nearest the requested 1308d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * cell location. Uses Euclidean distance to score multiple vacant areas. 1309d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * 1310d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param pixelX The X location at which you want to search for a vacant area. 1311d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param pixelY The Y location at which you want to search for a vacant area. 13126a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * @param spanX Horizontal span of the object. 13136a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * @param spanY Vertical span of the object. 1314df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param ignoreOccupied If true, the result can be an occupied cell 1315df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param result Array in which to place the result, or null (in which case a new array will 1316df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * be allocated) 13176a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * @return The X, Y cell of a vacant area that can contain this object, 13186a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * nearest the requested location. 13196a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka */ 1320df0353815c629fc678824b07a234b89a1ff94208Adam Cohen int[] findNearestArea(int pixelX, int pixelY, int spanX, int spanY, View ignoreView, 1321df0353815c629fc678824b07a234b89a1ff94208Adam Cohen boolean ignoreOccupied, int[] result) { 1322d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen return findNearestArea(pixelX, pixelY, spanX, spanY, 1323482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen spanX, spanY, ignoreView, ignoreOccupied, result, null, mOccupied); 1324d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1325d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen 1326d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen private final Stack<Rect> mTempRectStack = new Stack<Rect>(); 1327d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen private void lazyInitTempRectStack() { 1328d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (mTempRectStack.isEmpty()) { 1329d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen for (int i = 0; i < mCountX * mCountY; i++) { 1330d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen mTempRectStack.push(new Rect()); 1331d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1332d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1333d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1334482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1335d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen private void recycleTempRects(Stack<Rect> used) { 1336d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen while (!used.isEmpty()) { 1337d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen mTempRectStack.push(used.pop()); 1338d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1339d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1340d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen 1341d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen /** 1342d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * Find a vacant area that will fit the given bounds nearest the requested 1343d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * cell location. Uses Euclidean distance to score multiple vacant areas. 1344d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * 1345d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param pixelX The X location at which you want to search for a vacant area. 1346d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param pixelY The Y location at which you want to search for a vacant area. 1347d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param minSpanX The minimum horizontal span required 1348d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param minSpanY The minimum vertical span required 1349d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param spanX Horizontal span of the object. 1350d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param spanY Vertical span of the object. 1351d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param ignoreOccupied If true, the result can be an occupied cell 1352d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param result Array in which to place the result, or null (in which case a new array will 1353d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * be allocated) 1354d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @return The X, Y cell of a vacant area that can contain this object, 1355d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * nearest the requested location. 1356d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen */ 1357d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int[] findNearestArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, int spanY, 1358482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen View ignoreView, boolean ignoreOccupied, int[] result, int[] resultSpan, 1359482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean[][] occupied) { 1360d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen lazyInitTempRectStack(); 1361c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka // mark space take by ignoreView as available (method checks if ignoreView is null) 1362482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsAsUnoccupiedForView(ignoreView, occupied); 1363c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka 1364e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen // For items with a spanX / spanY > 1, the passed in point (pixelX, pixelY) corresponds 1365e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen // to the center of the item, but we are searching based on the top-left cell, so 1366e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen // we translate the point over to correspond to the top-left. 1367e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen pixelX -= (mCellWidth + mWidthGap) * (spanX - 1) / 2f; 1368e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen pixelY -= (mCellHeight + mHeightGap) * (spanY - 1) / 2f; 1369e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen 137070864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey // Keep track of best-scoring drop area 1371de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy final int[] bestXY = result != null ? result : new int[2]; 137270864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey double bestDistance = Double.MAX_VALUE; 1373d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen final Rect bestRect = new Rect(-1, -1, -1, -1); 1374d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen final Stack<Rect> validRegions = new Stack<Rect>(); 1375aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 1376de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy final int countX = mCountX; 1377de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy final int countY = mCountY; 1378de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy 1379d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (minSpanX <= 0 || minSpanY <= 0 || spanX <= 0 || spanY <= 0 || 1380d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen spanX < minSpanX || spanY < minSpanY) { 1381d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen return bestXY; 1382d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1383d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen 1384d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen for (int y = 0; y < countY - (minSpanY - 1); y++) { 1385c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka inner: 1386d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen for (int x = 0; x < countX - (minSpanX - 1); x++) { 1387d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int ySize = -1; 1388d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int xSize = -1; 1389df0353815c629fc678824b07a234b89a1ff94208Adam Cohen if (ignoreOccupied) { 1390d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // First, let's see if this thing fits anywhere 1391d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen for (int i = 0; i < minSpanX; i++) { 1392d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen for (int j = 0; j < minSpanY; j++) { 1393df0353815c629fc678824b07a234b89a1ff94208Adam Cohen if (occupied[x + i][y + j]) { 1394df0353815c629fc678824b07a234b89a1ff94208Adam Cohen continue inner; 1395df0353815c629fc678824b07a234b89a1ff94208Adam Cohen } 1396c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka } 1397c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka } 1398d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen xSize = minSpanX; 1399d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen ySize = minSpanY; 1400d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen 1401d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // We know that the item will fit at _some_ acceptable size, now let's see 1402d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // how big we can make it. We'll alternate between incrementing x and y spans 1403d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // until we hit a limit. 1404d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen boolean incX = true; 1405d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen boolean hitMaxX = xSize >= spanX; 1406d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen boolean hitMaxY = ySize >= spanY; 1407d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen while (!(hitMaxX && hitMaxY)) { 1408d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (incX && !hitMaxX) { 1409d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen for (int j = 0; j < ySize; j++) { 1410d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (x + xSize > countX -1 || occupied[x + xSize][y + j]) { 1411d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // We can't move out horizontally 1412d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen hitMaxX = true; 1413d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1414d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1415d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (!hitMaxX) { 1416d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen xSize++; 1417d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1418d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } else if (!hitMaxY) { 1419d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen for (int i = 0; i < xSize; i++) { 1420d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (y + ySize > countY - 1 || occupied[x + i][y + ySize]) { 1421d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // We can't move out vertically 1422d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen hitMaxY = true; 1423d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1424d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1425d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (!hitMaxY) { 1426d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen ySize++; 1427d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1428d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1429d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen hitMaxX |= xSize >= spanX; 1430d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen hitMaxY |= ySize >= spanY; 1431d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen incX = !incX; 1432d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1433d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen incX = true; 1434d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen hitMaxX = xSize >= spanX; 1435d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen hitMaxY = ySize >= spanY; 1436c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka } 14370be025d64c1f84138fe430a58875886e66aae767Winson Chung final int[] cellXY = mTmpXY; 1438e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen cellToCenterPoint(x, y, cellXY); 1439c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka 1440d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // We verify that the current rect is not a sub-rect of any of our previous 1441d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // candidates. In this case, the current rect is disqualified in favour of the 1442d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // containing rect. 1443d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen Rect currentRect = mTempRectStack.pop(); 1444d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen currentRect.set(x, y, x + xSize, y + ySize); 1445d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen boolean contained = false; 1446d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen for (Rect r : validRegions) { 1447d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (r.contains(currentRect)) { 1448d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen contained = true; 1449d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen break; 1450d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1451d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1452d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen validRegions.push(currentRect); 1453c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka double distance = Math.sqrt(Math.pow(cellXY[0] - pixelX, 2) 1454c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka + Math.pow(cellXY[1] - pixelY, 2)); 1455482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1456d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if ((distance <= bestDistance && !contained) || 1457d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen currentRect.contains(bestRect)) { 1458c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka bestDistance = distance; 1459c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka bestXY[0] = x; 1460c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka bestXY[1] = y; 1461d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (resultSpan != null) { 1462d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen resultSpan[0] = xSize; 1463d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen resultSpan[1] = ySize; 1464d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1465d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen bestRect.set(currentRect); 1466c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka } 146731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 146831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 1469c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka // re-mark space taken by ignoreView as occupied 1470482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsAsOccupiedForView(ignoreView, occupied); 147131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 1472c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen // Return -1, -1 if no suitable location found 1473c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen if (bestDistance == Double.MAX_VALUE) { 1474c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen bestXY[0] = -1; 1475c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen bestXY[1] = -1; 147670864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey } 1477d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen recycleTempRects(validRegions); 1478c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen return bestXY; 147931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 1480aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 1481482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen /** 1482482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * Find a vacant area that will fit the given bounds nearest the requested 1483482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * cell location, and will also weigh in a suggested direction vector of the 1484482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * desired location. This method computers distance based on unit grid distances, 1485482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * not pixel distances. 1486482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * 148747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param cellX The X cell nearest to which you want to search for a vacant area. 148847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param cellY The Y cell nearest which you want to search for a vacant area. 1489482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * @param spanX Horizontal span of the object. 1490482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * @param spanY Vertical span of the object. 149147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param direction The favored direction in which the views should move from x, y 149247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param exactDirectionOnly If this parameter is true, then only solutions where the direction 149347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * matches exactly. Otherwise we find the best matching direction. 149447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param occoupied The array which represents which cells in the CellLayout are occupied 149547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param blockOccupied The array which represents which cells in the specified block (cellX, 149647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * cellY, spanX, spanY) are occupied. This is used when try to move a group of views. 1497482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * @param result Array in which to place the result, or null (in which case a new array will 1498482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * be allocated) 1499482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * @return The X, Y cell of a vacant area that can contain this object, 1500482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * nearest the requested location. 1501482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen */ 1502482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private int[] findNearestArea(int cellX, int cellY, int spanX, int spanY, int[] direction, 150347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean[][] occupied, boolean blockOccupied[][], int[] result) { 1504482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // Keep track of best-scoring drop area 1505482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int[] bestXY = result != null ? result : new int[2]; 1506482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen float bestDistance = Float.MAX_VALUE; 1507482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int bestDirectionScore = Integer.MIN_VALUE; 1508482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1509482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int countX = mCountX; 1510482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int countY = mCountY; 1511482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1512482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int y = 0; y < countY - (spanY - 1); y++) { 1513482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen inner: 1514482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int x = 0; x < countX - (spanX - 1); x++) { 1515482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // First, let's see if this thing fits anywhere 1516482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < spanX; i++) { 1517482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int j = 0; j < spanY; j++) { 151847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (occupied[x + i][y + j] && (blockOccupied == null || blockOccupied[i][j])) { 1519482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen continue inner; 1520482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1521482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1522482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1523482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1524482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen float distance = (float) 1525482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen Math.sqrt((x - cellX) * (x - cellX) + (y - cellY) * (y - cellY)); 1526482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int[] curDirection = mTmpPoint; 152747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen computeDirectionVector(x - cellX, y - cellY, curDirection); 152847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen // The direction score is just the dot product of the two candidate direction 152947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen // and that passed in. 1530482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int curDirectionScore = direction[0] * curDirection[0] + 1531482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen direction[1] * curDirection[1]; 153247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean exactDirectionOnly = false; 153347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean directionMatches = direction[0] == curDirection[0] && 153447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen direction[0] == curDirection[0]; 153547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if ((directionMatches || !exactDirectionOnly) && 153647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen Float.compare(distance, bestDistance) < 0 || (Float.compare(distance, 1537482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen bestDistance) == 0 && curDirectionScore > bestDirectionScore)) { 1538482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen bestDistance = distance; 1539482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen bestDirectionScore = curDirectionScore; 1540482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen bestXY[0] = x; 1541482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen bestXY[1] = y; 1542482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1543482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1544482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1545482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1546482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // Return -1, -1 if no suitable location found 1547482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (bestDistance == Float.MAX_VALUE) { 1548482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen bestXY[0] = -1; 1549482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen bestXY[1] = -1; 1550482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1551482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return bestXY; 1552482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1553482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 155447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen private int[] findNearestAreaInDirection(int cellX, int cellY, int spanX, int spanY, 155547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen int[] direction,boolean[][] occupied, 155647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean blockOccupied[][], int[] result) { 155747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen // Keep track of best-scoring drop area 155847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen final int[] bestXY = result != null ? result : new int[2]; 155947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen bestXY[0] = -1; 156047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen bestXY[1] = -1; 156147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen float bestDistance = Float.MAX_VALUE; 156247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 156347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen // We use this to march in a single direction 15645b53f29f809a0dad4a1e0717ba610ce737ee0f43Adam Cohen if ((direction[0] != 0 && direction[1] != 0) || 15655b53f29f809a0dad4a1e0717ba610ce737ee0f43Adam Cohen (direction[0] == 0 && direction[1] == 0)) { 156647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen return bestXY; 156747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 156847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 156947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen // This will only incrememnet one of x or y based on the assertion above 157047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen int x = cellX + direction[0]; 157147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen int y = cellY + direction[1]; 157247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen while (x >= 0 && x + spanX <= mCountX && y >= 0 && y + spanY <= mCountY) { 157347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 157447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean fail = false; 157547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen for (int i = 0; i < spanX; i++) { 157647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen for (int j = 0; j < spanY; j++) { 157747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (occupied[x + i][y + j] && (blockOccupied == null || blockOccupied[i][j])) { 157847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen fail = true; 157947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 158047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 158147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 158247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (!fail) { 158347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen float distance = (float) 158447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen Math.sqrt((x - cellX) * (x - cellX) + (y - cellY) * (y - cellY)); 158547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (Float.compare(distance, bestDistance) < 0) { 158647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen bestDistance = distance; 158747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen bestXY[0] = x; 158847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen bestXY[1] = y; 158947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 159047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 159147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen x += direction[0]; 159247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen y += direction[1]; 159347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 159447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen return bestXY; 159547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 159647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 1597482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private boolean addViewToTempLocation(View v, Rect rectOccupiedByPotentialDrop, 15988baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen int[] direction, ItemConfiguration currentState) { 15998baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = currentState.map.get(v); 1600482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean success = false; 16018baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, false); 1602482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsForRect(rectOccupiedByPotentialDrop, mTmpOccupied, true); 1603482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 16048baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen findNearestArea(c.x, c.y, c.spanX, c.spanY, direction, mTmpOccupied, null, mTempLocation); 1605482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1606482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (mTempLocation[0] >= 0 && mTempLocation[1] >= 0) { 16078baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen c.x = mTempLocation[0]; 16088baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen c.y = mTempLocation[1]; 1609482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen success = true; 1610482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1611482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 16128baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, true); 1613482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return success; 1614482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1615482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 161647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen // This method looks in the specified direction to see if there is an additional view 161747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen // immediately adjecent in that direction 161847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen private boolean addViewInDirection(ArrayList<View> views, Rect boundingRect, int[] direction, 161919f3792523fe2d55ea791a9286398a6120920690Adam Cohen boolean[][] occupied, View dragView, ItemConfiguration currentState) { 162047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean found = false; 162147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 1622a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka int childCount = mShortcutsAndWidgets.getChildCount(); 162347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen Rect r0 = new Rect(boundingRect); 162447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen Rect r1 = new Rect(); 162547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 162647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen int deltaX = 0; 162747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen int deltaY = 0; 162847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (direction[1] < 0) { 162947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen r0.set(r0.left, r0.top - 1, r0.right, r0.bottom); 163047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen deltaY = -1; 163147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } else if (direction[1] > 0) { 163247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen r0.set(r0.left, r0.top, r0.right, r0.bottom + 1); 163347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen deltaY = 1; 163447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } else if (direction[0] < 0) { 163547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen r0.set(r0.left - 1, r0.top, r0.right, r0.bottom); 163647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen deltaX = -1; 163747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } else if (direction[0] > 0) { 163847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen r0.set(r0.left, r0.top, r0.right + 1, r0.bottom); 163947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen deltaX = 1; 164047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 164147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 164247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen for (int i = 0; i < childCount; i++) { 1643a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka View child = mShortcutsAndWidgets.getChildAt(i); 164419f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (views.contains(child) || child == dragView) continue; 16458baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = currentState.map.get(child); 164647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 16478baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen LayoutParams lp = (LayoutParams) child.getLayoutParams(); 16488baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen r1.set(c.x, c.y, c.x + c.spanX, c.y + c.spanY); 164947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (Rect.intersects(r0, r1)) { 165047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (!lp.canReorder) { 165147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen return false; 165247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 165347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean pushed = false; 16548baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen for (int x = c.x; x < c.x + c.spanX; x++) { 16558baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen for (int y = c.y; y < c.y + c.spanY; y++) { 165647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean inBounds = x - deltaX >= 0 && x -deltaX < mCountX 165747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen && y - deltaY >= 0 && y - deltaY < mCountY; 165847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (inBounds && occupied[x - deltaX][y - deltaY]) { 165947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen pushed = true; 166047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 166147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 166247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 166347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (pushed) { 166447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen views.add(child); 16658baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen boundingRect.union(c.x, c.y, c.x + c.spanX, c.y + c.spanY); 166647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen found = true; 166747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 166847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 166947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 167047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen return found; 167147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 167247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 16738baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen private boolean addViewsToTempLocation(ArrayList<View> views, Rect rectOccupiedByPotentialDrop, 167419f3792523fe2d55ea791a9286398a6120920690Adam Cohen int[] direction, boolean push, View dragView, ItemConfiguration currentState) { 167547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (views.size() == 0) return true; 167647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 167747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean success = false; 167847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen Rect boundingRect = null; 16798baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // We construct a rect which represents the entire group of views passed in 168047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen for (View v: views) { 16818baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = currentState.map.get(v); 168247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (boundingRect == null) { 16838baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen boundingRect = new Rect(c.x, c.y, c.x + c.spanX, c.y + c.spanY); 168447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } else { 16858baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen boundingRect.union(c.x, c.y, c.x + c.spanX, c.y + c.spanY); 168647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 168747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 168847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 16898baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen @SuppressWarnings("unchecked") 169047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen ArrayList<View> dup = (ArrayList<View>) views.clone(); 16918baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // We try and expand the group of views in the direction vector passed, based on 16928baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // whether they are physically adjacent, ie. based on "push mechanics". 169319f3792523fe2d55ea791a9286398a6120920690Adam Cohen while (push && addViewInDirection(dup, boundingRect, direction, mTmpOccupied, dragView, 16948baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen currentState)) { 169547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 16968baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen 16978baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // Mark the occupied state as false for the group of views we want to move. 169847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen for (View v: dup) { 16998baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = currentState.map.get(v); 17008baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, false); 170147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 170247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 170347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean[][] blockOccupied = new boolean[boundingRect.width()][boundingRect.height()]; 170447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen int top = boundingRect.top; 170547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen int left = boundingRect.left; 17068baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // We mark more precisely which parts of the bounding rect are truly occupied, allowing 17078baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // for tetris-style interlocking. 170847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen for (View v: dup) { 17098baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = currentState.map.get(v); 17108baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen markCellsForView(c.x - left, c.y - top, c.spanX, c.spanY, blockOccupied, true); 171147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 171247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 171347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen markCellsForRect(rectOccupiedByPotentialDrop, mTmpOccupied, true); 171447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 17158baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen if (push) { 17168baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen findNearestAreaInDirection(boundingRect.left, boundingRect.top, boundingRect.width(), 17178baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen boundingRect.height(), direction, mTmpOccupied, blockOccupied, mTempLocation); 17188baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen } else { 17198baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen findNearestArea(boundingRect.left, boundingRect.top, boundingRect.width(), 17208baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen boundingRect.height(), direction, mTmpOccupied, blockOccupied, mTempLocation); 17218baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen } 172247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 17238baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // If we successfuly found a location by pushing the block of views, we commit it 172447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (mTempLocation[0] >= 0 && mTempLocation[1] >= 0) { 17258baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen int deltaX = mTempLocation[0] - boundingRect.left; 17268baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen int deltaY = mTempLocation[1] - boundingRect.top; 172747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen for (View v: dup) { 17288baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = currentState.map.get(v); 17298baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen c.x += deltaX; 17308baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen c.y += deltaY; 173147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 173247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen success = true; 173347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 1734482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 17358baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // In either case, we set the occupied array as marked for the location of the views 17368baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen for (View v: dup) { 17378baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = currentState.map.get(v); 17388baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, true); 1739482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1740482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return success; 1741482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1742482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1743482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private void markCellsForRect(Rect r, boolean[][] occupied, boolean value) { 1744482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsForView(r.left, r.top, r.width(), r.height(), occupied, value); 1745482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1746482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1747482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private boolean rearrangementExists(int cellX, int cellY, int spanX, int spanY, int[] direction, 17488baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen View ignoreView, ItemConfiguration solution) { 1749e3e03bcd313ba8060f2832b6a16dea6fd6d532eaWinson Chung // Return early if get invalid cell positions 1750e3e03bcd313ba8060f2832b6a16dea6fd6d532eaWinson Chung if (cellX < 0 || cellY < 0) return false; 1751482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 17528baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen mIntersectingViews.clear(); 1753482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mOccupiedRect.set(cellX, cellY, cellX + spanX, cellY + spanY); 1754482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 17558baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // Mark the desired location of the view currently being dragged. 1756482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (ignoreView != null) { 17578baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = solution.map.get(ignoreView); 175819f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (c != null) { 175919f3792523fe2d55ea791a9286398a6120920690Adam Cohen c.x = cellX; 176019f3792523fe2d55ea791a9286398a6120920690Adam Cohen c.y = cellY; 176119f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 1762482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1763482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen Rect r0 = new Rect(cellX, cellY, cellX + spanX, cellY + spanY); 1764482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen Rect r1 = new Rect(); 17658baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen for (View child: solution.map.keySet()) { 1766482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (child == ignoreView) continue; 17678baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = solution.map.get(child); 1768482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen LayoutParams lp = (LayoutParams) child.getLayoutParams(); 17698baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen r1.set(c.x, c.y, c.x + c.spanX, c.y + c.spanY); 1770482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (Rect.intersects(r0, r1)) { 1771482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (!lp.canReorder) { 1772482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return false; 1773482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1774482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mIntersectingViews.add(child); 1775482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1776482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 177747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 17788baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // We try to move the intersecting views as a block using the push mechanic 177919f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (addViewsToTempLocation(mIntersectingViews, mOccupiedRect, direction, true, ignoreView, 178019f3792523fe2d55ea791a9286398a6120920690Adam Cohen solution)) { 178147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen return true; 178247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 178347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen // Try the opposite direction 178447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen direction[0] *= -1; 178547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen direction[1] *= -1; 178619f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (addViewsToTempLocation(mIntersectingViews, mOccupiedRect, direction, true, ignoreView, 178719f3792523fe2d55ea791a9286398a6120920690Adam Cohen solution)) { 178847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen return true; 178947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 179047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen // Switch the direction back 179147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen direction[0] *= -1; 179247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen direction[1] *= -1; 179347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 17948baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // Next we try moving the views as a block , but without requiring the push mechanic 179519f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (addViewsToTempLocation(mIntersectingViews, mOccupiedRect, direction, false, ignoreView, 179619f3792523fe2d55ea791a9286398a6120920690Adam Cohen solution)) { 1797482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return true; 1798482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 179947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 1800482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // Ok, they couldn't move as a block, let's move them individually 1801482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (View v : mIntersectingViews) { 18028baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen if (!addViewToTempLocation(v, mOccupiedRect, direction, solution)) { 1803482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return false; 1804482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1805482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1806482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return true; 1807482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1808482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1809482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen /* 1810482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * Returns a pair (x, y), where x,y are in {-1, 0, 1} corresponding to vector between 1811482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * the provided point and the provided cell 1812482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen */ 181347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen private void computeDirectionVector(float deltaX, float deltaY, int[] result) { 1814482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen double angle = Math.atan(((float) deltaY) / deltaX); 1815482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1816482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result[0] = 0; 1817482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result[1] = 0; 1818482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (Math.abs(Math.cos(angle)) > 0.5f) { 1819482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result[0] = (int) Math.signum(deltaX); 1820482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1821482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (Math.abs(Math.sin(angle)) > 0.5f) { 1822482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result[1] = (int) Math.signum(deltaY); 1823482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1824482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1825482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 18268baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen private void copyOccupiedArray(boolean[][] occupied) { 18278baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen for (int i = 0; i < mCountX; i++) { 18288baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen for (int j = 0; j < mCountY; j++) { 18298baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen occupied[i][j] = mOccupied[i][j]; 18308baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen } 18318baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen } 18328baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen } 18338baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen 1834482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen ItemConfiguration simpleSwap(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, 1835482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int spanY, int[] direction, View dragView, boolean decX, ItemConfiguration solution) { 18368baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // Copy the current state into the solution. This solution will be manipulated as necessary. 18378baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen copyCurrentStateToSolution(solution, false); 18388baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // Copy the current occupied array into the temporary occupied array. This array will be 18398baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // manipulated as necessary to find a solution. 18408baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen copyOccupiedArray(mTmpOccupied); 1841482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1842482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // We find the nearest cell into which we would place the dragged item, assuming there's 1843482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // nothing in its way. 1844482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int result[] = new int[2]; 1845482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result = findNearestArea(pixelX, pixelY, spanX, spanY, result); 1846482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1847482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean success = false; 1848482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // First we try the exact nearest position of the item being dragged, 1849482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // we will then want to try to move this around to other neighbouring positions 18508baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen success = rearrangementExists(result[0], result[1], spanX, spanY, direction, dragView, 18518baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen solution); 1852482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1853482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (!success) { 1854482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // We try shrinking the widget down to size in an alternating pattern, shrink 1 in 1855482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // x, then 1 in y etc. 1856482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (spanX > minSpanX && (minSpanY == spanY || decX)) { 1857482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return simpleSwap(pixelX, pixelY, minSpanX, minSpanY, spanX - 1, spanY, direction, 1858482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen dragView, false, solution); 1859482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } else if (spanY > minSpanY) { 1860482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return simpleSwap(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY - 1, direction, 1861482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen dragView, true, solution); 1862482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1863482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.isSolution = false; 1864482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } else { 1865482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.isSolution = true; 1866482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewX = result[0]; 1867482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewY = result[1]; 1868482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewSpanX = spanX; 1869482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewSpanY = spanY; 1870482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1871482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return solution; 1872482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1873482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1874482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private void copyCurrentStateToSolution(ItemConfiguration solution, boolean temp) { 1875a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka int childCount = mShortcutsAndWidgets.getChildCount(); 1876482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < childCount; i++) { 1877a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka View child = mShortcutsAndWidgets.getChildAt(i); 1878482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen LayoutParams lp = (LayoutParams) child.getLayoutParams(); 18798baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c; 1880482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (temp) { 18818baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen c = new CellAndSpan(lp.tmpCellX, lp.tmpCellY, lp.cellHSpan, lp.cellVSpan); 1882482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } else { 18838baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen c = new CellAndSpan(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan); 1884482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 18858baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen solution.map.put(child, c); 1886482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1887482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1888482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1889482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private void copySolutionToTempState(ItemConfiguration solution, View dragView) { 1890482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < mCountX; i++) { 1891482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int j = 0; j < mCountY; j++) { 1892482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mTmpOccupied[i][j] = false; 1893482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1894482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1895482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1896a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka int childCount = mShortcutsAndWidgets.getChildCount(); 1897482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < childCount; i++) { 1898a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka View child = mShortcutsAndWidgets.getChildAt(i); 1899482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (child == dragView) continue; 1900482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen LayoutParams lp = (LayoutParams) child.getLayoutParams(); 19018baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = solution.map.get(child); 19028baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen if (c != null) { 19038baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen lp.tmpCellX = c.x; 19048baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen lp.tmpCellY = c.y; 19058baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen lp.cellHSpan = c.spanX; 19068baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen lp.cellVSpan = c.spanY; 19078baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, true); 1908482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1909482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1910482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsForView(solution.dragViewX, solution.dragViewY, solution.dragViewSpanX, 1911482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewSpanY, mTmpOccupied, true); 1912482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1913482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1914482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private void animateItemsToSolution(ItemConfiguration solution, View dragView, boolean 1915482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen commitDragView) { 1916482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1917482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean[][] occupied = DESTRUCTIVE_REORDER ? mOccupied : mTmpOccupied; 1918482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < mCountX; i++) { 1919482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int j = 0; j < mCountY; j++) { 1920482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen occupied[i][j] = false; 1921482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1922482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1923482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1924a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka int childCount = mShortcutsAndWidgets.getChildCount(); 1925482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < childCount; i++) { 1926a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka View child = mShortcutsAndWidgets.getChildAt(i); 1927482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (child == dragView) continue; 19288baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = solution.map.get(child); 19298baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen if (c != null) { 193019f3792523fe2d55ea791a9286398a6120920690Adam Cohen animateChildToPosition(child, c.x, c.y, REORDER_ANIMATION_DURATION, 0, 193119f3792523fe2d55ea791a9286398a6120920690Adam Cohen DESTRUCTIVE_REORDER, false); 19328baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen markCellsForView(c.x, c.y, c.spanX, c.spanY, occupied, true); 1933482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1934482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1935482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (commitDragView) { 1936482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsForView(solution.dragViewX, solution.dragViewY, solution.dragViewSpanX, 1937482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewSpanY, occupied, true); 1938482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1939482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1940482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 194119f3792523fe2d55ea791a9286398a6120920690Adam Cohen // This method starts or changes the reorder hint animations 194219f3792523fe2d55ea791a9286398a6120920690Adam Cohen private void beginOrAdjustHintAnimations(ItemConfiguration solution, View dragView, int delay) { 194319f3792523fe2d55ea791a9286398a6120920690Adam Cohen int childCount = mShortcutsAndWidgets.getChildCount(); 194419f3792523fe2d55ea791a9286398a6120920690Adam Cohen int timeForPriorAnimationToComplete = getMaxCompletionTime(); 194519f3792523fe2d55ea791a9286398a6120920690Adam Cohen for (int i = 0; i < childCount; i++) { 194619f3792523fe2d55ea791a9286398a6120920690Adam Cohen View child = mShortcutsAndWidgets.getChildAt(i); 194719f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (child == dragView) continue; 194819f3792523fe2d55ea791a9286398a6120920690Adam Cohen CellAndSpan c = solution.map.get(child); 194919f3792523fe2d55ea791a9286398a6120920690Adam Cohen LayoutParams lp = (LayoutParams) child.getLayoutParams(); 195019f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (c != null) { 195119f3792523fe2d55ea791a9286398a6120920690Adam Cohen ReorderHintAnimation rha = new ReorderHintAnimation(child, lp.cellX, lp.cellY, 195219f3792523fe2d55ea791a9286398a6120920690Adam Cohen c.x, c.y, c.spanX, c.spanY); 195319f3792523fe2d55ea791a9286398a6120920690Adam Cohen rha.animate(timeForPriorAnimationToComplete); 195419f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 195519f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 195619f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 195719f3792523fe2d55ea791a9286398a6120920690Adam Cohen 195819f3792523fe2d55ea791a9286398a6120920690Adam Cohen // Class which represents the reorder hint animations. These animations show that an item is 195919f3792523fe2d55ea791a9286398a6120920690Adam Cohen // in a temporary state, and hint at where the item will return to. 196019f3792523fe2d55ea791a9286398a6120920690Adam Cohen class ReorderHintAnimation { 196119f3792523fe2d55ea791a9286398a6120920690Adam Cohen View child; 196219f3792523fe2d55ea791a9286398a6120920690Adam Cohen float deltaX; 196319f3792523fe2d55ea791a9286398a6120920690Adam Cohen float deltaY; 196419f3792523fe2d55ea791a9286398a6120920690Adam Cohen private static final int DURATION = 140; 196519f3792523fe2d55ea791a9286398a6120920690Adam Cohen private int repeatCount; 196619f3792523fe2d55ea791a9286398a6120920690Adam Cohen private boolean cancelOnCycleComplete = false; 196719f3792523fe2d55ea791a9286398a6120920690Adam Cohen ValueAnimator va; 196819f3792523fe2d55ea791a9286398a6120920690Adam Cohen 196919f3792523fe2d55ea791a9286398a6120920690Adam Cohen public ReorderHintAnimation(View child, int cellX0, int cellY0, int cellX1, int cellY1, 197019f3792523fe2d55ea791a9286398a6120920690Adam Cohen int spanX, int spanY) { 197119f3792523fe2d55ea791a9286398a6120920690Adam Cohen regionToCenterPoint(cellX0, cellY0, spanX, spanY, mTmpPoint); 197219f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int x0 = mTmpPoint[0]; 197319f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int y0 = mTmpPoint[1]; 197419f3792523fe2d55ea791a9286398a6120920690Adam Cohen regionToCenterPoint(cellX1, cellY1, spanX, spanY, mTmpPoint); 197519f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int x1 = mTmpPoint[0]; 197619f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int y1 = mTmpPoint[1]; 197719f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int dX = x1 - x0; 197819f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int dY = y1 - y0; 197919f3792523fe2d55ea791a9286398a6120920690Adam Cohen deltaX = 0; 198019f3792523fe2d55ea791a9286398a6120920690Adam Cohen deltaY = 0; 198119f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (dX == dY && dX == 0) { 198219f3792523fe2d55ea791a9286398a6120920690Adam Cohen } else { 198319f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (dY == 0) { 198419f3792523fe2d55ea791a9286398a6120920690Adam Cohen deltaX = mReorderHintAnimationMagnitude; 198519f3792523fe2d55ea791a9286398a6120920690Adam Cohen } else if (dX == 0) { 198619f3792523fe2d55ea791a9286398a6120920690Adam Cohen deltaY = mReorderHintAnimationMagnitude; 198719f3792523fe2d55ea791a9286398a6120920690Adam Cohen } else { 198819f3792523fe2d55ea791a9286398a6120920690Adam Cohen double angle = Math.atan( (float) (dY) / dX); 198919f3792523fe2d55ea791a9286398a6120920690Adam Cohen deltaX = (int) (Math.cos(angle) * mReorderHintAnimationMagnitude); 199019f3792523fe2d55ea791a9286398a6120920690Adam Cohen deltaY = (int) (Math.sin(angle) * mReorderHintAnimationMagnitude); 199119f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 199219f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 199319f3792523fe2d55ea791a9286398a6120920690Adam Cohen this.child = child; 199419f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 199519f3792523fe2d55ea791a9286398a6120920690Adam Cohen 199619f3792523fe2d55ea791a9286398a6120920690Adam Cohen void animate(int delay) { 199719f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (mShakeAnimators.containsKey(child)) { 199819f3792523fe2d55ea791a9286398a6120920690Adam Cohen ReorderHintAnimation oldAnimation = mShakeAnimators.get(child); 199919f3792523fe2d55ea791a9286398a6120920690Adam Cohen oldAnimation.completeAnimation(); 200019f3792523fe2d55ea791a9286398a6120920690Adam Cohen mShakeAnimators.remove(child); 200119f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 200219f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (deltaX == 0 && deltaY == 0) { 200319f3792523fe2d55ea791a9286398a6120920690Adam Cohen return; 200419f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 200519f3792523fe2d55ea791a9286398a6120920690Adam Cohen va = ValueAnimator.ofFloat(0f, 1f); 200619f3792523fe2d55ea791a9286398a6120920690Adam Cohen va.setRepeatMode(ValueAnimator.REVERSE); 200719f3792523fe2d55ea791a9286398a6120920690Adam Cohen va.setRepeatCount(ValueAnimator.INFINITE); 200819f3792523fe2d55ea791a9286398a6120920690Adam Cohen va.setDuration(DURATION); 200919f3792523fe2d55ea791a9286398a6120920690Adam Cohen va.addUpdateListener(new AnimatorUpdateListener() { 201019f3792523fe2d55ea791a9286398a6120920690Adam Cohen @Override 201119f3792523fe2d55ea791a9286398a6120920690Adam Cohen public void onAnimationUpdate(ValueAnimator animation) { 201219f3792523fe2d55ea791a9286398a6120920690Adam Cohen float r = ((Float) animation.getAnimatedValue()).floatValue(); 201319f3792523fe2d55ea791a9286398a6120920690Adam Cohen float x = r * deltaX; 201419f3792523fe2d55ea791a9286398a6120920690Adam Cohen float y = r * deltaY; 201519f3792523fe2d55ea791a9286398a6120920690Adam Cohen child.setTranslationX(x); 201619f3792523fe2d55ea791a9286398a6120920690Adam Cohen child.setTranslationY(y); 201719f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 201819f3792523fe2d55ea791a9286398a6120920690Adam Cohen }); 201919f3792523fe2d55ea791a9286398a6120920690Adam Cohen va.addListener(new AnimatorListenerAdapter() { 202019f3792523fe2d55ea791a9286398a6120920690Adam Cohen public void onAnimationRepeat(Animator animation) { 202119f3792523fe2d55ea791a9286398a6120920690Adam Cohen repeatCount++; 202219f3792523fe2d55ea791a9286398a6120920690Adam Cohen // We make sure to end only after a full period 202319f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (cancelOnCycleComplete && repeatCount % 2 == 0) { 202419f3792523fe2d55ea791a9286398a6120920690Adam Cohen va.cancel(); 202519f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 202619f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 202719f3792523fe2d55ea791a9286398a6120920690Adam Cohen }); 202819f3792523fe2d55ea791a9286398a6120920690Adam Cohen va.setStartDelay(Math.max(REORDER_ANIMATION_DURATION, delay)); 202919f3792523fe2d55ea791a9286398a6120920690Adam Cohen mShakeAnimators.put(child, this); 203019f3792523fe2d55ea791a9286398a6120920690Adam Cohen va.start(); 203119f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 203219f3792523fe2d55ea791a9286398a6120920690Adam Cohen 203319f3792523fe2d55ea791a9286398a6120920690Adam Cohen 203419f3792523fe2d55ea791a9286398a6120920690Adam Cohen private void completeAnimation() { 203519f3792523fe2d55ea791a9286398a6120920690Adam Cohen cancelOnCycleComplete = true; 203619f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 203719f3792523fe2d55ea791a9286398a6120920690Adam Cohen 203819f3792523fe2d55ea791a9286398a6120920690Adam Cohen // Returns the time required to complete the current oscillating animation 203919f3792523fe2d55ea791a9286398a6120920690Adam Cohen private int completionTime() { 204019f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (repeatCount % 2 == 0) { 204119f3792523fe2d55ea791a9286398a6120920690Adam Cohen return (int) (va.getDuration() - va.getCurrentPlayTime() + DURATION); 204219f3792523fe2d55ea791a9286398a6120920690Adam Cohen } else { 204319f3792523fe2d55ea791a9286398a6120920690Adam Cohen return (int) (va.getDuration() - va.getCurrentPlayTime()); 204419f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 204519f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 204619f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 204719f3792523fe2d55ea791a9286398a6120920690Adam Cohen 204819f3792523fe2d55ea791a9286398a6120920690Adam Cohen private void completeAndClearReorderHintAnimations() { 204919f3792523fe2d55ea791a9286398a6120920690Adam Cohen for (ReorderHintAnimation a: mShakeAnimators.values()) { 205019f3792523fe2d55ea791a9286398a6120920690Adam Cohen a.completeAnimation(); 205119f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 205219f3792523fe2d55ea791a9286398a6120920690Adam Cohen mShakeAnimators.clear(); 205319f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 205419f3792523fe2d55ea791a9286398a6120920690Adam Cohen 205519f3792523fe2d55ea791a9286398a6120920690Adam Cohen private int getMaxCompletionTime() { 205619f3792523fe2d55ea791a9286398a6120920690Adam Cohen int maxTime = 0; 205719f3792523fe2d55ea791a9286398a6120920690Adam Cohen for (ReorderHintAnimation a: mShakeAnimators.values()) { 205819f3792523fe2d55ea791a9286398a6120920690Adam Cohen maxTime = Math.max(maxTime, a.completionTime()); 205919f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 206019f3792523fe2d55ea791a9286398a6120920690Adam Cohen return maxTime; 206119f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 206219f3792523fe2d55ea791a9286398a6120920690Adam Cohen 2063482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private void commitTempPlacement() { 2064482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < mCountX; i++) { 2065482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int j = 0; j < mCountY; j++) { 2066482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mOccupied[i][j] = mTmpOccupied[i][j]; 2067482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2068482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2069a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka int childCount = mShortcutsAndWidgets.getChildCount(); 2070482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < childCount; i++) { 2071ea889a294be004f4b1c21e9b874f9e63abfb8bd6Adam Cohen View child = mShortcutsAndWidgets.getChildAt(i); 2072ea889a294be004f4b1c21e9b874f9e63abfb8bd6Adam Cohen LayoutParams lp = (LayoutParams) child.getLayoutParams(); 2073ea889a294be004f4b1c21e9b874f9e63abfb8bd6Adam Cohen ItemInfo info = (ItemInfo) child.getTag(); 20742acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen // We do a null check here because the item info can be null in the case of the 20752acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen // AllApps button in the hotseat. 20762acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen if (info != null) { 20772acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen info.cellX = lp.cellX = lp.tmpCellX; 20782acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen info.cellY = lp.cellY = lp.tmpCellY; 2079bebf042666cffe52039b875a549a582abd78a431Adam Cohen info.spanX = lp.cellHSpan; 2080bebf042666cffe52039b875a549a582abd78a431Adam Cohen info.spanY = lp.cellVSpan; 20812acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen } 2082482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 20832acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen mLauncher.getWorkspace().updateItemLocationsInDatabase(this); 2084482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2085482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2086482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public void setUseTempCoords(boolean useTempCoords) { 2087a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka int childCount = mShortcutsAndWidgets.getChildCount(); 2088482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < childCount; i++) { 2089a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka LayoutParams lp = (LayoutParams) mShortcutsAndWidgets.getChildAt(i).getLayoutParams(); 2090482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen lp.useTmpCoords = useTempCoords; 2091482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2092482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2093482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2094482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen ItemConfiguration findConfigurationNoShuffle(int pixelX, int pixelY, int minSpanX, int minSpanY, 2095482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int spanX, int spanY, View dragView, ItemConfiguration solution) { 2096482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int[] result = new int[2]; 2097482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int[] resultSpan = new int[2]; 2098482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen findNearestVacantArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, null, result, 2099482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen resultSpan); 2100482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (result[0] >= 0 && result[1] >= 0) { 2101482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen copyCurrentStateToSolution(solution, false); 2102482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewX = result[0]; 2103482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewY = result[1]; 2104482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewSpanX = resultSpan[0]; 2105482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewSpanY = resultSpan[1]; 2106482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.isSolution = true; 2107482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } else { 2108482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.isSolution = false; 2109482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2110482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return solution; 2111482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2112482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2113482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public void prepareChildForDrag(View child) { 2114482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsAsUnoccupiedForView(child); 2115482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2116482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 211719f3792523fe2d55ea791a9286398a6120920690Adam Cohen /* This seems like it should be obvious and straight-forward, but when the direction vector 211819f3792523fe2d55ea791a9286398a6120920690Adam Cohen needs to match with the notion of the dragView pushing other views, we have to employ 211919f3792523fe2d55ea791a9286398a6120920690Adam Cohen a slightly more subtle notion of the direction vector. The question is what two points is 212019f3792523fe2d55ea791a9286398a6120920690Adam Cohen the vector between? The center of the dragView and its desired destination? Not quite, as 212119f3792523fe2d55ea791a9286398a6120920690Adam Cohen this doesn't necessarily coincide with the interaction of the dragView and items occupying 212219f3792523fe2d55ea791a9286398a6120920690Adam Cohen those cells. Instead we use some heuristics to often lock the vector to up, down, left 212319f3792523fe2d55ea791a9286398a6120920690Adam Cohen or right, which helps make pushing feel right. 212419f3792523fe2d55ea791a9286398a6120920690Adam Cohen */ 212519f3792523fe2d55ea791a9286398a6120920690Adam Cohen private void getDirectionVectorForDrop(int dragViewCenterX, int dragViewCenterY, int spanX, 212619f3792523fe2d55ea791a9286398a6120920690Adam Cohen int spanY, View dragView, int[] resultDirection) { 212719f3792523fe2d55ea791a9286398a6120920690Adam Cohen int[] targetDestination = new int[2]; 212819f3792523fe2d55ea791a9286398a6120920690Adam Cohen 212919f3792523fe2d55ea791a9286398a6120920690Adam Cohen findNearestArea(dragViewCenterX, dragViewCenterY, spanX, spanY, targetDestination); 213019f3792523fe2d55ea791a9286398a6120920690Adam Cohen Rect dragRect = new Rect(); 213119f3792523fe2d55ea791a9286398a6120920690Adam Cohen regionToRect(targetDestination[0], targetDestination[1], spanX, spanY, dragRect); 213219f3792523fe2d55ea791a9286398a6120920690Adam Cohen dragRect.offset(dragViewCenterX - dragRect.centerX(), dragViewCenterY - dragRect.centerY()); 213319f3792523fe2d55ea791a9286398a6120920690Adam Cohen 213419f3792523fe2d55ea791a9286398a6120920690Adam Cohen Rect dropRegionRect = new Rect(); 213519f3792523fe2d55ea791a9286398a6120920690Adam Cohen getViewsIntersectingRegion(targetDestination[0], targetDestination[1], spanX, spanY, 213619f3792523fe2d55ea791a9286398a6120920690Adam Cohen dragView, dropRegionRect, mIntersectingViews); 213719f3792523fe2d55ea791a9286398a6120920690Adam Cohen 213819f3792523fe2d55ea791a9286398a6120920690Adam Cohen int dropRegionSpanX = dropRegionRect.width(); 213919f3792523fe2d55ea791a9286398a6120920690Adam Cohen int dropRegionSpanY = dropRegionRect.height(); 214019f3792523fe2d55ea791a9286398a6120920690Adam Cohen 214119f3792523fe2d55ea791a9286398a6120920690Adam Cohen regionToRect(dropRegionRect.left, dropRegionRect.top, dropRegionRect.width(), 214219f3792523fe2d55ea791a9286398a6120920690Adam Cohen dropRegionRect.height(), dropRegionRect); 214319f3792523fe2d55ea791a9286398a6120920690Adam Cohen 214419f3792523fe2d55ea791a9286398a6120920690Adam Cohen int deltaX = (dropRegionRect.centerX() - dragViewCenterX) / spanX; 214519f3792523fe2d55ea791a9286398a6120920690Adam Cohen int deltaY = (dropRegionRect.centerY() - dragViewCenterY) / spanY; 214619f3792523fe2d55ea791a9286398a6120920690Adam Cohen 214719f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (dropRegionSpanX == mCountX || spanX == mCountX) { 214819f3792523fe2d55ea791a9286398a6120920690Adam Cohen deltaX = 0; 214919f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 215019f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (dropRegionSpanY == mCountY || spanY == mCountY) { 215119f3792523fe2d55ea791a9286398a6120920690Adam Cohen deltaY = 0; 215219f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 215319f3792523fe2d55ea791a9286398a6120920690Adam Cohen 215419f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (deltaX == 0 && deltaY == 0) { 215519f3792523fe2d55ea791a9286398a6120920690Adam Cohen // No idea what to do, give a random direction. 215619f3792523fe2d55ea791a9286398a6120920690Adam Cohen resultDirection[0] = 1; 215719f3792523fe2d55ea791a9286398a6120920690Adam Cohen resultDirection[1] = 0; 215819f3792523fe2d55ea791a9286398a6120920690Adam Cohen } else { 215919f3792523fe2d55ea791a9286398a6120920690Adam Cohen computeDirectionVector(deltaX, deltaY, resultDirection); 216019f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 216119f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 216219f3792523fe2d55ea791a9286398a6120920690Adam Cohen 216319f3792523fe2d55ea791a9286398a6120920690Adam Cohen // For a given cell and span, fetch the set of views intersecting the region. 216419f3792523fe2d55ea791a9286398a6120920690Adam Cohen private void getViewsIntersectingRegion(int cellX, int cellY, int spanX, int spanY, 216519f3792523fe2d55ea791a9286398a6120920690Adam Cohen View dragView, Rect boundingRect, ArrayList<View> intersectingViews) { 216619f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (boundingRect != null) { 216719f3792523fe2d55ea791a9286398a6120920690Adam Cohen boundingRect.set(cellX, cellY, cellX + spanX, cellY + spanY); 216819f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 216919f3792523fe2d55ea791a9286398a6120920690Adam Cohen intersectingViews.clear(); 217019f3792523fe2d55ea791a9286398a6120920690Adam Cohen Rect r0 = new Rect(cellX, cellY, cellX + spanX, cellY + spanY); 217119f3792523fe2d55ea791a9286398a6120920690Adam Cohen Rect r1 = new Rect(); 217219f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int count = mShortcutsAndWidgets.getChildCount(); 217319f3792523fe2d55ea791a9286398a6120920690Adam Cohen for (int i = 0; i < count; i++) { 217419f3792523fe2d55ea791a9286398a6120920690Adam Cohen View child = mShortcutsAndWidgets.getChildAt(i); 217519f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (child == dragView) continue; 217619f3792523fe2d55ea791a9286398a6120920690Adam Cohen LayoutParams lp = (LayoutParams) child.getLayoutParams(); 217719f3792523fe2d55ea791a9286398a6120920690Adam Cohen r1.set(lp.cellX, lp.cellY, lp.cellX + lp.cellHSpan, lp.cellY + lp.cellVSpan); 217819f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (Rect.intersects(r0, r1)) { 217919f3792523fe2d55ea791a9286398a6120920690Adam Cohen mIntersectingViews.add(child); 218019f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (boundingRect != null) { 218119f3792523fe2d55ea791a9286398a6120920690Adam Cohen boundingRect.union(r1); 218219f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 218319f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 218419f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 218519f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 218619f3792523fe2d55ea791a9286398a6120920690Adam Cohen 218719f3792523fe2d55ea791a9286398a6120920690Adam Cohen boolean isNearestDropLocationOccupied(int pixelX, int pixelY, int spanX, int spanY, 218819f3792523fe2d55ea791a9286398a6120920690Adam Cohen View dragView, int[] result) { 218919f3792523fe2d55ea791a9286398a6120920690Adam Cohen result = findNearestArea(pixelX, pixelY, spanX, spanY, result); 219019f3792523fe2d55ea791a9286398a6120920690Adam Cohen getViewsIntersectingRegion(result[0], result[1], spanX, spanY, dragView, null, 219119f3792523fe2d55ea791a9286398a6120920690Adam Cohen mIntersectingViews); 219219f3792523fe2d55ea791a9286398a6120920690Adam Cohen return !mIntersectingViews.isEmpty(); 219319f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 219419f3792523fe2d55ea791a9286398a6120920690Adam Cohen 219519f3792523fe2d55ea791a9286398a6120920690Adam Cohen void revertTempState() { 219619f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (!isItemPlacementDirty() || DESTRUCTIVE_REORDER) return; 219719f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int count = mShortcutsAndWidgets.getChildCount(); 219819f3792523fe2d55ea791a9286398a6120920690Adam Cohen for (int i = 0; i < count; i++) { 219919f3792523fe2d55ea791a9286398a6120920690Adam Cohen View child = mShortcutsAndWidgets.getChildAt(i); 220019f3792523fe2d55ea791a9286398a6120920690Adam Cohen LayoutParams lp = (LayoutParams) child.getLayoutParams(); 220119f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (lp.tmpCellX != lp.cellX || lp.tmpCellY != lp.cellY) { 220219f3792523fe2d55ea791a9286398a6120920690Adam Cohen lp.tmpCellX = lp.cellX; 220319f3792523fe2d55ea791a9286398a6120920690Adam Cohen lp.tmpCellY = lp.cellY; 220419f3792523fe2d55ea791a9286398a6120920690Adam Cohen animateChildToPosition(child, lp.cellX, lp.cellY, REORDER_ANIMATION_DURATION, 220519f3792523fe2d55ea791a9286398a6120920690Adam Cohen 0, false, false); 220619f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 220719f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 220819f3792523fe2d55ea791a9286398a6120920690Adam Cohen completeAndClearReorderHintAnimations(); 220919f3792523fe2d55ea791a9286398a6120920690Adam Cohen setItemPlacementDirty(false); 221019f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 221119f3792523fe2d55ea791a9286398a6120920690Adam Cohen 2212bebf042666cffe52039b875a549a582abd78a431Adam Cohen boolean createAreaForResize(int cellX, int cellY, int spanX, int spanY, 2213bebf042666cffe52039b875a549a582abd78a431Adam Cohen View dragView, int[] direction, boolean commit) { 2214bebf042666cffe52039b875a549a582abd78a431Adam Cohen int[] pixelXY = new int[2]; 2215bebf042666cffe52039b875a549a582abd78a431Adam Cohen regionToCenterPoint(cellX, cellY, spanX, spanY, pixelXY); 2216bebf042666cffe52039b875a549a582abd78a431Adam Cohen 2217bebf042666cffe52039b875a549a582abd78a431Adam Cohen // First we determine if things have moved enough to cause a different layout 2218bebf042666cffe52039b875a549a582abd78a431Adam Cohen ItemConfiguration swapSolution = simpleSwap(pixelXY[0], pixelXY[1], spanX, spanY, 2219bebf042666cffe52039b875a549a582abd78a431Adam Cohen spanX, spanY, direction, dragView, true, new ItemConfiguration()); 2220bebf042666cffe52039b875a549a582abd78a431Adam Cohen 2221bebf042666cffe52039b875a549a582abd78a431Adam Cohen setUseTempCoords(true); 2222bebf042666cffe52039b875a549a582abd78a431Adam Cohen if (swapSolution != null && swapSolution.isSolution) { 2223bebf042666cffe52039b875a549a582abd78a431Adam Cohen // If we're just testing for a possible location (MODE_ACCEPT_DROP), we don't bother 2224bebf042666cffe52039b875a549a582abd78a431Adam Cohen // committing anything or animating anything as we just want to determine if a solution 2225bebf042666cffe52039b875a549a582abd78a431Adam Cohen // exists 2226bebf042666cffe52039b875a549a582abd78a431Adam Cohen copySolutionToTempState(swapSolution, dragView); 2227bebf042666cffe52039b875a549a582abd78a431Adam Cohen setItemPlacementDirty(true); 2228bebf042666cffe52039b875a549a582abd78a431Adam Cohen animateItemsToSolution(swapSolution, dragView, commit); 2229bebf042666cffe52039b875a549a582abd78a431Adam Cohen 2230bebf042666cffe52039b875a549a582abd78a431Adam Cohen if (commit) { 2231bebf042666cffe52039b875a549a582abd78a431Adam Cohen commitTempPlacement(); 2232bebf042666cffe52039b875a549a582abd78a431Adam Cohen completeAndClearReorderHintAnimations(); 2233bebf042666cffe52039b875a549a582abd78a431Adam Cohen setItemPlacementDirty(false); 2234bebf042666cffe52039b875a549a582abd78a431Adam Cohen } else { 2235bebf042666cffe52039b875a549a582abd78a431Adam Cohen beginOrAdjustHintAnimations(swapSolution, dragView, 2236bebf042666cffe52039b875a549a582abd78a431Adam Cohen REORDER_ANIMATION_DURATION); 2237bebf042666cffe52039b875a549a582abd78a431Adam Cohen } 2238bebf042666cffe52039b875a549a582abd78a431Adam Cohen mShortcutsAndWidgets.requestLayout(); 2239bebf042666cffe52039b875a549a582abd78a431Adam Cohen } 2240bebf042666cffe52039b875a549a582abd78a431Adam Cohen return swapSolution.isSolution; 2241bebf042666cffe52039b875a549a582abd78a431Adam Cohen } 2242bebf042666cffe52039b875a549a582abd78a431Adam Cohen 2243482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int[] createArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, int spanY, 2244482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen View dragView, int[] result, int resultSpan[], int mode) { 2245482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // First we determine if things have moved enough to cause a different layout 224647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen result = findNearestArea(pixelX, pixelY, spanX, spanY, result); 2247482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2248482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (resultSpan == null) { 2249482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen resultSpan = new int[2]; 2250482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2251482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 225219f3792523fe2d55ea791a9286398a6120920690Adam Cohen // When we are checking drop validity or actually dropping, we don't recompute the 225319f3792523fe2d55ea791a9286398a6120920690Adam Cohen // direction vector, since we want the solution to match the preview, and it's possible 225419f3792523fe2d55ea791a9286398a6120920690Adam Cohen // that the exact position of the item has changed to result in a new reordering outcome. 2255b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen if ((mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL || mode == MODE_ACCEPT_DROP) 2256b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen && mPreviousReorderDirection[0] != INVALID_DIRECTION) { 225719f3792523fe2d55ea791a9286398a6120920690Adam Cohen mDirectionVector[0] = mPreviousReorderDirection[0]; 225819f3792523fe2d55ea791a9286398a6120920690Adam Cohen mDirectionVector[1] = mPreviousReorderDirection[1]; 225919f3792523fe2d55ea791a9286398a6120920690Adam Cohen // We reset this vector after drop 2260b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen if (mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL) { 2261b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen mPreviousReorderDirection[0] = INVALID_DIRECTION; 2262b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen mPreviousReorderDirection[1] = INVALID_DIRECTION; 226319f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 226419f3792523fe2d55ea791a9286398a6120920690Adam Cohen } else { 226519f3792523fe2d55ea791a9286398a6120920690Adam Cohen getDirectionVectorForDrop(pixelX, pixelY, spanX, spanY, dragView, mDirectionVector); 226619f3792523fe2d55ea791a9286398a6120920690Adam Cohen mPreviousReorderDirection[0] = mDirectionVector[0]; 226719f3792523fe2d55ea791a9286398a6120920690Adam Cohen mPreviousReorderDirection[1] = mDirectionVector[1]; 226819f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 226919f3792523fe2d55ea791a9286398a6120920690Adam Cohen 2270482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen ItemConfiguration swapSolution = simpleSwap(pixelX, pixelY, minSpanX, minSpanY, 2271482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen spanX, spanY, mDirectionVector, dragView, true, new ItemConfiguration()); 2272482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2273482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // We attempt the approach which doesn't shuffle views at all 2274482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen ItemConfiguration noShuffleSolution = findConfigurationNoShuffle(pixelX, pixelY, minSpanX, 2275482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen minSpanY, spanX, spanY, dragView, new ItemConfiguration()); 2276482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2277482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen ItemConfiguration finalSolution = null; 2278482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (swapSolution.isSolution && swapSolution.area() >= noShuffleSolution.area()) { 2279482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen finalSolution = swapSolution; 2280482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } else if (noShuffleSolution.isSolution) { 2281482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen finalSolution = noShuffleSolution; 2282482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2283482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2284482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean foundSolution = true; 2285482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (!DESTRUCTIVE_REORDER) { 2286482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen setUseTempCoords(true); 2287482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2288482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2289482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (finalSolution != null) { 2290482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result[0] = finalSolution.dragViewX; 2291482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result[1] = finalSolution.dragViewY; 2292482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen resultSpan[0] = finalSolution.dragViewSpanX; 2293482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen resultSpan[1] = finalSolution.dragViewSpanY; 2294482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2295482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // If we're just testing for a possible location (MODE_ACCEPT_DROP), we don't bother 2296482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // committing anything or animating anything as we just want to determine if a solution 2297482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // exists 2298482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (mode == MODE_DRAG_OVER || mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL) { 2299482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (!DESTRUCTIVE_REORDER) { 2300482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen copySolutionToTempState(finalSolution, dragView); 2301482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2302482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen setItemPlacementDirty(true); 2303482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen animateItemsToSolution(finalSolution, dragView, mode == MODE_ON_DROP); 2304482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 230519f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (!DESTRUCTIVE_REORDER && 230619f3792523fe2d55ea791a9286398a6120920690Adam Cohen (mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL)) { 2307482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen commitTempPlacement(); 230819f3792523fe2d55ea791a9286398a6120920690Adam Cohen completeAndClearReorderHintAnimations(); 230919f3792523fe2d55ea791a9286398a6120920690Adam Cohen setItemPlacementDirty(false); 231019f3792523fe2d55ea791a9286398a6120920690Adam Cohen } else { 231119f3792523fe2d55ea791a9286398a6120920690Adam Cohen beginOrAdjustHintAnimations(finalSolution, dragView, 231219f3792523fe2d55ea791a9286398a6120920690Adam Cohen REORDER_ANIMATION_DURATION); 2313482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2314482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2315482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } else { 2316482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen foundSolution = false; 2317482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result[0] = result[1] = resultSpan[0] = resultSpan[1] = -1; 2318482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2319482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2320482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if ((mode == MODE_ON_DROP || !foundSolution) && !DESTRUCTIVE_REORDER) { 2321482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen setUseTempCoords(false); 2322482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2323482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2324a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.requestLayout(); 2325482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return result; 2326482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2327482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 232819f3792523fe2d55ea791a9286398a6120920690Adam Cohen void setItemPlacementDirty(boolean dirty) { 232919f3792523fe2d55ea791a9286398a6120920690Adam Cohen mItemPlacementDirty = dirty; 2330482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 233119f3792523fe2d55ea791a9286398a6120920690Adam Cohen boolean isItemPlacementDirty() { 233219f3792523fe2d55ea791a9286398a6120920690Adam Cohen return mItemPlacementDirty; 2333482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2334482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2335482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private class ItemConfiguration { 23368baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen HashMap<View, CellAndSpan> map = new HashMap<View, CellAndSpan>(); 2337482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean isSolution = false; 2338482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int dragViewX, dragViewY, dragViewSpanX, dragViewSpanY; 2339482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2340482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int area() { 2341482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return dragViewSpanX * dragViewSpanY; 2342482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 23438baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen } 23448baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen 23458baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen private class CellAndSpan { 23468baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen int x, y; 23478baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen int spanX, spanY; 23488baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen 23498baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen public CellAndSpan(int x, int y, int spanX, int spanY) { 23508baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen this.x = x; 23518baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen this.y = y; 23528baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen this.spanX = spanX; 23538baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen this.spanY = spanY; 2354482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2355482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2356482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2357df0353815c629fc678824b07a234b89a1ff94208Adam Cohen /** 2358df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * Find a vacant area that will fit the given bounds nearest the requested 2359df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * cell location. Uses Euclidean distance to score multiple vacant areas. 2360df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * 2361df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param pixelX The X location at which you want to search for a vacant area. 2362df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param pixelY The Y location at which you want to search for a vacant area. 2363df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param spanX Horizontal span of the object. 2364df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param spanY Vertical span of the object. 2365df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param ignoreView Considers space occupied by this view as unoccupied 2366df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param result Previously returned value to possibly recycle. 2367df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @return The X, Y cell of a vacant area that can contain this object, 2368df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * nearest the requested location. 2369df0353815c629fc678824b07a234b89a1ff94208Adam Cohen */ 2370df0353815c629fc678824b07a234b89a1ff94208Adam Cohen int[] findNearestVacantArea( 2371df0353815c629fc678824b07a234b89a1ff94208Adam Cohen int pixelX, int pixelY, int spanX, int spanY, View ignoreView, int[] result) { 2372df0353815c629fc678824b07a234b89a1ff94208Adam Cohen return findNearestArea(pixelX, pixelY, spanX, spanY, ignoreView, true, result); 2373df0353815c629fc678824b07a234b89a1ff94208Adam Cohen } 2374df0353815c629fc678824b07a234b89a1ff94208Adam Cohen 2375df0353815c629fc678824b07a234b89a1ff94208Adam Cohen /** 2376d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * Find a vacant area that will fit the given bounds nearest the requested 2377d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * cell location. Uses Euclidean distance to score multiple vacant areas. 2378d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * 2379d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param pixelX The X location at which you want to search for a vacant area. 2380d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param pixelY The Y location at which you want to search for a vacant area. 2381d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param minSpanX The minimum horizontal span required 2382d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param minSpanY The minimum vertical span required 2383d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param spanX Horizontal span of the object. 2384d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param spanY Vertical span of the object. 2385d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param ignoreView Considers space occupied by this view as unoccupied 2386d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param result Previously returned value to possibly recycle. 2387d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @return The X, Y cell of a vacant area that can contain this object, 2388d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * nearest the requested location. 2389d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen */ 2390d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int[] findNearestVacantArea(int pixelX, int pixelY, int minSpanX, int minSpanY, 2391d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int spanX, int spanY, View ignoreView, int[] result, int[] resultSpan) { 2392482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return findNearestArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, ignoreView, true, 2393482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result, resultSpan, mOccupied); 2394d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 2395d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen 2396d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen /** 2397df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * Find a starting cell position that will fit the given bounds nearest the requested 2398df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * cell location. Uses Euclidean distance to score multiple vacant areas. 2399df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * 2400df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param pixelX The X location at which you want to search for a vacant area. 2401df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param pixelY The Y location at which you want to search for a vacant area. 2402df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param spanX Horizontal span of the object. 2403df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param spanY Vertical span of the object. 2404df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param ignoreView Considers space occupied by this view as unoccupied 2405df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param result Previously returned value to possibly recycle. 2406df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @return The X, Y cell of a vacant area that can contain this object, 2407df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * nearest the requested location. 2408df0353815c629fc678824b07a234b89a1ff94208Adam Cohen */ 2409df0353815c629fc678824b07a234b89a1ff94208Adam Cohen int[] findNearestArea( 2410df0353815c629fc678824b07a234b89a1ff94208Adam Cohen int pixelX, int pixelY, int spanX, int spanY, int[] result) { 2411df0353815c629fc678824b07a234b89a1ff94208Adam Cohen return findNearestArea(pixelX, pixelY, spanX, spanY, null, false, result); 2412df0353815c629fc678824b07a234b89a1ff94208Adam Cohen } 2413df0353815c629fc678824b07a234b89a1ff94208Adam Cohen 24140280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka boolean existsEmptyCell() { 24150280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka return findCellForSpan(null, 1, 1); 24160280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 24170280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 24180280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka /** 24190280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * Finds the upper-left coordinate of the first rectangle in the grid that can 24200280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * hold a cell of the specified dimensions. If intersectX and intersectY are not -1, 24210280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * then this method will only return coordinates for rectangles that contain the cell 24220280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * (intersectX, intersectY) 24230280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * 24240280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param cellXY The array that will contain the position of a vacant cell if such a cell 24250280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * can be found. 24260280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param spanX The horizontal span of the cell we want to find. 24270280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param spanY The vertical span of the cell we want to find. 24280280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * 24290280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @return True if a vacant cell of the specified dimension was found, false otherwise. 24300280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka */ 24310280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka boolean findCellForSpan(int[] cellXY, int spanX, int spanY) { 2432482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return findCellForSpanThatIntersectsIgnoring(cellXY, spanX, spanY, -1, -1, null, mOccupied); 24330280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 24340280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 24350280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka /** 24360280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * Like above, but ignores any cells occupied by the item "ignoreView" 24370280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * 24380280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param cellXY The array that will contain the position of a vacant cell if such a cell 24390280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * can be found. 24400280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param spanX The horizontal span of the cell we want to find. 24410280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param spanY The vertical span of the cell we want to find. 24420280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param ignoreView The home screen item we should treat as not occupying any space 24430280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @return 24440280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka */ 24450280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka boolean findCellForSpanIgnoring(int[] cellXY, int spanX, int spanY, View ignoreView) { 2446482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return findCellForSpanThatIntersectsIgnoring(cellXY, spanX, spanY, -1, -1, 2447482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen ignoreView, mOccupied); 24480280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 24490280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 24500280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka /** 24510280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * Like above, but if intersectX and intersectY are not -1, then this method will try to 24520280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * return coordinates for rectangles that contain the cell [intersectX, intersectY] 24530280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * 24540280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param spanX The horizontal span of the cell we want to find. 24550280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param spanY The vertical span of the cell we want to find. 24560280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param ignoreView The home screen item we should treat as not occupying any space 24570280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param intersectX The X coordinate of the cell that we should try to overlap 24580280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param intersectX The Y coordinate of the cell that we should try to overlap 24590280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * 24600280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @return True if a vacant cell of the specified dimension was found, false otherwise. 24610280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka */ 24620280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka boolean findCellForSpanThatIntersects(int[] cellXY, int spanX, int spanY, 24630280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka int intersectX, int intersectY) { 24640280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka return findCellForSpanThatIntersectsIgnoring( 2465482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen cellXY, spanX, spanY, intersectX, intersectY, null, mOccupied); 24660280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 24670280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 24680280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka /** 24690280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * The superset of the above two methods 24700280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka */ 24710280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka boolean findCellForSpanThatIntersectsIgnoring(int[] cellXY, int spanX, int spanY, 2472482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int intersectX, int intersectY, View ignoreView, boolean occupied[][]) { 2473c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka // mark space take by ignoreView as available (method checks if ignoreView is null) 2474482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsAsUnoccupiedForView(ignoreView, occupied); 24750280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 247628750fba6a2d141eb9a1e566718c17236030b815Michael Jurka boolean foundCell = false; 24770280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka while (true) { 24780280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka int startX = 0; 24790280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka if (intersectX >= 0) { 24800280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka startX = Math.max(startX, intersectX - (spanX - 1)); 24810280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 24820280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka int endX = mCountX - (spanX - 1); 24830280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka if (intersectX >= 0) { 24840280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka endX = Math.min(endX, intersectX + (spanX - 1) + (spanX == 1 ? 1 : 0)); 24850280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 24860280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka int startY = 0; 24870280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka if (intersectY >= 0) { 24880280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka startY = Math.max(startY, intersectY - (spanY - 1)); 24890280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 24900280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka int endY = mCountY - (spanY - 1); 24910280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka if (intersectY >= 0) { 24920280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka endY = Math.min(endY, intersectY + (spanY - 1) + (spanY == 1 ? 1 : 0)); 24930280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 24940280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 2495bbc60d8e79416e37cbede55c159bf6aaa6c171d5Winson Chung for (int y = startY; y < endY && !foundCell; y++) { 24960280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka inner: 2497bbc60d8e79416e37cbede55c159bf6aaa6c171d5Winson Chung for (int x = startX; x < endX; x++) { 24980280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka for (int i = 0; i < spanX; i++) { 24990280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka for (int j = 0; j < spanY; j++) { 2500482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (occupied[x + i][y + j]) { 2501bbc60d8e79416e37cbede55c159bf6aaa6c171d5Winson Chung // small optimization: we can skip to after the column we just found 25020280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // an occupied cell 2503bbc60d8e79416e37cbede55c159bf6aaa6c171d5Winson Chung x += i; 25040280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka continue inner; 25050280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 25060280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 25070280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 25080280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka if (cellXY != null) { 25090280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka cellXY[0] = x; 25100280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka cellXY[1] = y; 25110280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 251228750fba6a2d141eb9a1e566718c17236030b815Michael Jurka foundCell = true; 251328750fba6a2d141eb9a1e566718c17236030b815Michael Jurka break; 25140280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 25150280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 25160280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka if (intersectX == -1 && intersectY == -1) { 25170280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka break; 25180280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } else { 25190280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // if we failed to find anything, try again but without any requirements of 25200280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // intersecting 25210280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka intersectX = -1; 25220280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka intersectY = -1; 25230280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka continue; 25240280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 25250280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 25260280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 2527c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka // re-mark space taken by ignoreView as occupied 2528482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsAsOccupiedForView(ignoreView, occupied); 252928750fba6a2d141eb9a1e566718c17236030b815Michael Jurka return foundCell; 25300280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 25310280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 253231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 2533c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung * A drag event has begun over this layout. 2534c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung * It may have begun over this layout (in which case onDragChild is called first), 2535c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung * or it may have begun on another layout. 2536c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung */ 2537c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung void onDragEnter() { 2538c6cc61d45836e4081920883cc4d448ccb0bb8417Adam Cohen mDragEnforcer.onDragEnter(); 2539c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung mDragging = true; 2540c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung } 2541c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung 2542c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung /** 25430280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * Called when drag has left this CellLayout or has been completed (successfully or not) 25446569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy */ 25450280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka void onDragExit() { 2546c6cc61d45836e4081920883cc4d448ccb0bb8417Adam Cohen mDragEnforcer.onDragExit(); 25474be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // This can actually be called when we aren't in a drag, e.g. when adding a new 25484be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // item to this layout via the customize drawer. 25494be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // Guard against that case. 25504be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato if (mDragging) { 25514be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato mDragging = false; 25524be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato } 255308ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy 255408ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy // Invalidate the drag data 2555d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen mDragCell[0] = mDragCell[1] = -1; 255608ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy mDragOutlineAnims[mDragOutlineCurrent].animateOut(); 255708ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy mDragOutlineCurrent = (mDragOutlineCurrent + 1) % mDragOutlineAnims.length; 255819f3792523fe2d55ea791a9286398a6120920690Adam Cohen revertTempState(); 255933945b21544bc98381df17726a3537c292d8c985Michael Jurka setIsDragOverlapping(false); 25606569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy } 25616569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 25626569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy /** 2563aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * Mark a child as having been dropped. 2564de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy * At the beginning of the drag operation, the child may have been on another 2565ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy * screen, but it is re-parented before this method is called. 256631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 256731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param child The child that is being dropped 256831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 2569716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen void onDropChild(View child) { 2570d94533d04a5f8f5485f106d10af60169857ea899Romain Guy if (child != null) { 2571d94533d04a5f8f5485f106d10af60169857ea899Romain Guy LayoutParams lp = (LayoutParams) child.getLayoutParams(); 257284f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy lp.dropped = true; 2573d94533d04a5f8f5485f106d10af60169857ea899Romain Guy child.requestLayout(); 2574d94533d04a5f8f5485f106d10af60169857ea899Romain Guy } 257531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 257631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 257731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 257831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Computes a bounding rectangle for a range of cells 2579aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * 258031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param cellX X coordinate of upper left corner expressed as a cell position 258131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param cellY Y coordinate of upper left corner expressed as a cell position 2582aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * @param cellHSpan Width in cells 258331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param cellVSpan Height in cells 25846569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy * @param resultRect Rect into which to put the results 258531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 2586d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen public void cellToRect(int cellX, int cellY, int cellHSpan, int cellVSpan, Rect resultRect) { 258731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int cellWidth = mCellWidth; 258831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int cellHeight = mCellHeight; 258931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int widthGap = mWidthGap; 259031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int heightGap = mHeightGap; 2591aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 25924b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung final int hStartPadding = getPaddingLeft(); 25934b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung final int vStartPadding = getPaddingTop(); 2594aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 259531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int width = cellHSpan * cellWidth + ((cellHSpan - 1) * widthGap); 259631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int height = cellVSpan * cellHeight + ((cellVSpan - 1) * heightGap); 259731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 259831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int x = hStartPadding + cellX * (cellWidth + widthGap); 259931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int y = vStartPadding + cellY * (cellHeight + heightGap); 2600aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 26016569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy resultRect.set(x, y, x + width, y + height); 260231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 2603aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 260431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 2605aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * Computes the required horizontal and vertical cell spans to always 260631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * fit the given rectangle. 2607aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * 260831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param width Width in pixels 260931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param height Height in pixels 26108f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy * @param result An array of length 2 in which to store the result (may be null). 261131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 26128f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy public int[] rectToCell(int width, int height, int[] result) { 26139987a5c45e7d01a780d73b269bdce8d8a5309219Michael Jurka return rectToCell(getResources(), width, height, result); 26149987a5c45e7d01a780d73b269bdce8d8a5309219Michael Jurka } 26159987a5c45e7d01a780d73b269bdce8d8a5309219Michael Jurka 26169987a5c45e7d01a780d73b269bdce8d8a5309219Michael Jurka public static int[] rectToCell(Resources resources, int width, int height, int[] result) { 261731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // Always assume we're working with the smallest span to make sure we 261831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // reserve enough space in both orientations. 261979e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato int actualWidth = resources.getDimensionPixelSize(R.dimen.workspace_cell_width); 262079e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato int actualHeight = resources.getDimensionPixelSize(R.dimen.workspace_cell_height); 262131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int smallerSize = Math.min(actualWidth, actualHeight); 262279e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato 262331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // Always round up to next largest cell 262454c725cc294cd43ed0650179bfae64a622547660Winson Chung int spanX = (int) Math.ceil(width / (float) smallerSize); 262554c725cc294cd43ed0650179bfae64a622547660Winson Chung int spanY = (int) Math.ceil(height / (float) smallerSize); 262679e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato 26278f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy if (result == null) { 26288f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy return new int[] { spanX, spanY }; 26298f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy } 26308f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy result[0] = spanX; 26318f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy result[1] = spanY; 26328f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy return result; 263331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 263431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 2635f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka public int[] cellSpansToSize(int hSpans, int vSpans) { 2636f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka int[] size = new int[2]; 2637f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka size[0] = hSpans * mCellWidth + (hSpans - 1) * mWidthGap; 2638f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka size[1] = vSpans * mCellHeight + (vSpans - 1) * mHeightGap; 2639f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka return size; 2640f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka } 2641f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka 264231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 2643047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy * Calculate the grid spans needed to fit given item 2644047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy */ 2645047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy public void calculateSpans(ItemInfo info) { 2646047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy final int minWidth; 2647047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy final int minHeight; 2648047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy 2649047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy if (info instanceof LauncherAppWidgetInfo) { 2650047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy minWidth = ((LauncherAppWidgetInfo) info).minWidth; 2651047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy minHeight = ((LauncherAppWidgetInfo) info).minHeight; 2652047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy } else if (info instanceof PendingAddWidgetInfo) { 2653047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy minWidth = ((PendingAddWidgetInfo) info).minWidth; 2654047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy minHeight = ((PendingAddWidgetInfo) info).minHeight; 2655047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy } else { 2656047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy // It's not a widget, so it must be 1x1 2657047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy info.spanX = info.spanY = 1; 2658047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy return; 2659047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy } 2660047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy int[] spans = rectToCell(minWidth, minHeight, null); 2661047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy info.spanX = spans[0]; 2662047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy info.spanY = spans[1]; 2663047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy } 2664047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy 2665047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy /** 266631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Find the first vacant cell, if there is one. 266731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 266831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param vacant Holds the x and y coordinate of the vacant cell 266931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param spanX Horizontal cell span. 267031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param spanY Vertical cell span. 2671aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * 267231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @return True if a vacant cell was found 267331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 267431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public boolean getVacantCell(int[] vacant, int spanX, int spanY) { 267531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 26760280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka return findVacantCell(vacant, spanX, spanY, mCountX, mCountY, mOccupied); 267731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 267831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 267931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project static boolean findVacantCell(int[] vacant, int spanX, int spanY, 268031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int xCount, int yCount, boolean[][] occupied) { 268131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 26822801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen for (int y = 0; y < yCount; y++) { 26832801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen for (int x = 0; x < xCount; x++) { 268431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project boolean available = !occupied[x][y]; 268531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectout: for (int i = x; i < x + spanX - 1 && x < xCount; i++) { 268631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int j = y; j < y + spanY - 1 && y < yCount; j++) { 268731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project available = available && !occupied[i][j]; 268831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (!available) break out; 268931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 269031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 269131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 269231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (available) { 269331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project vacant[0] = x; 269431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project vacant[1] = y; 269531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return true; 269631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 269731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 269831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 269931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 270031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return false; 270131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 270231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 27030280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka private void clearOccupiedCells() { 27040280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka for (int x = 0; x < mCountX; x++) { 27050280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka for (int y = 0; y < mCountY; y++) { 27060280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka mOccupied[x][y] = false; 270731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 270831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 27090280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 271031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 2711d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen public void onMove(View view, int newCellX, int newCellY, int newSpanX, int newSpanY) { 27120280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka markCellsAsUnoccupiedForView(view); 2713482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsForView(newCellX, newCellY, newSpanX, newSpanY, mOccupied, true); 27140280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 271531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 2716d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen public void markCellsAsOccupiedForView(View view) { 2717482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsAsOccupiedForView(view, mOccupied); 2718482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2719482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public void markCellsAsOccupiedForView(View view, boolean[][] occupied) { 2720a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka if (view == null || view.getParent() != mShortcutsAndWidgets) return; 27210280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka LayoutParams lp = (LayoutParams) view.getLayoutParams(); 2722482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, occupied, true); 27230280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 27240280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 2725d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen public void markCellsAsUnoccupiedForView(View view) { 2726482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsAsUnoccupiedForView(view, mOccupied); 2727482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2728482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public void markCellsAsUnoccupiedForView(View view, boolean occupied[][]) { 2729a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka if (view == null || view.getParent() != mShortcutsAndWidgets) return; 27300280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka LayoutParams lp = (LayoutParams) view.getLayoutParams(); 2731482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, occupied, false); 27320280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 27330280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 2734482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private void markCellsForView(int cellX, int cellY, int spanX, int spanY, boolean[][] occupied, 2735482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean value) { 2736482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (cellX < 0 || cellY < 0) return; 27370280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka for (int x = cellX; x < cellX + spanX && x < mCountX; x++) { 27380280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka for (int y = cellY; y < cellY + spanY && y < mCountY; y++) { 2739482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen occupied[x][y] = value; 274031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 274131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 274231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 274331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 27442801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen public int getDesiredWidth() { 27458b805b17158886035b38261eb611d8641701ae43Michael Jurka return getPaddingLeft() + getPaddingRight() + (mCountX * mCellWidth) + 27462801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen (Math.max((mCountX - 1), 0) * mWidthGap); 27472801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen } 27482801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen 27492801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen public int getDesiredHeight() { 27508b805b17158886035b38261eb611d8641701ae43Michael Jurka return getPaddingTop() + getPaddingBottom() + (mCountY * mCellHeight) + 27512801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen (Math.max((mCountY - 1), 0) * mHeightGap); 27522801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen } 27532801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen 275466d72178af91d455700875635473be942bc90e54Michael Jurka public boolean isOccupied(int x, int y) { 275566d72178af91d455700875635473be942bc90e54Michael Jurka if (x < mCountX && y < mCountY) { 275666d72178af91d455700875635473be942bc90e54Michael Jurka return mOccupied[x][y]; 275766d72178af91d455700875635473be942bc90e54Michael Jurka } else { 275866d72178af91d455700875635473be942bc90e54Michael Jurka throw new RuntimeException("Position exceeds the bound of this CellLayout"); 275966d72178af91d455700875635473be942bc90e54Michael Jurka } 276066d72178af91d455700875635473be942bc90e54Michael Jurka } 276166d72178af91d455700875635473be942bc90e54Michael Jurka 276231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 276331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) { 276431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return new CellLayout.LayoutParams(getContext(), attrs); 276531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 276631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 276731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 276831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { 276931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return p instanceof CellLayout.LayoutParams; 277031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 277131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 277231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 277331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { 277431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return new CellLayout.LayoutParams(p); 277531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 277631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 2777aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung public static class CellLayoutAnimationController extends LayoutAnimationController { 2778aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung public CellLayoutAnimationController(Animation animation, float delay) { 2779aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung super(animation, delay); 2780aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung } 2781aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 2782aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung @Override 2783aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung protected long getDelayForView(View view) { 2784aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung return (int) (Math.random() * 150); 2785aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung } 2786aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung } 2787aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 278831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public static class LayoutParams extends ViewGroup.MarginLayoutParams { 278931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 279031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Horizontal location of the item in the grid. 279131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 279231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @ViewDebug.ExportedProperty 279331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public int cellX; 279431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 279531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 279631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Vertical location of the item in the grid. 279731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 279831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @ViewDebug.ExportedProperty 279931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public int cellY; 280031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 280131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 2802482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * Temporary horizontal location of the item in the grid during reorder 2803482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen */ 2804482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public int tmpCellX; 2805482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2806482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen /** 2807482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * Temporary vertical location of the item in the grid during reorder 2808482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen */ 2809482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public int tmpCellY; 2810482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2811482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen /** 2812482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * Indicates that the temporary coordinates should be used to layout the items 2813482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen */ 2814482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public boolean useTmpCoords; 2815482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2816482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen /** 281731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Number of cells spanned horizontally by the item. 281831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 281931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @ViewDebug.ExportedProperty 282031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public int cellHSpan; 282131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 282231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 282331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Number of cells spanned vertically by the item. 282431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 282531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @ViewDebug.ExportedProperty 282631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public int cellVSpan; 2827aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 28281b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen /** 28291b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen * Indicates whether the item will set its x, y, width and height parameters freely, 28301b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen * or whether these will be computed based on cellX, cellY, cellHSpan and cellVSpan. 28311b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen */ 2832d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen public boolean isLockedToGrid = true; 2833d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen 2834482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen /** 2835482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * Indicates whether this item can be reordered. Always true except in the case of the 2836482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * the AllApps button. 2837482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen */ 2838482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public boolean canReorder = true; 2839482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 284031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // X coordinate of the view in the layout. 284131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @ViewDebug.ExportedProperty 284231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int x; 284331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // Y coordinate of the view in the layout. 284431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @ViewDebug.ExportedProperty 284531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int y; 284631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 284784f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy boolean dropped; 2848fcb9e7144e58614f5ae0e9b272fb7ce040848c67Romain Guy 284931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public LayoutParams(Context c, AttributeSet attrs) { 285031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project super(c, attrs); 285131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellHSpan = 1; 285231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellVSpan = 1; 285331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 285431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 285531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public LayoutParams(ViewGroup.LayoutParams source) { 285631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project super(source); 285731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellHSpan = 1; 285831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellVSpan = 1; 285931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 2860aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 2861aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung public LayoutParams(LayoutParams source) { 2862aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung super(source); 2863aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung this.cellX = source.cellX; 2864aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung this.cellY = source.cellY; 2865aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung this.cellHSpan = source.cellHSpan; 2866aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung this.cellVSpan = source.cellVSpan; 2867aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung } 2868aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 286931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public LayoutParams(int cellX, int cellY, int cellHSpan, int cellVSpan) { 28708f19cdd62f6e2be05e3890916eabd11317ae1bc2Romain Guy super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); 287131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this.cellX = cellX; 287231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this.cellY = cellY; 287331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this.cellHSpan = cellHSpan; 287431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this.cellVSpan = cellVSpan; 287531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 287631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 28777f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public void setup(int cellWidth, int cellHeight, int widthGap, int heightGap) { 2878d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen if (isLockedToGrid) { 2879d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen final int myCellHSpan = cellHSpan; 2880d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen final int myCellVSpan = cellVSpan; 2881482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int myCellX = useTmpCoords ? tmpCellX : cellX; 2882482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int myCellY = useTmpCoords ? tmpCellY : cellY; 28831b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen 2884d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen width = myCellHSpan * cellWidth + ((myCellHSpan - 1) * widthGap) - 2885d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen leftMargin - rightMargin; 2886d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen height = myCellVSpan * cellHeight + ((myCellVSpan - 1) * heightGap) - 2887d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen topMargin - bottomMargin; 2888eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung x = (int) (myCellX * (cellWidth + widthGap) + leftMargin); 2889eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung y = (int) (myCellY * (cellHeight + heightGap) + topMargin); 2890d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen } 2891d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen } 2892d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen 2893aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung public String toString() { 2894aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung return "(" + this.cellX + ", " + this.cellY + ")"; 2895aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung } 28967f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 28977f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public void setWidth(int width) { 28987f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen this.width = width; 28997f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 29007f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 29017f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public int getWidth() { 29027f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen return width; 29037f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 29047f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 29057f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public void setHeight(int height) { 29067f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen this.height = height; 29077f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 29087f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 29097f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public int getHeight() { 29107f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen return height; 29117f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 29127f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 29137f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public void setX(int x) { 29147f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen this.x = x; 29157f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 29167f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 29177f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public int getX() { 29187f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen return x; 29197f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 29207f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 29217f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public void setY(int y) { 29227f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen this.y = y; 29237f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 29247f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 29257f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public int getY() { 29267f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen return y; 29277f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 292831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 292931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 29300280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // This class stores info for two purposes: 29310280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // 1. When dragging items (mDragInfo in Workspace), we store the View, its cellX & cellY, 29320280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // its spanX, spanY, and the screen it is on 29330280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // 2. When long clicking on an empty cell in a CellLayout, we save information about the 29340280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // cellX and cellY coordinates and which page was clicked. We then set this as a tag on 29350280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // the CellLayout that was long clicked 2936e5fb0f27bca7afb996258a7163c76ca7390d7bffMichael Jurka static final class CellInfo { 293731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project View cell; 2938a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka int cellX = -1; 2939a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka int cellY = -1; 294031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int spanX; 294131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int spanY; 294231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int screen; 29433d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung long container; 294431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 294531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 294631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public String toString() { 2947aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung return "Cell[view=" + (cell == null ? "null" : cell.getClass()) 2948aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung + ", x=" + cellX + ", y=" + cellY + "]"; 294931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 295031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 2951d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka 2952d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka public boolean lastDownOnOccupiedCell() { 2953d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka return mLastDownOnOccupiedCell; 2954d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka } 295531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project} 2956