CellLayout.java revision b209e634a29a0cb5514fafb4e5882ea49ba1cfa7
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 604b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung private int mOriginalCellWidth; 614b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung private int mOriginalCellHeight; 6231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private int mCellWidth; 6331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private int mCellHeight; 64aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 65d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen private int mCountX; 66d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen private int mCountY; 6731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 68234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen private int mOriginalWidthGap; 69234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen private int mOriginalHeightGap; 7031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private int mWidthGap; 7131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private int mHeightGap; 724b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung private int mMaxGap; 73ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen private boolean mScrollingTransformsDirty = false; 7431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 7531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private final Rect mRect = new Rect(); 7631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private final CellInfo mCellInfo = new CellInfo(); 77aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 78de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy // These are temporary variables to prevent having to allocate a new object just to 79de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy // return an (x, y) value from helper functions. Do NOT use them to maintain other state. 800be025d64c1f84138fe430a58875886e66aae767Winson Chung private final int[] mTmpXY = new int[2]; 81de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy private final int[] mTmpPoint = new int[2]; 82de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy private final PointF mTmpPointF = new PointF(); 8369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen int[] mTempLocation = new int[2]; 846569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 8531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project boolean[][] mOccupied; 86482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean[][] mTmpOccupied; 87d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka private boolean mLastDownOnOccupiedCell = false; 8831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 89dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka private OnTouchListener mInterceptTouchListener; 90dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka 9169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen private ArrayList<FolderRingAnimator> mFolderOuterRings = new ArrayList<FolderRingAnimator>(); 92c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen private int[] mFolderLeaveBehindCell = {-1, -1}; 9369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 94b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen private int mForegroundAlpha = 0; 955f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka private float mBackgroundAlpha; 961b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen private float mBackgroundAlphaMultiplier = 1.0f; 97f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen 9833945b21544bc98381df17726a3537c292d8c985Michael Jurka private Drawable mNormalBackground; 9933945b21544bc98381df17726a3537c292d8c985Michael Jurka private Drawable mActiveGlowBackground; 100b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen private Drawable mOverScrollForegroundDrawable; 101b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen private Drawable mOverScrollLeft; 102b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen private Drawable mOverScrollRight; 10318014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka private Rect mBackgroundRect; 104b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen private Rect mForegroundRect; 105b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen private int mForegroundPadding; 10633945b21544bc98381df17726a3537c292d8c985Michael Jurka 10733945b21544bc98381df17726a3537c292d8c985Michael Jurka // If we're actively dragging something over this screen, mIsDragOverlapping is true 10833945b21544bc98381df17726a3537c292d8c985Michael Jurka private boolean mIsDragOverlapping = false; 109de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy private final Point mDragCenter = new Point(); 1106569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 111150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung // These arrays are used to implement the drag visualization on x-large screens. 1124be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // They are used as circular arrays, indexed by mDragOutlineCurrent. 113d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen private Rect[] mDragOutlines = new Rect[4]; 114472b281d5cb4f5660df981a6c912266b9f5703feChet Haase private float[] mDragOutlineAlphas = new float[mDragOutlines.length]; 1154be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato private InterruptibleInOutAnimator[] mDragOutlineAnims = 1164be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato new InterruptibleInOutAnimator[mDragOutlines.length]; 117150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung 118150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung // Used as an index into the above 3 arrays; indicates which is the most current value. 1194be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato private int mDragOutlineCurrent = 0; 1208e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy private final Paint mDragOutlinePaint = new Paint(); 121150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung 12296864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy private BubbleTextView mPressedOrFocusedIcon; 12396864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy 124de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy private Drawable mCrosshairsDrawable = null; 12549250ad530385fcdd6072ca54697f670ec503b59Patrick Dubroy private InterruptibleInOutAnimator mCrosshairsAnimator = null; 126de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy private float mCrosshairsVisibility = 0.0f; 127de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy 128482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private HashMap<CellLayout.LayoutParams, Animator> mReorderAnimators = new 129482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen HashMap<CellLayout.LayoutParams, Animator>(); 13019f3792523fe2d55ea791a9286398a6120920690Adam Cohen private HashMap<View, ReorderHintAnimation> 13119f3792523fe2d55ea791a9286398a6120920690Adam Cohen mShakeAnimators = new HashMap<View, ReorderHintAnimation>(); 13219f3792523fe2d55ea791a9286398a6120920690Adam Cohen 13319f3792523fe2d55ea791a9286398a6120920690Adam Cohen private boolean mItemPlacementDirty = false; 134bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen 1356569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy // When a drag operation is in progress, holds the nearest cell to the touch point 1366569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy private final int[] mDragCell = new int[2]; 13731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 1384be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato private boolean mDragging = false; 1394be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato 140ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy private TimeInterpolator mEaseOutInterpolator; 141a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka private ShortcutAndWidgetContainer mShortcutsAndWidgets; 142ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy 1430dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn private boolean mIsHotseat = false; 144eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung private float mChildScale = 1f; 145eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung private float mHotseatChildScale = 1f; 1460dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn 147482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public static final int MODE_DRAG_OVER = 0; 148482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public static final int MODE_ON_DROP = 1; 149482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public static final int MODE_ON_DROP_EXTERNAL = 2; 150482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public static final int MODE_ACCEPT_DROP = 3; 15119f3792523fe2d55ea791a9286398a6120920690Adam Cohen private static final boolean DESTRUCTIVE_REORDER = false; 152482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private static final boolean DEBUG_VISUALIZE_OCCUPIED = false; 153482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 15419f3792523fe2d55ea791a9286398a6120920690Adam Cohen private static final float REORDER_HINT_MAGNITUDE = 0.27f; 15519f3792523fe2d55ea791a9286398a6120920690Adam Cohen private static final int REORDER_ANIMATION_DURATION = 150; 15619f3792523fe2d55ea791a9286398a6120920690Adam Cohen private float mReorderHintAnimationMagnitude; 15719f3792523fe2d55ea791a9286398a6120920690Adam Cohen 158482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private ArrayList<View> mIntersectingViews = new ArrayList<View>(); 159482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private Rect mOccupiedRect = new Rect(); 160482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private int[] mDirectionVector = new int[2]; 16119f3792523fe2d55ea791a9286398a6120920690Adam Cohen int[] mPreviousReorderDirection = new int[2]; 162b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen private static final int INVALID_DIRECTION = -100; 163482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 16431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public CellLayout(Context context) { 16531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this(context, null); 16631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 16731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 16831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public CellLayout(Context context, AttributeSet attrs) { 16931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this(context, attrs, 0); 17031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 17131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 17231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public CellLayout(Context context, AttributeSet attrs, int defStyle) { 17331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project super(context, attrs, defStyle); 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); 178a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka 17931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CellLayout, defStyle, 0); 18031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 1814b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung mOriginalCellWidth = 1824b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung mCellWidth = a.getDimensionPixelSize(R.styleable.CellLayout_cellWidth, 10); 1834b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung mOriginalCellHeight = 1844b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung mCellHeight = a.getDimensionPixelSize(R.styleable.CellLayout_cellHeight, 10); 185234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen mWidthGap = mOriginalWidthGap = a.getDimensionPixelSize(R.styleable.CellLayout_widthGap, 0); 186234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen mHeightGap = mOriginalHeightGap = a.getDimensionPixelSize(R.styleable.CellLayout_heightGap, 0); 1874b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung mMaxGap = a.getDimensionPixelSize(R.styleable.CellLayout_maxGap, 0); 188d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen mCountX = LauncherModel.getCellCountX(); 189d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen mCountY = LauncherModel.getCellCountY(); 1900280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka mOccupied = new boolean[mCountX][mCountY]; 191482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mTmpOccupied = new boolean[mCountX][mCountY]; 19231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 19331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project a.recycle(); 19431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 19531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project setAlwaysDrawnWithCacheEnabled(false); 19631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 197046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy final Resources res = getResources(); 198de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy 199967289b6d5fec77f5c381d11ffb2319f3bb5e737Winson Chung mNormalBackground = res.getDrawable(R.drawable.homescreen_blue_normal_holo); 200dea74b7d12b0fcd50bfdb4274f9867ba76d75238Winson Chung mActiveGlowBackground = res.getDrawable(R.drawable.homescreen_blue_strong_holo); 201b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung 202b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mOverScrollLeft = res.getDrawable(R.drawable.overscroll_glow_left); 203b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mOverScrollRight = res.getDrawable(R.drawable.overscroll_glow_right); 204b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mForegroundPadding = 205b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen res.getDimensionPixelSize(R.dimen.workspace_overscroll_drawable_padding); 206b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung 20719f3792523fe2d55ea791a9286398a6120920690Adam Cohen mReorderHintAnimationMagnitude = (REORDER_HINT_MAGNITUDE * 20819f3792523fe2d55ea791a9286398a6120920690Adam Cohen res.getDimensionPixelSize(R.dimen.app_icon_size)); 20919f3792523fe2d55ea791a9286398a6120920690Adam Cohen 210b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung mNormalBackground.setFilterBitmap(true); 211b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung mActiveGlowBackground.setFilterBitmap(true); 212de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy 213eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung int iconScale = res.getInteger(R.integer.app_icon_scale_percent); 214eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung if (iconScale >= 0) { 215eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung mChildScale = iconScale / 100f; 216eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung } 217eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung int hotseatIconScale = res.getInteger(R.integer.app_icon_hotseat_scale_percent); 218eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung if (hotseatIconScale >= 0) { 219eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung mHotseatChildScale = hotseatIconScale / 100f; 220eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung } 2210dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn 222046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy // Initialize the data structures used for the drag visualization. 223150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung 224046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy mCrosshairsDrawable = res.getDrawable(R.drawable.gardening_crosshairs); 225ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy mEaseOutInterpolator = new DecelerateInterpolator(2.5f); // Quint ease out 226de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy 227046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy // Set up the animation for fading the crosshairs in and out 228046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy int animDuration = res.getInteger(R.integer.config_crosshairsFadeInTime); 22949250ad530385fcdd6072ca54697f670ec503b59Patrick Dubroy mCrosshairsAnimator = new InterruptibleInOutAnimator(animDuration, 0.0f, 1.0f); 230472b281d5cb4f5660df981a6c912266b9f5703feChet Haase mCrosshairsAnimator.getAnimator().addUpdateListener(new AnimatorUpdateListener() { 231046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy public void onAnimationUpdate(ValueAnimator animation) { 232046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy mCrosshairsVisibility = ((Float) animation.getAnimatedValue()).floatValue(); 2338e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy invalidate(); 234046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy } 235046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy }); 236ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy mCrosshairsAnimator.getAnimator().setInterpolator(mEaseOutInterpolator); 237046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy 238b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung mDragCell[0] = mDragCell[1] = -1; 2394be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato for (int i = 0; i < mDragOutlines.length; i++) { 240d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen mDragOutlines[i] = new Rect(-1, -1, -1, -1); 241046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy } 242046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy 243046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy // When dragging things around the home screens, we show a green outline of 244046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy // where the item will land. The outlines gradually fade out, leaving a trail 245046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy // behind the drag path. 246046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy // Set up all the animations that are used to implement this fading. 247046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy final int duration = res.getInteger(R.integer.config_dragOutlineFadeTime); 248472b281d5cb4f5660df981a6c912266b9f5703feChet Haase final float fromAlphaValue = 0; 249472b281d5cb4f5660df981a6c912266b9f5703feChet Haase final float toAlphaValue = (float)res.getInteger(R.integer.config_dragOutlineMaxAlpha); 2504be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato 2518e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy Arrays.fill(mDragOutlineAlphas, fromAlphaValue); 2524be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato 2534be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato for (int i = 0; i < mDragOutlineAnims.length; i++) { 254046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy final InterruptibleInOutAnimator anim = 255046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy new InterruptibleInOutAnimator(duration, fromAlphaValue, toAlphaValue); 256ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy anim.getAnimator().setInterpolator(mEaseOutInterpolator); 257046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy final int thisIndex = i; 258472b281d5cb4f5660df981a6c912266b9f5703feChet Haase anim.getAnimator().addUpdateListener(new AnimatorUpdateListener() { 259de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy public void onAnimationUpdate(ValueAnimator animation) { 2604be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato final Bitmap outline = (Bitmap)anim.getTag(); 2614be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato 2624be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // If an animation is started and then stopped very quickly, we can still 2634be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // get spurious updates we've cleared the tag. Guard against this. 2644be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato if (outline == null) { 265fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy if (false) { 266fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy Object val = animation.getAnimatedValue(); 267fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy Log.d(TAG, "anim " + thisIndex + " update: " + val + 268fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy ", isStopped " + anim.isStopped()); 269fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy } 2704be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // Try to prevent it from continuing to run 2714be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato animation.cancel(); 2724be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato } else { 273472b281d5cb4f5660df981a6c912266b9f5703feChet Haase mDragOutlineAlphas[thisIndex] = (Float) animation.getAnimatedValue(); 274d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen CellLayout.this.invalidate(mDragOutlines[thisIndex]); 2754be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato } 276de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy } 277de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy }); 2784be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // The animation holds a reference to the drag outline bitmap as long is it's 2794be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // running. This way the bitmap can be GCed when the animations are complete. 280472b281d5cb4f5660df981a6c912266b9f5703feChet Haase anim.getAnimator().addListener(new AnimatorListenerAdapter() { 2813c4c20fbe682cb4b3ef94f09afe0af09171583f3Michael Jurka @Override 2824be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato public void onAnimationEnd(Animator animation) { 283472b281d5cb4f5660df981a6c912266b9f5703feChet Haase if ((Float) ((ValueAnimator) animation).getAnimatedValue() == 0f) { 2844be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato anim.setTag(null); 2854be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato } 2864be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato } 2874be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato }); 2884be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato mDragOutlineAnims[i] = anim; 289de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy } 290ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy 29118014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka mBackgroundRect = new Rect(); 292b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mForegroundRect = new Rect(); 293bea15195346bab3c52b0156e92f2b71f0811b210Michael Jurka 294a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets = new ShortcutAndWidgetContainer(context); 295a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.setCellDimensions(mCellWidth, mCellHeight, mWidthGap, mHeightGap); 296a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka addView(mShortcutsAndWidgets); 29718014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka } 29818014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka 299f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka static int widthInPortrait(Resources r, int numCells) { 300f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka // We use this method from Workspace to figure out how many rows/columns Launcher should 301f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka // have. We ignore the left/right padding on CellLayout because it turns out in our design 302f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka // the padding extends outside the visible screen size, but it looked fine anyway. 303f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka int cellWidth = r.getDimensionPixelSize(R.dimen.workspace_cell_width); 3044b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung int minGap = Math.min(r.getDimensionPixelSize(R.dimen.workspace_width_gap), 3054b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung r.getDimensionPixelSize(R.dimen.workspace_height_gap)); 306f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka 3074b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung return minGap * (numCells - 1) + cellWidth * numCells; 308f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka } 309f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka 310f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka static int heightInLandscape(Resources r, int numCells) { 311f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka // We use this method from Workspace to figure out how many rows/columns Launcher should 312f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka // have. We ignore the left/right padding on CellLayout because it turns out in our design 313f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka // the padding extends outside the visible screen size, but it looked fine anyway. 314f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka int cellHeight = r.getDimensionPixelSize(R.dimen.workspace_cell_height); 3154b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung int minGap = Math.min(r.getDimensionPixelSize(R.dimen.workspace_width_gap), 3164b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung r.getDimensionPixelSize(R.dimen.workspace_height_gap)); 317f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka 3184b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung return minGap * (numCells - 1) + cellHeight * numCells; 319f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka } 320f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka 3212801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen public void enableHardwareLayers() { 322a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.enableHardwareLayers(); 3232801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen } 3242801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen 3252801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen public void setGridSize(int x, int y) { 3262801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen mCountX = x; 3272801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen mCountY = y; 3282801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen mOccupied = new boolean[mCountX][mCountY]; 329482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mTmpOccupied = new boolean[mCountX][mCountY]; 3307fbec10b36818f100b631f3d73fe1ad5360975aaAdam Cohen mTempRectStack.clear(); 33176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen requestLayout(); 3322801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen } 3332801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen 33496864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy private void invalidateBubbleTextView(BubbleTextView icon) { 33596864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy final int padding = icon.getPressedOrFocusedBackgroundPadding(); 3364b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung invalidate(icon.getLeft() + getPaddingLeft() - padding, 3374b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung icon.getTop() + getPaddingTop() - padding, 3384b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung icon.getRight() + getPaddingLeft() + padding, 3394b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung icon.getBottom() + getPaddingTop() + padding); 34096864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy } 34196864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy 342b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen void setOverScrollAmount(float r, boolean left) { 343b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen if (left && mOverScrollForegroundDrawable != mOverScrollLeft) { 344b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mOverScrollForegroundDrawable = mOverScrollLeft; 345b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen } else if (!left && mOverScrollForegroundDrawable != mOverScrollRight) { 346b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mOverScrollForegroundDrawable = mOverScrollRight; 347b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen } 348b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen 349b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mForegroundAlpha = (int) Math.round((r * 255)); 350b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mOverScrollForegroundDrawable.setAlpha(mForegroundAlpha); 351b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen invalidate(); 352b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen } 353b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen 35496864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy void setPressedOrFocusedIcon(BubbleTextView icon) { 35596864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy // We draw the pressed or focused BubbleTextView's background in CellLayout because it 35696864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy // requires an expanded clip rect (due to the glow's blur radius) 35796864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy BubbleTextView oldIcon = mPressedOrFocusedIcon; 35896864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy mPressedOrFocusedIcon = icon; 35996864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy if (oldIcon != null) { 36096864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy invalidateBubbleTextView(oldIcon); 36196864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy } 36296864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy if (mPressedOrFocusedIcon != null) { 36396864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy invalidateBubbleTextView(mPressedOrFocusedIcon); 36496864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy } 36596864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy } 36696864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy 36733945b21544bc98381df17726a3537c292d8c985Michael Jurka void setIsDragOverlapping(boolean isDragOverlapping) { 36833945b21544bc98381df17726a3537c292d8c985Michael Jurka if (mIsDragOverlapping != isDragOverlapping) { 36933945b21544bc98381df17726a3537c292d8c985Michael Jurka mIsDragOverlapping = isDragOverlapping; 37033945b21544bc98381df17726a3537c292d8c985Michael Jurka invalidate(); 37133945b21544bc98381df17726a3537c292d8c985Michael Jurka } 37233945b21544bc98381df17726a3537c292d8c985Michael Jurka } 37333945b21544bc98381df17726a3537c292d8c985Michael Jurka 37433945b21544bc98381df17726a3537c292d8c985Michael Jurka boolean getIsDragOverlapping() { 37533945b21544bc98381df17726a3537c292d8c985Michael Jurka return mIsDragOverlapping; 37633945b21544bc98381df17726a3537c292d8c985Michael Jurka } 37733945b21544bc98381df17726a3537c292d8c985Michael Jurka 378ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen protected void setOverscrollTransformsDirty(boolean dirty) { 379ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen mScrollingTransformsDirty = dirty; 380ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen } 381ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen 382ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen protected void resetOverscrollTransforms() { 383ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen if (mScrollingTransformsDirty) { 384ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen setOverscrollTransformsDirty(false); 385ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen setTranslationX(0); 386ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen setRotationY(0); 387ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen // It doesn't matter if we pass true or false here, the important thing is that we 388ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen // pass 0, which results in the overscroll drawable not being drawn any more. 389ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen setOverScrollAmount(0, false); 390ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen setPivotX(getMeasuredWidth() / 2); 391ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen setPivotY(getMeasuredHeight() / 2); 392ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen } 393ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen } 394ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen 395a6abce8464b57ce91e8f083951ad263370fc2da8Romain Guy @Override 3961262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy protected void onDraw(Canvas canvas) { 3973e7c7634531302271270c8cf418abc959d621cbcMichael Jurka // When we're large, we are either drawn in a "hover" state (ie when dragging an item to 3983e7c7634531302271270c8cf418abc959d621cbcMichael Jurka // a neighboring page) or with just a normal background (if backgroundAlpha > 0.0f) 3993e7c7634531302271270c8cf418abc959d621cbcMichael Jurka // When we're small, we are either drawn normally or in the "accepts drops" state (during 4003e7c7634531302271270c8cf418abc959d621cbcMichael Jurka // a drag). However, we also drag the mini hover background *over* one of those two 4013e7c7634531302271270c8cf418abc959d621cbcMichael Jurka // backgrounds 402b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung if (mBackgroundAlpha > 0.0f) { 403f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen Drawable bg; 40433945b21544bc98381df17726a3537c292d8c985Michael Jurka 40533945b21544bc98381df17726a3537c292d8c985Michael Jurka if (mIsDragOverlapping) { 40633945b21544bc98381df17726a3537c292d8c985Michael Jurka // In the mini case, we draw the active_glow bg *over* the active background 407bdf78559f223ac11e01e3311edd5a48a80383e1eMichael Jurka bg = mActiveGlowBackground; 408f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen } else { 409bdf78559f223ac11e01e3311edd5a48a80383e1eMichael Jurka bg = mNormalBackground; 410f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen } 41133945b21544bc98381df17726a3537c292d8c985Michael Jurka 41233945b21544bc98381df17726a3537c292d8c985Michael Jurka bg.setAlpha((int) (mBackgroundAlpha * mBackgroundAlphaMultiplier * 255)); 41333945b21544bc98381df17726a3537c292d8c985Michael Jurka bg.setBounds(mBackgroundRect); 41433945b21544bc98381df17726a3537c292d8c985Michael Jurka bg.draw(canvas); 415a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka } 41631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 417de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy if (mCrosshairsVisibility > 0.0f) { 418de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy final int countX = mCountX; 419de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy final int countY = mCountY; 420de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy 421de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy final float MAX_ALPHA = 0.4f; 422de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy final int MAX_VISIBLE_DISTANCE = 600; 423de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy final float DISTANCE_MULTIPLIER = 0.002f; 424de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy 425de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy final Drawable d = mCrosshairsDrawable; 426de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy final int width = d.getIntrinsicWidth(); 427de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy final int height = d.getIntrinsicHeight(); 428de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy 4294b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung int x = getPaddingLeft() - (mWidthGap / 2) - (width / 2); 430de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy for (int col = 0; col <= countX; col++) { 4314b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung int y = getPaddingTop() - (mHeightGap / 2) - (height / 2); 432de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy for (int row = 0; row <= countY; row++) { 433de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy mTmpPointF.set(x - mDragCenter.x, y - mDragCenter.y); 434de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy float dist = mTmpPointF.length(); 435de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy // Crosshairs further from the drag point are more faint 436de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy float alpha = Math.min(MAX_ALPHA, 437de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy DISTANCE_MULTIPLIER * (MAX_VISIBLE_DISTANCE - dist)); 438de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy if (alpha > 0.0f) { 439de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy d.setBounds(x, y, x + width, y + height); 440de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy d.setAlpha((int) (alpha * 255 * mCrosshairsVisibility)); 441de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy d.draw(canvas); 442de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy } 443de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy y += mCellHeight + mHeightGap; 444de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy } 445de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy x += mCellWidth + mWidthGap; 446de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy } 4474be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato } 448150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung 4498e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy final Paint paint = mDragOutlinePaint; 4504be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato for (int i = 0; i < mDragOutlines.length; i++) { 451472b281d5cb4f5660df981a6c912266b9f5703feChet Haase final float alpha = mDragOutlineAlphas[i]; 4524be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato if (alpha > 0) { 453d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen final Rect r = mDragOutlines[i]; 4544be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato final Bitmap b = (Bitmap) mDragOutlineAnims[i].getTag(); 455472b281d5cb4f5660df981a6c912266b9f5703feChet Haase paint.setAlpha((int)(alpha + .5f)); 456d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen canvas.drawBitmap(b, null, r, paint); 457150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung } 4586569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy } 45996864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy 46096864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy // We draw the pressed or focused BubbleTextView's background in CellLayout because it 46196864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy // requires an expanded clip rect (due to the glow's blur radius) 46296864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy if (mPressedOrFocusedIcon != null) { 46396864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy final int padding = mPressedOrFocusedIcon.getPressedOrFocusedBackgroundPadding(); 46496864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy final Bitmap b = mPressedOrFocusedIcon.getPressedOrFocusedBackground(); 46596864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy if (b != null) { 46696864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy canvas.drawBitmap(b, 4674b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung mPressedOrFocusedIcon.getLeft() + getPaddingLeft() - padding, 4684b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung mPressedOrFocusedIcon.getTop() + getPaddingTop() - padding, 46996864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy null); 47096864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy } 47196864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy } 47269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 473482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (DEBUG_VISUALIZE_OCCUPIED) { 474482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int[] pt = new int[2]; 475482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen ColorDrawable cd = new ColorDrawable(Color.RED); 476482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen cd.setBounds(0, 0, 80, 80); 477482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < mCountX; i++) { 478482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int j = 0; j < mCountY; j++) { 479482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (mOccupied[i][j]) { 480482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen cellToPoint(i, j, pt); 481482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen canvas.save(); 482482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen canvas.translate(pt[0], pt[1]); 483482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen cd.draw(canvas); 484482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen canvas.restore(); 485482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 486482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 487482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 488482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 489482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 49069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen // The folder outer / inner ring image(s) 49169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen for (int i = 0; i < mFolderOuterRings.size(); i++) { 49269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen FolderRingAnimator fra = mFolderOuterRings.get(i); 49369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 49469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen // Draw outer ring 49569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen Drawable d = FolderRingAnimator.sSharedOuterRingDrawable; 49669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen int width = (int) fra.getOuterRingSize(); 49769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen int height = width; 49869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen cellToPoint(fra.mCellX, fra.mCellY, mTempLocation); 49969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 50069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen int centerX = mTempLocation[0] + mCellWidth / 2; 50169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen int centerY = mTempLocation[1] + FolderRingAnimator.sPreviewSize / 2; 50269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 50369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen canvas.save(); 50469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen canvas.translate(centerX - width / 2, centerY - height / 2); 50569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen d.setBounds(0, 0, width, height); 50669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen d.draw(canvas); 50769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen canvas.restore(); 50869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 50969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen // Draw inner ring 51069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen d = FolderRingAnimator.sSharedInnerRingDrawable; 51169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen width = (int) fra.getInnerRingSize(); 51269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen height = width; 51369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen cellToPoint(fra.mCellX, fra.mCellY, mTempLocation); 51469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 51569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen centerX = mTempLocation[0] + mCellWidth / 2; 51669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen centerY = mTempLocation[1] + FolderRingAnimator.sPreviewSize / 2; 51769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen canvas.save(); 51869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen canvas.translate(centerX - width / 2, centerY - width / 2); 51969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen d.setBounds(0, 0, width, height); 52069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen d.draw(canvas); 52169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen canvas.restore(); 52269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen } 523c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen 524c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen if (mFolderLeaveBehindCell[0] >= 0 && mFolderLeaveBehindCell[1] >= 0) { 525c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen Drawable d = FolderIcon.sSharedFolderLeaveBehind; 526c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen int width = d.getIntrinsicWidth(); 527c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen int height = d.getIntrinsicHeight(); 528c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen 529c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen cellToPoint(mFolderLeaveBehindCell[0], mFolderLeaveBehindCell[1], mTempLocation); 530c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen int centerX = mTempLocation[0] + mCellWidth / 2; 531c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen int centerY = mTempLocation[1] + FolderRingAnimator.sPreviewSize / 2; 532c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen 533c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen canvas.save(); 534c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen canvas.translate(centerX - width / 2, centerY - width / 2); 535c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen d.setBounds(0, 0, width, height); 536c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen d.draw(canvas); 537c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen canvas.restore(); 538c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen } 53969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen } 54069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 541b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen @Override 542b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen protected void dispatchDraw(Canvas canvas) { 543b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen super.dispatchDraw(canvas); 544b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen if (mForegroundAlpha > 0) { 545b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mOverScrollForegroundDrawable.setBounds(mForegroundRect); 546b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen Paint p = ((NinePatchDrawable) mOverScrollForegroundDrawable).getPaint(); 547b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen p.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.ADD)); 548b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mOverScrollForegroundDrawable.draw(canvas); 549b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen p.setXfermode(null); 550b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen } 551b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen } 552b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen 55369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen public void showFolderAccept(FolderRingAnimator fra) { 55469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen mFolderOuterRings.add(fra); 55569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen } 55669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 55769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen public void hideFolderAccept(FolderRingAnimator fra) { 55869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen if (mFolderOuterRings.contains(fra)) { 55969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen mFolderOuterRings.remove(fra); 56069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen } 56169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen invalidate(); 5626569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy } 5636569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 564c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen public void setFolderLeaveBehindCell(int x, int y) { 565c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen mFolderLeaveBehindCell[0] = x; 566c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen mFolderLeaveBehindCell[1] = y; 567c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen invalidate(); 568c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen } 569c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen 570c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen public void clearFolderLeaveBehind() { 571c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen mFolderLeaveBehindCell[0] = -1; 572c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen mFolderLeaveBehindCell[1] = -1; 573c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen invalidate(); 574c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen } 575c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen 5766569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy @Override 577e6235dd225404239b55c459245543f3302326112Michael Jurka public boolean shouldDelayChildPressedState() { 578e6235dd225404239b55c459245543f3302326112Michael Jurka return false; 579e6235dd225404239b55c459245543f3302326112Michael Jurka } 580e6235dd225404239b55c459245543f3302326112Michael Jurka 581e6235dd225404239b55c459245543f3302326112Michael Jurka @Override 58283f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey public void cancelLongPress() { 58383f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey super.cancelLongPress(); 58483f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey 58583f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey // Cancel long press for all children 58683f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey final int count = getChildCount(); 58783f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey for (int i = 0; i < count; i++) { 58883f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey final View child = getChildAt(i); 58983f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey child.cancelLongPress(); 59083f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey } 59183f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey } 59283f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey 593dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka public void setOnInterceptTouchListener(View.OnTouchListener listener) { 594dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka mInterceptTouchListener = listener; 595dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } 596dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka 59731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int getCountX() { 598d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen return mCountX; 59931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 60031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 60131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int getCountY() { 602d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen return mCountY; 60331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 60431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 6050dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn public void setIsHotseat(boolean isHotseat) { 6060dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn mIsHotseat = isHotseat; 6070dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn } 6080dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn 609eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung public float getChildrenScale() { 610eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung return mIsHotseat ? mHotseatChildScale : mChildScale; 611eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung } 612eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung 613f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka public boolean addViewToCellLayout( 614f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka View child, int index, int childId, LayoutParams params, boolean markCells) { 6150dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn return addViewToCellLayout(child, index, childId, params, markCells, false); 6160dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn } 6170dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn 618eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung private void scaleChild(BubbleTextView bubbleChild, float pivot, float scale) { 619bc239a15464f543a41b960b946aa77258454efafAndrew Flynn // If we haven't measured the child yet, do it now 620bc239a15464f543a41b960b946aa77258454efafAndrew Flynn // (this happens if we're being dropped from all-apps 621bc239a15464f543a41b960b946aa77258454efafAndrew Flynn if (bubbleChild.getLayoutParams() instanceof LayoutParams && 622bc239a15464f543a41b960b946aa77258454efafAndrew Flynn (bubbleChild.getMeasuredWidth() | bubbleChild.getMeasuredHeight()) == 0) { 623a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka getShortcutsAndWidgets().measureChild(bubbleChild); 624bc239a15464f543a41b960b946aa77258454efafAndrew Flynn } 625bc239a15464f543a41b960b946aa77258454efafAndrew Flynn 626bc239a15464f543a41b960b946aa77258454efafAndrew Flynn bubbleChild.setScaleX(scale); 627bc239a15464f543a41b960b946aa77258454efafAndrew Flynn bubbleChild.setScaleY(scale); 628bc239a15464f543a41b960b946aa77258454efafAndrew Flynn } 629bc239a15464f543a41b960b946aa77258454efafAndrew Flynn 630bc239a15464f543a41b960b946aa77258454efafAndrew Flynn private void resetChild(BubbleTextView bubbleChild) { 631bc239a15464f543a41b960b946aa77258454efafAndrew Flynn bubbleChild.setScaleX(1f); 632bc239a15464f543a41b960b946aa77258454efafAndrew Flynn bubbleChild.setScaleY(1f); 633bc239a15464f543a41b960b946aa77258454efafAndrew Flynn 634bc239a15464f543a41b960b946aa77258454efafAndrew Flynn bubbleChild.setTextColor(getResources().getColor(R.color.workspace_icon_text_color)); 635bc239a15464f543a41b960b946aa77258454efafAndrew Flynn } 636bc239a15464f543a41b960b946aa77258454efafAndrew Flynn 6370dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn public boolean addViewToCellLayout(View child, int index, int childId, LayoutParams params, 6380dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn boolean markCells, boolean allApps) { 639aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung final LayoutParams lp = params; 640aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 6410dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn // Hotseat icons - scale down and remove text 6420dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn // Don't scale the all apps button 6430dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn // scale percent set to -1 means do not scale 6440dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn // Only scale BubbleTextViews 6450dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn if (child instanceof BubbleTextView) { 6460dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn BubbleTextView bubbleChild = (BubbleTextView) child; 6470dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn 648bc239a15464f543a41b960b946aa77258454efafAndrew Flynn // Start the child with 100% scale and visible text 649bc239a15464f543a41b960b946aa77258454efafAndrew Flynn resetChild(bubbleChild); 650bc239a15464f543a41b960b946aa77258454efafAndrew Flynn 651eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung if (mIsHotseat && !allApps && mHotseatChildScale >= 0) { 652bc239a15464f543a41b960b946aa77258454efafAndrew Flynn // Scale/make transparent for a hotseat 653eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung scaleChild(bubbleChild, 0f, mHotseatChildScale); 6540dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn 655bc239a15464f543a41b960b946aa77258454efafAndrew Flynn bubbleChild.setTextColor(getResources().getColor(android.R.color.transparent)); 656eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung } else if (mChildScale >= 0) { 657bc239a15464f543a41b960b946aa77258454efafAndrew Flynn // Else possibly still scale it if we need to for smaller icons 658eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung scaleChild(bubbleChild, 0f, mChildScale); 6590dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn } 6600dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn } 6610dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn 66231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // Generate an id for each view, this assumes we have at most 256x256 cells 66331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // per workspace screen 664d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen if (lp.cellX >= 0 && lp.cellX <= mCountX - 1 && lp.cellY >= 0 && lp.cellY <= mCountY - 1) { 665aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung // If the horizontal or vertical span is set to -1, it is taken to 666aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung // mean that it spans the extent of the CellLayout 667d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen if (lp.cellHSpan < 0) lp.cellHSpan = mCountX; 668d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen if (lp.cellVSpan < 0) lp.cellVSpan = mCountY; 669aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 670aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung child.setId(childId); 67131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 672a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.addView(child, index, lp); 673dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka 674f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka if (markCells) markCellsAsOccupiedForView(child); 6750280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 676aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung return true; 677aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung } 678aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung return false; 67931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 6803e7c7634531302271270c8cf418abc959d621cbcMichael Jurka 68131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 6820280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka public void removeAllViews() { 6830280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka clearOccupiedCells(); 684a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.removeAllViews(); 6850280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 6860280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 6870280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka @Override 6880280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka public void removeAllViewsInLayout() { 689a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka if (mShortcutsAndWidgets.getChildCount() > 0) { 6907cfc2825c3a1029f962d2fc387ae2eaa85b51798Michael Jurka clearOccupiedCells(); 691a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.removeAllViewsInLayout(); 6927cfc2825c3a1029f962d2fc387ae2eaa85b51798Michael Jurka } 6930280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 6940280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 695f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka public void removeViewWithoutMarkingCells(View view) { 696a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.removeView(view); 697f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka } 698f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka 6990280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka @Override 7000280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka public void removeView(View view) { 7010280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka markCellsAsUnoccupiedForView(view); 702a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.removeView(view); 7030280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 7040280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 7050280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka @Override 7060280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka public void removeViewAt(int index) { 707a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka markCellsAsUnoccupiedForView(mShortcutsAndWidgets.getChildAt(index)); 708a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.removeViewAt(index); 7090280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 7100280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 7110280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka @Override 7120280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka public void removeViewInLayout(View view) { 7130280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka markCellsAsUnoccupiedForView(view); 714a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.removeViewInLayout(view); 7150280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 7160280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 7170280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka @Override 7180280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka public void removeViews(int start, int count) { 7190280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka for (int i = start; i < start + count; i++) { 720a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka markCellsAsUnoccupiedForView(mShortcutsAndWidgets.getChildAt(i)); 7210280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 722a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.removeViews(start, count); 7230280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 7240280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 7250280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka @Override 7260280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka public void removeViewsInLayout(int start, int count) { 7270280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka for (int i = start; i < start + count; i++) { 728a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka markCellsAsUnoccupiedForView(mShortcutsAndWidgets.getChildAt(i)); 7290280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 730a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.removeViewsInLayout(start, count); 731abded66084680bb31cc7ea403c88f44f79a3c884Michael Jurka } 732abded66084680bb31cc7ea403c88f44f79a3c884Michael Jurka 73331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 73431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected void onAttachedToWindow() { 73531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project super.onAttachedToWindow(); 73631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mCellInfo.screen = ((ViewGroup) getParent()).indexOfChild(this); 73731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 73831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 739af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka public void setTagToCellInfoForPoint(int touchX, int touchY) { 74031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final CellInfo cellInfo = mCellInfo; 741eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung Rect frame = mRect; 742af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka final int x = touchX + mScrollX; 743af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka final int y = touchY + mScrollY; 744a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka final int count = mShortcutsAndWidgets.getChildCount(); 74531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 746af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka boolean found = false; 747af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka for (int i = count - 1; i >= 0; i--) { 748a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka final View child = mShortcutsAndWidgets.getChildAt(i); 749d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 750af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka 7511b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen if ((child.getVisibility() == VISIBLE || child.getAnimation() != null) && 7521b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen lp.isLockedToGrid) { 753af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka child.getHitRect(frame); 7540be025d64c1f84138fe430a58875886e66aae767Winson Chung 755eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung float scale = child.getScaleX(); 756eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung frame = new Rect(child.getLeft(), child.getTop(), child.getRight(), 757eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung child.getBottom()); 7580be025d64c1f84138fe430a58875886e66aae767Winson Chung // The child hit rect is relative to the CellLayoutChildren parent, so we need to 7590be025d64c1f84138fe430a58875886e66aae767Winson Chung // offset that by this CellLayout's padding to test an (x,y) point that is relative 7600be025d64c1f84138fe430a58875886e66aae767Winson Chung // to this view. 7614b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung frame.offset(mPaddingLeft, mPaddingTop); 762eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung frame.inset((int) (frame.width() * (1f - scale) / 2), 763eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung (int) (frame.height() * (1f - scale) / 2)); 7640be025d64c1f84138fe430a58875886e66aae767Winson Chung 765af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka if (frame.contains(x, y)) { 766af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.cell = child; 767af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.cellX = lp.cellX; 768af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.cellY = lp.cellY; 769af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.spanX = lp.cellHSpan; 770af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.spanY = lp.cellVSpan; 771af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka found = true; 772af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka break; 77331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 77431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 775af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka } 776aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 777d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka mLastDownOnOccupiedCell = found; 778d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka 779af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka if (!found) { 7800be025d64c1f84138fe430a58875886e66aae767Winson Chung final int cellXY[] = mTmpXY; 781af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka pointToCellExact(x, y, cellXY); 78231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 783af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.cell = null; 784af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.cellX = cellXY[0]; 785af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.cellY = cellXY[1]; 786af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.spanX = 1; 787af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.spanY = 1; 788af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka } 789af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka setTag(cellInfo); 790af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka } 79131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 792af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka @Override 793af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka public boolean onInterceptTouchEvent(MotionEvent ev) { 794c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen // First we clear the tag to ensure that on every touch down we start with a fresh slate, 795c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen // even in the case where we return early. Not clearing here was causing bugs whereby on 796c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen // long-press we'd end up picking up an item from a previous drag operation. 797c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen final int action = ev.getAction(); 798c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen 799c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen if (action == MotionEvent.ACTION_DOWN) { 800c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen clearTagCellInfo(); 801c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen } 802c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen 803dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka if (mInterceptTouchListener != null && mInterceptTouchListener.onTouch(this, ev)) { 804dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka return true; 805dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } 80631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 807af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka if (action == MotionEvent.ACTION_DOWN) { 808af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka setTagToCellInfoForPoint((int) ev.getX(), (int) ev.getY()); 80931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 810eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung 81131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return false; 81231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 81331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 814c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen private void clearTagCellInfo() { 815c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen final CellInfo cellInfo = mCellInfo; 816c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen cellInfo.cell = null; 817c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen cellInfo.cellX = -1; 818c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen cellInfo.cellY = -1; 819c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen cellInfo.spanX = 0; 820c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen cellInfo.spanY = 0; 821c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen setTag(cellInfo); 822c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen } 823c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen 82431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public CellInfo getTag() { 8250280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka return (CellInfo) super.getTag(); 82631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 82731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 8286569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy /** 829aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * Given a point, return the cell that strictly encloses that point 83031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param x X coordinate of the point 83131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param y Y coordinate of the point 83231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param result Array of 2 ints to hold the x and y coordinate of the cell 83331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 83431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project void pointToCellExact(int x, int y, int[] result) { 8354b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung final int hStartPadding = getPaddingLeft(); 8364b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung final int vStartPadding = getPaddingTop(); 83731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 83831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project result[0] = (x - hStartPadding) / (mCellWidth + mWidthGap); 83931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project result[1] = (y - vStartPadding) / (mCellHeight + mHeightGap); 84031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 841d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen final int xAxis = mCountX; 842d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen final int yAxis = mCountY; 84331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 84431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (result[0] < 0) result[0] = 0; 84531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (result[0] >= xAxis) result[0] = xAxis - 1; 84631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (result[1] < 0) result[1] = 0; 84731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (result[1] >= yAxis) result[1] = yAxis - 1; 84831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 849aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 85031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 85131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Given a point, return the cell that most closely encloses that point 85231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param x X coordinate of the point 85331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param y Y coordinate of the point 85431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param result Array of 2 ints to hold the x and y coordinate of the cell 85531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 85631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project void pointToCellRounded(int x, int y, int[] result) { 85731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project pointToCellExact(x + (mCellWidth / 2), y + (mCellHeight / 2), result); 85831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 85931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 86031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 86131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Given a cell coordinate, return the point that represents the upper left corner of that cell 862aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * 863aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * @param cellX X coordinate of the cell 86431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param cellY Y coordinate of the cell 865aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * 86631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param result Array of 2 ints to hold the x and y coordinate of the point 86731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 86831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project void cellToPoint(int cellX, int cellY, int[] result) { 8694b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung final int hStartPadding = getPaddingLeft(); 8704b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung final int vStartPadding = getPaddingTop(); 87131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 87231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project result[0] = hStartPadding + cellX * (mCellWidth + mWidthGap); 87331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project result[1] = vStartPadding + cellY * (mCellHeight + mHeightGap); 87431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 87531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 876e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen /** 877482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * Given a cell coordinate, return the point that represents the center of the cell 878e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen * 879e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen * @param cellX X coordinate of the cell 880e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen * @param cellY Y coordinate of the cell 881e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen * 882e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen * @param result Array of 2 ints to hold the x and y coordinate of the point 883e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen */ 884e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen void cellToCenterPoint(int cellX, int cellY, int[] result) { 88547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen regionToCenterPoint(cellX, cellY, 1, 1, result); 88647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 88747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 88847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen /** 88947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * Given a cell coordinate and span return the point that represents the center of the regio 89047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * 89147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param cellX X coordinate of the cell 89247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param cellY Y coordinate of the cell 89347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * 89447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param result Array of 2 ints to hold the x and y coordinate of the point 89547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen */ 89647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen void regionToCenterPoint(int cellX, int cellY, int spanX, int spanY, int[] result) { 8974b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung final int hStartPadding = getPaddingLeft(); 8984b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung final int vStartPadding = getPaddingTop(); 89947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen result[0] = hStartPadding + cellX * (mCellWidth + mWidthGap) + 90047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen (spanX * mCellWidth + (spanX - 1) * mWidthGap) / 2; 90147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen result[1] = vStartPadding + cellY * (mCellHeight + mHeightGap) + 90247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen (spanY * mCellHeight + (spanY - 1) * mHeightGap) / 2; 903e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen } 904e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen 90519f3792523fe2d55ea791a9286398a6120920690Adam Cohen /** 90619f3792523fe2d55ea791a9286398a6120920690Adam Cohen * Given a cell coordinate and span fills out a corresponding pixel rect 90719f3792523fe2d55ea791a9286398a6120920690Adam Cohen * 90819f3792523fe2d55ea791a9286398a6120920690Adam Cohen * @param cellX X coordinate of the cell 90919f3792523fe2d55ea791a9286398a6120920690Adam Cohen * @param cellY Y coordinate of the cell 91019f3792523fe2d55ea791a9286398a6120920690Adam Cohen * @param result Rect in which to write the result 91119f3792523fe2d55ea791a9286398a6120920690Adam Cohen */ 91219f3792523fe2d55ea791a9286398a6120920690Adam Cohen void regionToRect(int cellX, int cellY, int spanX, int spanY, Rect result) { 91319f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int hStartPadding = getPaddingLeft(); 91419f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int vStartPadding = getPaddingTop(); 91519f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int left = hStartPadding + cellX * (mCellWidth + mWidthGap); 91619f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int top = vStartPadding + cellY * (mCellHeight + mHeightGap); 91719f3792523fe2d55ea791a9286398a6120920690Adam Cohen result.set(left, top, left + (spanX * mCellWidth + (spanX - 1) * mWidthGap), 91819f3792523fe2d55ea791a9286398a6120920690Adam Cohen top + (spanY * mCellHeight + (spanY - 1) * mHeightGap)); 91919f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 92019f3792523fe2d55ea791a9286398a6120920690Adam Cohen 921482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public float getDistanceFromCell(float x, float y, int[] cell) { 922482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen cellToCenterPoint(cell[0], cell[1], mTmpPoint); 923482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen float distance = (float) Math.sqrt( Math.pow(x - mTmpPoint[0], 2) + 924482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen Math.pow(y - mTmpPoint[1], 2)); 925482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return distance; 926482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 927482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 92884f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy int getCellWidth() { 92984f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy return mCellWidth; 93084f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy } 93184f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy 93284f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy int getCellHeight() { 93384f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy return mCellHeight; 93484f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy } 93584f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy 936d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen int getWidthGap() { 937d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen return mWidthGap; 938d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen } 939d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen 940d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen int getHeightGap() { 941d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen return mHeightGap; 942d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen } 943d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen 9447f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen Rect getContentRect(Rect r) { 9457f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen if (r == null) { 9467f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen r = new Rect(); 9477f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 9487f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen int left = getPaddingLeft(); 9497f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen int top = getPaddingTop(); 9504b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung int right = left + getWidth() - mPaddingLeft - mPaddingRight; 9514b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung int bottom = top + getHeight() - mPaddingTop - mPaddingBottom; 9527f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen r.set(left, top, right, bottom); 9537f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen return r; 9547f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 9557f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 95631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 95731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 95831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // TODO: currently ignoring padding 959aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 96031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec); 961aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec); 962aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 96331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec); 96431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec); 965aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 96631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (widthSpecMode == MeasureSpec.UNSPECIFIED || heightSpecMode == MeasureSpec.UNSPECIFIED) { 96731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project throw new RuntimeException("CellLayout cannot have UNSPECIFIED dimensions"); 96831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 96931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 970d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen int numWidthGaps = mCountX - 1; 971d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen int numHeightGaps = mCountY - 1; 972d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen 973234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen if (mOriginalWidthGap < 0 || mOriginalHeightGap < 0) { 9744b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung int hSpace = widthSpecSize - mPaddingLeft - mPaddingRight; 9754b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung int vSpace = heightSpecSize - mPaddingTop - mPaddingBottom; 9764b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung int hFreeSpace = hSpace - (mCountX * mOriginalCellWidth); 9774b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung int vFreeSpace = vSpace - (mCountY * mOriginalCellHeight); 9784b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung mWidthGap = Math.min(mMaxGap, numWidthGaps > 0 ? (hFreeSpace / numWidthGaps) : 0); 9794b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung mHeightGap = Math.min(mMaxGap,numHeightGaps > 0 ? (vFreeSpace / numHeightGaps) : 0); 980a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.setCellDimensions(mCellWidth, mCellHeight, mWidthGap, mHeightGap); 981234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen } else { 982234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen mWidthGap = mOriginalWidthGap; 983234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen mHeightGap = mOriginalHeightGap; 984ece7f5b3b55cab646941123e03589241a61678e2Winson Chung } 9855f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka 9868c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka // Initial values correspond to widthSpecMode == MeasureSpec.EXACTLY 9878c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka int newWidth = widthSpecSize; 9888c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka int newHeight = heightSpecSize; 9898c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka if (widthSpecMode == MeasureSpec.AT_MOST) { 9904b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung newWidth = mPaddingLeft + mPaddingRight + (mCountX * mCellWidth) + 9918c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka ((mCountX - 1) * mWidthGap); 9924b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung newHeight = mPaddingTop + mPaddingBottom + (mCountY * mCellHeight) + 9938c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka ((mCountY - 1) * mHeightGap); 9948c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka setMeasuredDimension(newWidth, newHeight); 9958c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka } 99631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 9978c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka int count = getChildCount(); 99831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int i = 0; i < count; i++) { 99931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project View child = getChildAt(i); 10004b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(newWidth - mPaddingLeft - 10014b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung mPaddingRight, MeasureSpec.EXACTLY); 10024b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung int childheightMeasureSpec = MeasureSpec.makeMeasureSpec(newHeight - mPaddingTop - 10034b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung mPaddingBottom, MeasureSpec.EXACTLY); 100431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project child.measure(childWidthMeasureSpec, childheightMeasureSpec); 100531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 10068c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka setMeasuredDimension(newWidth, newHeight); 100731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 100831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 100931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 101028750fba6a2d141eb9a1e566718c17236030b815Michael Jurka protected void onLayout(boolean changed, int l, int t, int r, int b) { 101131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int count = getChildCount(); 101231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int i = 0; i < count; i++) { 10138c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka View child = getChildAt(i); 10144b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung child.layout(mPaddingLeft, mPaddingTop, 10154b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung r - l - mPaddingRight, b - t - mPaddingBottom); 101631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 101731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 101831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 101931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 1020dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka protected void onSizeChanged(int w, int h, int oldw, int oldh) { 1021dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka super.onSizeChanged(w, h, oldw, oldh); 102218014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka mBackgroundRect.set(0, 0, w, h); 1023b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mForegroundRect.set(mForegroundPadding, mForegroundPadding, 1024b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen w - 2 * mForegroundPadding, h - 2 * mForegroundPadding); 1025dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } 1026dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka 1027dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka @Override 102831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected void setChildrenDrawingCacheEnabled(boolean enabled) { 1029a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.setChildrenDrawingCacheEnabled(enabled); 103031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 103131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 103231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 103331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected void setChildrenDrawnWithCacheEnabled(boolean enabled) { 1034a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.setChildrenDrawnWithCacheEnabled(enabled); 103531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 103631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 10375f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka public float getBackgroundAlpha() { 10385f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka return mBackgroundAlpha; 1039dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } 1040dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka 10411b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen public void setBackgroundAlphaMultiplier(float multiplier) { 10421b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen mBackgroundAlphaMultiplier = multiplier; 10431b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen } 10441b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen 1045ddb821981e0919bbd3b4c9a2b6aa1811d6c86bb6Adam Cohen public float getBackgroundAlphaMultiplier() { 1046ddb821981e0919bbd3b4c9a2b6aa1811d6c86bb6Adam Cohen return mBackgroundAlphaMultiplier; 1047ddb821981e0919bbd3b4c9a2b6aa1811d6c86bb6Adam Cohen } 1048ddb821981e0919bbd3b4c9a2b6aa1811d6c86bb6Adam Cohen 10495f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka public void setBackgroundAlpha(float alpha) { 1050afaa05014e0bf3ed1192f9ddec2af4283bc50248Michael Jurka if (mBackgroundAlpha != alpha) { 1051afaa05014e0bf3ed1192f9ddec2af4283bc50248Michael Jurka mBackgroundAlpha = alpha; 1052afaa05014e0bf3ed1192f9ddec2af4283bc50248Michael Jurka invalidate(); 1053afaa05014e0bf3ed1192f9ddec2af4283bc50248Michael Jurka } 1054dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } 1055dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka 1056a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka public void setShortcutAndWidgetAlpha(float alpha) { 10570142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka final int childCount = getChildCount(); 10580142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka for (int i = 0; i < childCount; i++) { 1059dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka getChildAt(i).setAlpha(alpha); 1060dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } 1061dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } 1062dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka 1063a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka public ShortcutAndWidgetContainer getShortcutsAndWidgets() { 1064a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka if (getChildCount() > 0) { 1065a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka return (ShortcutAndWidgetContainer) getChildAt(0); 1066a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka } 1067a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka return null; 1068a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka } 1069a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka 1070440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy public View getChildAt(int x, int y) { 1071a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka return mShortcutsAndWidgets.getChildAt(x, y); 1072440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy } 1073440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy 107476fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen public boolean animateChildToPosition(final View child, int cellX, int cellY, int duration, 1075482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int delay, boolean permanent, boolean adjustOccupied) { 1076a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka ShortcutAndWidgetContainer clc = getShortcutsAndWidgets(); 1077482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean[][] occupied = mOccupied; 1078482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (!permanent) { 1079482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen occupied = mTmpOccupied; 1080482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1081482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 108219f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (clc.indexOfChild(child) != -1) { 1083bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 1084bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen final ItemInfo info = (ItemInfo) child.getTag(); 1085bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen 1086bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen // We cancel any existing animations 1087bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen if (mReorderAnimators.containsKey(lp)) { 1088bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen mReorderAnimators.get(lp).cancel(); 1089bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen mReorderAnimators.remove(lp); 1090bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 1091bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen 1092482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int oldX = lp.x; 1093482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int oldY = lp.y; 1094482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (adjustOccupied) { 1095482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen occupied[lp.cellX][lp.cellY] = false; 1096482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen occupied[cellX][cellY] = true; 1097482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1098bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen lp.isLockedToGrid = true; 1099482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (permanent) { 1100482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen lp.cellX = info.cellX = cellX; 1101482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen lp.cellY = info.cellY = cellY; 1102482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } else { 1103482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen lp.tmpCellX = cellX; 1104482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen lp.tmpCellY = cellY; 1105482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1106bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen clc.setupLp(lp); 1107bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen lp.isLockedToGrid = false; 1108482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int newX = lp.x; 1109482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int newY = lp.y; 1110bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen 111176fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen lp.x = oldX; 111276fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen lp.y = oldY; 111376fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen 1114482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // Exit early if we're not actually moving the view 1115482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (oldX == newX && oldY == newY) { 1116482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen lp.isLockedToGrid = true; 1117482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return true; 1118482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1119482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1120482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen ValueAnimator va = ValueAnimator.ofFloat(0f, 1f); 1121482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen va.setDuration(duration); 1122482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mReorderAnimators.put(lp, va); 1123482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1124482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen va.addUpdateListener(new AnimatorUpdateListener() { 1125482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen @Override 1126bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen public void onAnimationUpdate(ValueAnimator animation) { 1127482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen float r = ((Float) animation.getAnimatedValue()).floatValue(); 112819f3792523fe2d55ea791a9286398a6120920690Adam Cohen lp.x = (int) ((1 - r) * oldX + r * newX); 112919f3792523fe2d55ea791a9286398a6120920690Adam Cohen lp.y = (int) ((1 - r) * oldY + r * newY); 11306b8a02d63a5d9cab8209381993e37db6a6afb753Adam Cohen child.requestLayout(); 1131bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 1132bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen }); 1133482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen va.addListener(new AnimatorListenerAdapter() { 1134bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen boolean cancelled = false; 1135bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen public void onAnimationEnd(Animator animation) { 1136bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen // If the animation was cancelled, it means that another animation 1137bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen // has interrupted this one, and we don't want to lock the item into 1138bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen // place just yet. 1139bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen if (!cancelled) { 1140bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen lp.isLockedToGrid = true; 1141482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen child.requestLayout(); 1142bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 1143bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen if (mReorderAnimators.containsKey(lp)) { 1144bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen mReorderAnimators.remove(lp); 1145bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 1146bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 1147bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen public void onAnimationCancel(Animator animation) { 1148bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen cancelled = true; 1149bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 1150bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen }); 1151482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen va.setStartDelay(delay); 1152482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen va.start(); 1153bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen return true; 1154bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 1155bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen return false; 1156bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 1157bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen 11586569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy /** 11596569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy * Estimate where the top left cell of the dragged item will land if it is dropped. 11606569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy * 11616569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy * @param originX The X value of the top left corner of the item 11626569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy * @param originY The Y value of the top left corner of the item 11636569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy * @param spanX The number of horizontal cells that the item spans 11646569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy * @param spanY The number of vertical cells that the item spans 11656569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy * @param result The estimated drop cell X and Y. 11666569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy */ 11676569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy void estimateDropCell(int originX, int originY, int spanX, int spanY, int[] result) { 1168d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen final int countX = mCountX; 1169d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen final int countY = mCountY; 11706569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 1171a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka // pointToCellRounded takes the top left of a cell but will pad that with 1172a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka // cellWidth/2 and cellHeight/2 when finding the matching cell 1173a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka pointToCellRounded(originX, originY, result); 11746569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 11756569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy // If the item isn't fully on this screen, snap to the edges 11766569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy int rightOverhang = result[0] + spanX - countX; 11776569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy if (rightOverhang > 0) { 11786569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy result[0] -= rightOverhang; // Snap to right 11796569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy } 11806569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy result[0] = Math.max(0, result[0]); // Snap to left 11816569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy int bottomOverhang = result[1] + spanY - countY; 11826569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy if (bottomOverhang > 0) { 11836569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy result[1] -= bottomOverhang; // Snap to bottom 11846569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy } 11856569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy result[1] = Math.max(0, result[1]); // Snap to top 11866569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy } 11876569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 1188482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen void visualizeDropLocation(View v, Bitmap dragOutline, int originX, int originY, int cellX, 1189482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int cellY, int spanX, int spanY, boolean resize, Point dragOffset, Rect dragRegion) { 119008ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy final int oldDragCellX = mDragCell[0]; 119108ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy final int oldDragCellY = mDragCell[1]; 1192482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1193b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung if (v != null && dragOffset == null) { 1194a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung mDragCenter.set(originX + (v.getWidth() / 2), originY + (v.getHeight() / 2)); 1195a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung } else { 1196a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung mDragCenter.set(originX, originY); 1197a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung } 11986569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 11992801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen if (dragOutline == null && v == null) { 12002801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen if (mCrosshairsDrawable != null) { 12012801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen invalidate(); 12022801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen } 12032801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen return; 12042801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen } 12052801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen 1206482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (cellX != oldDragCellX || cellY != oldDragCellY) { 1207482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mDragCell[0] = cellX; 1208482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mDragCell[1] = cellY; 12096569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy // Find the top left corner of the rect the object will occupy 1210de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy final int[] topLeft = mTmpPoint; 1211482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen cellToPoint(cellX, cellY, topLeft); 1212de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy 12134be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato int left = topLeft[0]; 12144be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato int top = topLeft[1]; 12156569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 1216b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung if (v != null && dragOffset == null) { 121799e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen // When drawing the drag outline, it did not account for margin offsets 121899e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen // added by the view's parent. 121999e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen MarginLayoutParams lp = (MarginLayoutParams) v.getLayoutParams(); 122099e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen left += lp.leftMargin; 122199e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen top += lp.topMargin; 122299e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen 122399e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen // Offsets due to the size difference between the View and the dragOutline. 122499e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen // There is a size difference to account for the outer blur, which may lie 122599e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen // outside the bounds of the view. 1226a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung top += (v.getHeight() - dragOutline.getHeight()) / 2; 1227ae915cecd36af4973061a1cb0b58c5be1be699a0Adam Cohen // We center about the x axis 1228ae915cecd36af4973061a1cb0b58c5be1be699a0Adam Cohen left += ((mCellWidth * spanX) + ((spanX - 1) * mWidthGap) 1229ae915cecd36af4973061a1cb0b58c5be1be699a0Adam Cohen - dragOutline.getWidth()) / 2; 12306639687cd67bab1aeef2a75e5c6bc458b20dc082Adam Cohen } else { 1231b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung if (dragOffset != null && dragRegion != null) { 1232b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung // Center the drag region *horizontally* in the cell and apply a drag 1233b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung // outline offset 1234b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung left += dragOffset.x + ((mCellWidth * spanX) + ((spanX - 1) * mWidthGap) 1235b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung - dragRegion.width()) / 2; 1236b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung top += dragOffset.y; 1237b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung } else { 1238b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung // Center the drag outline in the cell 1239b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung left += ((mCellWidth * spanX) + ((spanX - 1) * mWidthGap) 1240b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung - dragOutline.getWidth()) / 2; 1241b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung top += ((mCellHeight * spanY) + ((spanY - 1) * mHeightGap) 1242b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung - dragOutline.getHeight()) / 2; 1243b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung } 1244a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung } 12454be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato final int oldIndex = mDragOutlineCurrent; 124608ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy mDragOutlineAnims[oldIndex].animateOut(); 124708ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy mDragOutlineCurrent = (oldIndex + 1) % mDragOutlines.length; 1248d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen Rect r = mDragOutlines[mDragOutlineCurrent]; 1249d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen r.set(left, top, left + dragOutline.getWidth(), top + dragOutline.getHeight()); 1250d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (resize) { 1251482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen cellToRect(cellX, cellY, spanX, spanY, r); 1252d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1253150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung 125408ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy mDragOutlineAnims[mDragOutlineCurrent].setTag(dragOutline); 125508ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy mDragOutlineAnims[mDragOutlineCurrent].animateIn(); 12566569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy } 125749250ad530385fcdd6072ca54697f670ec503b59Patrick Dubroy 125849250ad530385fcdd6072ca54697f670ec503b59Patrick Dubroy // If we are drawing crosshairs, the entire CellLayout needs to be invalidated 125949250ad530385fcdd6072ca54697f670ec503b59Patrick Dubroy if (mCrosshairsDrawable != null) { 126049250ad530385fcdd6072ca54697f670ec503b59Patrick Dubroy invalidate(); 126149250ad530385fcdd6072ca54697f670ec503b59Patrick Dubroy } 12626569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy } 12636569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 1264e0310965022e7a1adb7ad489505d404186608689Adam Cohen public void clearDragOutlines() { 1265e0310965022e7a1adb7ad489505d404186608689Adam Cohen final int oldIndex = mDragOutlineCurrent; 1266e0310965022e7a1adb7ad489505d404186608689Adam Cohen mDragOutlineAnims[oldIndex].animateOut(); 1267d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen mDragCell[0] = mDragCell[1] = -1; 1268e0310965022e7a1adb7ad489505d404186608689Adam Cohen } 1269e0310965022e7a1adb7ad489505d404186608689Adam Cohen 127031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 127170864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * Find a vacant area that will fit the given bounds nearest the requested 127270864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * cell location. Uses Euclidean distance to score multiple vacant areas. 1273aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * 127451afc022fa76c79f0d1ece470ddc126c08fea8a4Romain Guy * @param pixelX The X location at which you want to search for a vacant area. 127551afc022fa76c79f0d1ece470ddc126c08fea8a4Romain Guy * @param pixelY The Y location at which you want to search for a vacant area. 127670864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * @param spanX Horizontal span of the object. 127770864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * @param spanY Vertical span of the object. 1278de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy * @param result Array in which to place the result, or null (in which case a new array will 1279de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy * be allocated) 128070864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * @return The X, Y cell of a vacant area that can contain this object, 128170864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * nearest the requested location. 128231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 1283d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int[] findNearestVacantArea(int pixelX, int pixelY, int spanX, int spanY, 1284d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int[] result) { 1285de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy return findNearestVacantArea(pixelX, pixelY, spanX, spanY, null, result); 12866a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka } 1287aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 12886a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka /** 12896a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * Find a vacant area that will fit the given bounds nearest the requested 12906a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * cell location. Uses Euclidean distance to score multiple vacant areas. 12916a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * 12926a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * @param pixelX The X location at which you want to search for a vacant area. 12936a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * @param pixelY The Y location at which you want to search for a vacant area. 1294d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param minSpanX The minimum horizontal span required 1295d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param minSpanY The minimum vertical span required 1296d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param spanX Horizontal span of the object. 1297d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param spanY Vertical span of the object. 1298d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param result Array in which to place the result, or null (in which case a new array will 1299d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * be allocated) 1300d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @return The X, Y cell of a vacant area that can contain this object, 1301d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * nearest the requested location. 1302d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen */ 1303d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int[] findNearestVacantArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, 1304d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int spanY, int[] result, int[] resultSpan) { 1305d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen return findNearestVacantArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, null, 1306d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen result, resultSpan); 1307d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1308d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen 1309d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen /** 1310d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * Find a vacant area that will fit the given bounds nearest the requested 1311d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * cell location. Uses Euclidean distance to score multiple vacant areas. 1312d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * 1313d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param pixelX The X location at which you want to search for a vacant area. 1314d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param pixelY The Y location at which you want to search for a vacant area. 13156a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * @param spanX Horizontal span of the object. 13166a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * @param spanY Vertical span of the object. 1317df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param ignoreOccupied If true, the result can be an occupied cell 1318df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param result Array in which to place the result, or null (in which case a new array will 1319df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * be allocated) 13206a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * @return The X, Y cell of a vacant area that can contain this object, 13216a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * nearest the requested location. 13226a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka */ 1323df0353815c629fc678824b07a234b89a1ff94208Adam Cohen int[] findNearestArea(int pixelX, int pixelY, int spanX, int spanY, View ignoreView, 1324df0353815c629fc678824b07a234b89a1ff94208Adam Cohen boolean ignoreOccupied, int[] result) { 1325d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen return findNearestArea(pixelX, pixelY, spanX, spanY, 1326482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen spanX, spanY, ignoreView, ignoreOccupied, result, null, mOccupied); 1327d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1328d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen 1329d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen private final Stack<Rect> mTempRectStack = new Stack<Rect>(); 1330d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen private void lazyInitTempRectStack() { 1331d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (mTempRectStack.isEmpty()) { 1332d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen for (int i = 0; i < mCountX * mCountY; i++) { 1333d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen mTempRectStack.push(new Rect()); 1334d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1335d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1336d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1337482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1338d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen private void recycleTempRects(Stack<Rect> used) { 1339d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen while (!used.isEmpty()) { 1340d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen mTempRectStack.push(used.pop()); 1341d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1342d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1343d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen 1344d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen /** 1345d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * Find a vacant area that will fit the given bounds nearest the requested 1346d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * cell location. Uses Euclidean distance to score multiple vacant areas. 1347d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * 1348d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param pixelX The X location at which you want to search for a vacant area. 1349d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param pixelY The Y location at which you want to search for a vacant area. 1350d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param minSpanX The minimum horizontal span required 1351d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param minSpanY The minimum vertical span required 1352d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param spanX Horizontal span of the object. 1353d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param spanY Vertical span of the object. 1354d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param ignoreOccupied If true, the result can be an occupied cell 1355d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param result Array in which to place the result, or null (in which case a new array will 1356d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * be allocated) 1357d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @return The X, Y cell of a vacant area that can contain this object, 1358d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * nearest the requested location. 1359d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen */ 1360d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int[] findNearestArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, int spanY, 1361482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen View ignoreView, boolean ignoreOccupied, int[] result, int[] resultSpan, 1362482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean[][] occupied) { 1363d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen lazyInitTempRectStack(); 1364c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka // mark space take by ignoreView as available (method checks if ignoreView is null) 1365482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsAsUnoccupiedForView(ignoreView, occupied); 1366c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka 1367e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen // For items with a spanX / spanY > 1, the passed in point (pixelX, pixelY) corresponds 1368e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen // to the center of the item, but we are searching based on the top-left cell, so 1369e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen // we translate the point over to correspond to the top-left. 1370e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen pixelX -= (mCellWidth + mWidthGap) * (spanX - 1) / 2f; 1371e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen pixelY -= (mCellHeight + mHeightGap) * (spanY - 1) / 2f; 1372e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen 137370864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey // Keep track of best-scoring drop area 1374de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy final int[] bestXY = result != null ? result : new int[2]; 137570864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey double bestDistance = Double.MAX_VALUE; 1376d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen final Rect bestRect = new Rect(-1, -1, -1, -1); 1377d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen final Stack<Rect> validRegions = new Stack<Rect>(); 1378aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 1379de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy final int countX = mCountX; 1380de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy final int countY = mCountY; 1381de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy 1382d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (minSpanX <= 0 || minSpanY <= 0 || spanX <= 0 || spanY <= 0 || 1383d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen spanX < minSpanX || spanY < minSpanY) { 1384d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen return bestXY; 1385d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1386d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen 1387d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen for (int y = 0; y < countY - (minSpanY - 1); y++) { 1388c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka inner: 1389d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen for (int x = 0; x < countX - (minSpanX - 1); x++) { 1390d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int ySize = -1; 1391d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int xSize = -1; 1392df0353815c629fc678824b07a234b89a1ff94208Adam Cohen if (ignoreOccupied) { 1393d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // First, let's see if this thing fits anywhere 1394d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen for (int i = 0; i < minSpanX; i++) { 1395d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen for (int j = 0; j < minSpanY; j++) { 1396df0353815c629fc678824b07a234b89a1ff94208Adam Cohen if (occupied[x + i][y + j]) { 1397df0353815c629fc678824b07a234b89a1ff94208Adam Cohen continue inner; 1398df0353815c629fc678824b07a234b89a1ff94208Adam Cohen } 1399c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka } 1400c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka } 1401d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen xSize = minSpanX; 1402d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen ySize = minSpanY; 1403d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen 1404d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // We know that the item will fit at _some_ acceptable size, now let's see 1405d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // how big we can make it. We'll alternate between incrementing x and y spans 1406d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // until we hit a limit. 1407d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen boolean incX = true; 1408d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen boolean hitMaxX = xSize >= spanX; 1409d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen boolean hitMaxY = ySize >= spanY; 1410d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen while (!(hitMaxX && hitMaxY)) { 1411d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (incX && !hitMaxX) { 1412d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen for (int j = 0; j < ySize; j++) { 1413d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (x + xSize > countX -1 || occupied[x + xSize][y + j]) { 1414d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // We can't move out horizontally 1415d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen hitMaxX = true; 1416d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1417d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1418d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (!hitMaxX) { 1419d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen xSize++; 1420d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1421d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } else if (!hitMaxY) { 1422d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen for (int i = 0; i < xSize; i++) { 1423d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (y + ySize > countY - 1 || occupied[x + i][y + ySize]) { 1424d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // We can't move out vertically 1425d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen hitMaxY = true; 1426d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1427d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1428d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (!hitMaxY) { 1429d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen ySize++; 1430d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1431d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1432d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen hitMaxX |= xSize >= spanX; 1433d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen hitMaxY |= ySize >= spanY; 1434d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen incX = !incX; 1435d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1436d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen incX = true; 1437d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen hitMaxX = xSize >= spanX; 1438d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen hitMaxY = ySize >= spanY; 1439c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka } 14400be025d64c1f84138fe430a58875886e66aae767Winson Chung final int[] cellXY = mTmpXY; 1441e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen cellToCenterPoint(x, y, cellXY); 1442c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka 1443d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // We verify that the current rect is not a sub-rect of any of our previous 1444d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // candidates. In this case, the current rect is disqualified in favour of the 1445d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // containing rect. 1446d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen Rect currentRect = mTempRectStack.pop(); 1447d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen currentRect.set(x, y, x + xSize, y + ySize); 1448d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen boolean contained = false; 1449d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen for (Rect r : validRegions) { 1450d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (r.contains(currentRect)) { 1451d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen contained = true; 1452d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen break; 1453d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1454d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1455d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen validRegions.push(currentRect); 1456c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka double distance = Math.sqrt(Math.pow(cellXY[0] - pixelX, 2) 1457c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka + Math.pow(cellXY[1] - pixelY, 2)); 1458482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1459d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if ((distance <= bestDistance && !contained) || 1460d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen currentRect.contains(bestRect)) { 1461c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka bestDistance = distance; 1462c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka bestXY[0] = x; 1463c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka bestXY[1] = y; 1464d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (resultSpan != null) { 1465d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen resultSpan[0] = xSize; 1466d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen resultSpan[1] = ySize; 1467d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1468d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen bestRect.set(currentRect); 1469c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka } 147031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 147131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 1472c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka // re-mark space taken by ignoreView as occupied 1473482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsAsOccupiedForView(ignoreView, occupied); 147431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 1475c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen // Return -1, -1 if no suitable location found 1476c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen if (bestDistance == Double.MAX_VALUE) { 1477c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen bestXY[0] = -1; 1478c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen bestXY[1] = -1; 147970864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey } 1480d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen recycleTempRects(validRegions); 1481c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen return bestXY; 148231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 1483aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 1484482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen /** 1485482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * Find a vacant area that will fit the given bounds nearest the requested 1486482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * cell location, and will also weigh in a suggested direction vector of the 1487482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * desired location. This method computers distance based on unit grid distances, 1488482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * not pixel distances. 1489482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * 149047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param cellX The X cell nearest to which you want to search for a vacant area. 149147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param cellY The Y cell nearest which you want to search for a vacant area. 1492482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * @param spanX Horizontal span of the object. 1493482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * @param spanY Vertical span of the object. 149447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param direction The favored direction in which the views should move from x, y 149547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param exactDirectionOnly If this parameter is true, then only solutions where the direction 149647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * matches exactly. Otherwise we find the best matching direction. 149747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param occoupied The array which represents which cells in the CellLayout are occupied 149847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param blockOccupied The array which represents which cells in the specified block (cellX, 149947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * cellY, spanX, spanY) are occupied. This is used when try to move a group of views. 1500482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * @param result Array in which to place the result, or null (in which case a new array will 1501482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * be allocated) 1502482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * @return The X, Y cell of a vacant area that can contain this object, 1503482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * nearest the requested location. 1504482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen */ 1505482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private int[] findNearestArea(int cellX, int cellY, int spanX, int spanY, int[] direction, 150647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean[][] occupied, boolean blockOccupied[][], int[] result) { 1507482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // Keep track of best-scoring drop area 1508482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int[] bestXY = result != null ? result : new int[2]; 1509482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen float bestDistance = Float.MAX_VALUE; 1510482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int bestDirectionScore = Integer.MIN_VALUE; 1511482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1512482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int countX = mCountX; 1513482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int countY = mCountY; 1514482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1515482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int y = 0; y < countY - (spanY - 1); y++) { 1516482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen inner: 1517482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int x = 0; x < countX - (spanX - 1); x++) { 1518482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // First, let's see if this thing fits anywhere 1519482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < spanX; i++) { 1520482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int j = 0; j < spanY; j++) { 152147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (occupied[x + i][y + j] && (blockOccupied == null || blockOccupied[i][j])) { 1522482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen continue inner; 1523482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1524482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1525482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1526482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1527482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen float distance = (float) 1528482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen Math.sqrt((x - cellX) * (x - cellX) + (y - cellY) * (y - cellY)); 1529482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int[] curDirection = mTmpPoint; 153047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen computeDirectionVector(x - cellX, y - cellY, curDirection); 153147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen // The direction score is just the dot product of the two candidate direction 153247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen // and that passed in. 1533482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int curDirectionScore = direction[0] * curDirection[0] + 1534482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen direction[1] * curDirection[1]; 153547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean exactDirectionOnly = false; 153647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean directionMatches = direction[0] == curDirection[0] && 153747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen direction[0] == curDirection[0]; 153847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if ((directionMatches || !exactDirectionOnly) && 153947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen Float.compare(distance, bestDistance) < 0 || (Float.compare(distance, 1540482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen bestDistance) == 0 && curDirectionScore > bestDirectionScore)) { 1541482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen bestDistance = distance; 1542482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen bestDirectionScore = curDirectionScore; 1543482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen bestXY[0] = x; 1544482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen bestXY[1] = y; 1545482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1546482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1547482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1548482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1549482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // Return -1, -1 if no suitable location found 1550482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (bestDistance == Float.MAX_VALUE) { 1551482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen bestXY[0] = -1; 1552482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen bestXY[1] = -1; 1553482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1554482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return bestXY; 1555482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1556482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 155747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen private int[] findNearestAreaInDirection(int cellX, int cellY, int spanX, int spanY, 155847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen int[] direction,boolean[][] occupied, 155947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean blockOccupied[][], int[] result) { 156047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen // Keep track of best-scoring drop area 156147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen final int[] bestXY = result != null ? result : new int[2]; 156247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen bestXY[0] = -1; 156347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen bestXY[1] = -1; 156447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen float bestDistance = Float.MAX_VALUE; 156547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 156647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen // We use this to march in a single direction 156747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (direction[0] != 0 && direction[1] != 0) { 156847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen return bestXY; 156947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 157047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 157147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen // This will only incrememnet one of x or y based on the assertion above 157247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen int x = cellX + direction[0]; 157347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen int y = cellY + direction[1]; 157447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen while (x >= 0 && x + spanX <= mCountX && y >= 0 && y + spanY <= mCountY) { 157547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 157647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean fail = false; 157747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen for (int i = 0; i < spanX; i++) { 157847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen for (int j = 0; j < spanY; j++) { 157947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (occupied[x + i][y + j] && (blockOccupied == null || blockOccupied[i][j])) { 158047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen fail = true; 158147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 158247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 158347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 158447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (!fail) { 158547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen float distance = (float) 158647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen Math.sqrt((x - cellX) * (x - cellX) + (y - cellY) * (y - cellY)); 158747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (Float.compare(distance, bestDistance) < 0) { 158847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen bestDistance = distance; 158947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen bestXY[0] = x; 159047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen bestXY[1] = y; 159147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 159247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 159347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen x += direction[0]; 159447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen y += direction[1]; 159547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 159647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen return bestXY; 159747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 159847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 1599482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private boolean addViewToTempLocation(View v, Rect rectOccupiedByPotentialDrop, 16008baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen int[] direction, ItemConfiguration currentState) { 16018baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = currentState.map.get(v); 1602482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean success = false; 16038baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, false); 1604482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsForRect(rectOccupiedByPotentialDrop, mTmpOccupied, true); 1605482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 16068baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen findNearestArea(c.x, c.y, c.spanX, c.spanY, direction, mTmpOccupied, null, mTempLocation); 1607482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1608482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (mTempLocation[0] >= 0 && mTempLocation[1] >= 0) { 16098baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen c.x = mTempLocation[0]; 16108baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen c.y = mTempLocation[1]; 1611482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen success = true; 1612482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1613482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 16148baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, true); 1615482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return success; 1616482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1617482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 161847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen // This method looks in the specified direction to see if there is an additional view 161947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen // immediately adjecent in that direction 162047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen private boolean addViewInDirection(ArrayList<View> views, Rect boundingRect, int[] direction, 162119f3792523fe2d55ea791a9286398a6120920690Adam Cohen boolean[][] occupied, View dragView, ItemConfiguration currentState) { 162247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean found = false; 162347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 1624a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka int childCount = mShortcutsAndWidgets.getChildCount(); 162547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen Rect r0 = new Rect(boundingRect); 162647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen Rect r1 = new Rect(); 162747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 162847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen int deltaX = 0; 162947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen int deltaY = 0; 163047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (direction[1] < 0) { 163147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen r0.set(r0.left, r0.top - 1, r0.right, r0.bottom); 163247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen deltaY = -1; 163347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } else if (direction[1] > 0) { 163447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen r0.set(r0.left, r0.top, r0.right, r0.bottom + 1); 163547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen deltaY = 1; 163647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } else if (direction[0] < 0) { 163747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen r0.set(r0.left - 1, r0.top, r0.right, r0.bottom); 163847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen deltaX = -1; 163947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } else if (direction[0] > 0) { 164047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen r0.set(r0.left, r0.top, r0.right + 1, r0.bottom); 164147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen deltaX = 1; 164247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 164347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 164447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen for (int i = 0; i < childCount; i++) { 1645a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka View child = mShortcutsAndWidgets.getChildAt(i); 164619f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (views.contains(child) || child == dragView) continue; 16478baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = currentState.map.get(child); 164847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 16498baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen LayoutParams lp = (LayoutParams) child.getLayoutParams(); 16508baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen r1.set(c.x, c.y, c.x + c.spanX, c.y + c.spanY); 165147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (Rect.intersects(r0, r1)) { 165247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (!lp.canReorder) { 165347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen return false; 165447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 165547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean pushed = false; 16568baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen for (int x = c.x; x < c.x + c.spanX; x++) { 16578baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen for (int y = c.y; y < c.y + c.spanY; y++) { 165847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean inBounds = x - deltaX >= 0 && x -deltaX < mCountX 165947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen && y - deltaY >= 0 && y - deltaY < mCountY; 166047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (inBounds && occupied[x - deltaX][y - deltaY]) { 166147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen pushed = true; 166247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 166347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 166447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 166547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (pushed) { 166647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen views.add(child); 16678baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen boundingRect.union(c.x, c.y, c.x + c.spanX, c.y + c.spanY); 166847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen found = true; 166947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 167047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 167147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 167247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen return found; 167347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 167447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 16758baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen private boolean addViewsToTempLocation(ArrayList<View> views, Rect rectOccupiedByPotentialDrop, 167619f3792523fe2d55ea791a9286398a6120920690Adam Cohen int[] direction, boolean push, View dragView, ItemConfiguration currentState) { 167747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (views.size() == 0) return true; 167847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 167947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean success = false; 168047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen Rect boundingRect = null; 16818baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // We construct a rect which represents the entire group of views passed in 168247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen for (View v: views) { 16838baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = currentState.map.get(v); 168447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (boundingRect == null) { 16858baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen boundingRect = new Rect(c.x, c.y, c.x + c.spanX, c.y + c.spanY); 168647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } else { 16878baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen boundingRect.union(c.x, c.y, c.x + c.spanX, c.y + c.spanY); 168847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 168947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 169047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 16918baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen @SuppressWarnings("unchecked") 169247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen ArrayList<View> dup = (ArrayList<View>) views.clone(); 16938baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // We try and expand the group of views in the direction vector passed, based on 16948baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // whether they are physically adjacent, ie. based on "push mechanics". 169519f3792523fe2d55ea791a9286398a6120920690Adam Cohen while (push && addViewInDirection(dup, boundingRect, direction, mTmpOccupied, dragView, 16968baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen currentState)) { 169747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 16988baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen 16998baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // Mark the occupied state as false for the group of views we want to move. 170047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen for (View v: dup) { 17018baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = currentState.map.get(v); 17028baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, false); 170347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 170447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 170547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean[][] blockOccupied = new boolean[boundingRect.width()][boundingRect.height()]; 170647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen int top = boundingRect.top; 170747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen int left = boundingRect.left; 17088baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // We mark more precisely which parts of the bounding rect are truly occupied, allowing 17098baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // for tetris-style interlocking. 171047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen for (View v: dup) { 17118baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = currentState.map.get(v); 17128baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen markCellsForView(c.x - left, c.y - top, c.spanX, c.spanY, blockOccupied, true); 171347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 171447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 171547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen markCellsForRect(rectOccupiedByPotentialDrop, mTmpOccupied, true); 171647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 17178baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen if (push) { 17188baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen findNearestAreaInDirection(boundingRect.left, boundingRect.top, boundingRect.width(), 17198baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen boundingRect.height(), direction, mTmpOccupied, blockOccupied, mTempLocation); 17208baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen } else { 17218baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen findNearestArea(boundingRect.left, boundingRect.top, boundingRect.width(), 17228baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen boundingRect.height(), direction, mTmpOccupied, blockOccupied, mTempLocation); 17238baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen } 172447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 17258baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // If we successfuly found a location by pushing the block of views, we commit it 172647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (mTempLocation[0] >= 0 && mTempLocation[1] >= 0) { 17278baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen int deltaX = mTempLocation[0] - boundingRect.left; 17288baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen int deltaY = mTempLocation[1] - boundingRect.top; 172947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen for (View v: dup) { 17308baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = currentState.map.get(v); 17318baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen c.x += deltaX; 17328baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen c.y += deltaY; 173347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 173447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen success = true; 173547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 1736482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 17378baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // In either case, we set the occupied array as marked for the location of the views 17388baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen for (View v: dup) { 17398baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = currentState.map.get(v); 17408baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, true); 1741482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1742482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return success; 1743482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1744482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1745482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private void markCellsForRect(Rect r, boolean[][] occupied, boolean value) { 1746482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsForView(r.left, r.top, r.width(), r.height(), occupied, value); 1747482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1748482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1749482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private boolean rearrangementExists(int cellX, int cellY, int spanX, int spanY, int[] direction, 17508baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen View ignoreView, ItemConfiguration solution) { 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(); 2074ea889a294be004f4b1c21e9b874f9e63abfb8bd6Adam Cohen info.cellX = lp.cellX = lp.tmpCellX; 2075ea889a294be004f4b1c21e9b874f9e63abfb8bd6Adam Cohen info.cellY = lp.cellY = lp.tmpCellY; 2076482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2077ea889a294be004f4b1c21e9b874f9e63abfb8bd6Adam Cohen Workspace workspace = (Workspace) getParent(); 2078ea889a294be004f4b1c21e9b874f9e63abfb8bd6Adam Cohen workspace.updateItemLocationsInDatabase(this); 2079482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2080482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2081482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public void setUseTempCoords(boolean useTempCoords) { 2082a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka int childCount = mShortcutsAndWidgets.getChildCount(); 2083482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < childCount; i++) { 2084a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka LayoutParams lp = (LayoutParams) mShortcutsAndWidgets.getChildAt(i).getLayoutParams(); 2085482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen lp.useTmpCoords = useTempCoords; 2086482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2087482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2088482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2089482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen ItemConfiguration findConfigurationNoShuffle(int pixelX, int pixelY, int minSpanX, int minSpanY, 2090482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int spanX, int spanY, View dragView, ItemConfiguration solution) { 2091482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int[] result = new int[2]; 2092482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int[] resultSpan = new int[2]; 2093482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen findNearestVacantArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, null, result, 2094482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen resultSpan); 2095482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (result[0] >= 0 && result[1] >= 0) { 2096482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen copyCurrentStateToSolution(solution, false); 2097482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewX = result[0]; 2098482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewY = result[1]; 2099482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewSpanX = resultSpan[0]; 2100482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewSpanY = resultSpan[1]; 2101482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.isSolution = true; 2102482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } else { 2103482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.isSolution = false; 2104482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2105482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return solution; 2106482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2107482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2108482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public void prepareChildForDrag(View child) { 2109482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsAsUnoccupiedForView(child); 2110482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2111482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 211219f3792523fe2d55ea791a9286398a6120920690Adam Cohen /* This seems like it should be obvious and straight-forward, but when the direction vector 211319f3792523fe2d55ea791a9286398a6120920690Adam Cohen needs to match with the notion of the dragView pushing other views, we have to employ 211419f3792523fe2d55ea791a9286398a6120920690Adam Cohen a slightly more subtle notion of the direction vector. The question is what two points is 211519f3792523fe2d55ea791a9286398a6120920690Adam Cohen the vector between? The center of the dragView and its desired destination? Not quite, as 211619f3792523fe2d55ea791a9286398a6120920690Adam Cohen this doesn't necessarily coincide with the interaction of the dragView and items occupying 211719f3792523fe2d55ea791a9286398a6120920690Adam Cohen those cells. Instead we use some heuristics to often lock the vector to up, down, left 211819f3792523fe2d55ea791a9286398a6120920690Adam Cohen or right, which helps make pushing feel right. 211919f3792523fe2d55ea791a9286398a6120920690Adam Cohen */ 212019f3792523fe2d55ea791a9286398a6120920690Adam Cohen private void getDirectionVectorForDrop(int dragViewCenterX, int dragViewCenterY, int spanX, 212119f3792523fe2d55ea791a9286398a6120920690Adam Cohen int spanY, View dragView, int[] resultDirection) { 212219f3792523fe2d55ea791a9286398a6120920690Adam Cohen int[] targetDestination = new int[2]; 212319f3792523fe2d55ea791a9286398a6120920690Adam Cohen 212419f3792523fe2d55ea791a9286398a6120920690Adam Cohen findNearestArea(dragViewCenterX, dragViewCenterY, spanX, spanY, targetDestination); 212519f3792523fe2d55ea791a9286398a6120920690Adam Cohen Rect dragRect = new Rect(); 212619f3792523fe2d55ea791a9286398a6120920690Adam Cohen regionToRect(targetDestination[0], targetDestination[1], spanX, spanY, dragRect); 212719f3792523fe2d55ea791a9286398a6120920690Adam Cohen dragRect.offset(dragViewCenterX - dragRect.centerX(), dragViewCenterY - dragRect.centerY()); 212819f3792523fe2d55ea791a9286398a6120920690Adam Cohen 212919f3792523fe2d55ea791a9286398a6120920690Adam Cohen Rect dropRegionRect = new Rect(); 213019f3792523fe2d55ea791a9286398a6120920690Adam Cohen getViewsIntersectingRegion(targetDestination[0], targetDestination[1], spanX, spanY, 213119f3792523fe2d55ea791a9286398a6120920690Adam Cohen dragView, dropRegionRect, mIntersectingViews); 213219f3792523fe2d55ea791a9286398a6120920690Adam Cohen 213319f3792523fe2d55ea791a9286398a6120920690Adam Cohen int dropRegionSpanX = dropRegionRect.width(); 213419f3792523fe2d55ea791a9286398a6120920690Adam Cohen int dropRegionSpanY = dropRegionRect.height(); 213519f3792523fe2d55ea791a9286398a6120920690Adam Cohen 213619f3792523fe2d55ea791a9286398a6120920690Adam Cohen regionToRect(dropRegionRect.left, dropRegionRect.top, dropRegionRect.width(), 213719f3792523fe2d55ea791a9286398a6120920690Adam Cohen dropRegionRect.height(), dropRegionRect); 213819f3792523fe2d55ea791a9286398a6120920690Adam Cohen 213919f3792523fe2d55ea791a9286398a6120920690Adam Cohen int deltaX = (dropRegionRect.centerX() - dragViewCenterX) / spanX; 214019f3792523fe2d55ea791a9286398a6120920690Adam Cohen int deltaY = (dropRegionRect.centerY() - dragViewCenterY) / spanY; 214119f3792523fe2d55ea791a9286398a6120920690Adam Cohen 214219f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (dropRegionSpanX == mCountX || spanX == mCountX) { 214319f3792523fe2d55ea791a9286398a6120920690Adam Cohen deltaX = 0; 214419f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 214519f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (dropRegionSpanY == mCountY || spanY == mCountY) { 214619f3792523fe2d55ea791a9286398a6120920690Adam Cohen deltaY = 0; 214719f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 214819f3792523fe2d55ea791a9286398a6120920690Adam Cohen 214919f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (deltaX == 0 && deltaY == 0) { 215019f3792523fe2d55ea791a9286398a6120920690Adam Cohen // No idea what to do, give a random direction. 215119f3792523fe2d55ea791a9286398a6120920690Adam Cohen resultDirection[0] = 1; 215219f3792523fe2d55ea791a9286398a6120920690Adam Cohen resultDirection[1] = 0; 215319f3792523fe2d55ea791a9286398a6120920690Adam Cohen } else { 215419f3792523fe2d55ea791a9286398a6120920690Adam Cohen computeDirectionVector(deltaX, deltaY, resultDirection); 215519f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 215619f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 215719f3792523fe2d55ea791a9286398a6120920690Adam Cohen 215819f3792523fe2d55ea791a9286398a6120920690Adam Cohen // For a given cell and span, fetch the set of views intersecting the region. 215919f3792523fe2d55ea791a9286398a6120920690Adam Cohen private void getViewsIntersectingRegion(int cellX, int cellY, int spanX, int spanY, 216019f3792523fe2d55ea791a9286398a6120920690Adam Cohen View dragView, Rect boundingRect, ArrayList<View> intersectingViews) { 216119f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (boundingRect != null) { 216219f3792523fe2d55ea791a9286398a6120920690Adam Cohen boundingRect.set(cellX, cellY, cellX + spanX, cellY + spanY); 216319f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 216419f3792523fe2d55ea791a9286398a6120920690Adam Cohen intersectingViews.clear(); 216519f3792523fe2d55ea791a9286398a6120920690Adam Cohen Rect r0 = new Rect(cellX, cellY, cellX + spanX, cellY + spanY); 216619f3792523fe2d55ea791a9286398a6120920690Adam Cohen Rect r1 = new Rect(); 216719f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int count = mShortcutsAndWidgets.getChildCount(); 216819f3792523fe2d55ea791a9286398a6120920690Adam Cohen for (int i = 0; i < count; i++) { 216919f3792523fe2d55ea791a9286398a6120920690Adam Cohen View child = mShortcutsAndWidgets.getChildAt(i); 217019f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (child == dragView) continue; 217119f3792523fe2d55ea791a9286398a6120920690Adam Cohen LayoutParams lp = (LayoutParams) child.getLayoutParams(); 217219f3792523fe2d55ea791a9286398a6120920690Adam Cohen r1.set(lp.cellX, lp.cellY, lp.cellX + lp.cellHSpan, lp.cellY + lp.cellVSpan); 217319f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (Rect.intersects(r0, r1)) { 217419f3792523fe2d55ea791a9286398a6120920690Adam Cohen mIntersectingViews.add(child); 217519f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (boundingRect != null) { 217619f3792523fe2d55ea791a9286398a6120920690Adam Cohen boundingRect.union(r1); 217719f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 217819f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 217919f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 218019f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 218119f3792523fe2d55ea791a9286398a6120920690Adam Cohen 218219f3792523fe2d55ea791a9286398a6120920690Adam Cohen boolean isNearestDropLocationOccupied(int pixelX, int pixelY, int spanX, int spanY, 218319f3792523fe2d55ea791a9286398a6120920690Adam Cohen View dragView, int[] result) { 218419f3792523fe2d55ea791a9286398a6120920690Adam Cohen result = findNearestArea(pixelX, pixelY, spanX, spanY, result); 218519f3792523fe2d55ea791a9286398a6120920690Adam Cohen getViewsIntersectingRegion(result[0], result[1], spanX, spanY, dragView, null, 218619f3792523fe2d55ea791a9286398a6120920690Adam Cohen mIntersectingViews); 218719f3792523fe2d55ea791a9286398a6120920690Adam Cohen return !mIntersectingViews.isEmpty(); 218819f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 218919f3792523fe2d55ea791a9286398a6120920690Adam Cohen 219019f3792523fe2d55ea791a9286398a6120920690Adam Cohen void revertTempState() { 219119f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (!isItemPlacementDirty() || DESTRUCTIVE_REORDER) return; 219219f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int count = mShortcutsAndWidgets.getChildCount(); 219319f3792523fe2d55ea791a9286398a6120920690Adam Cohen for (int i = 0; i < count; i++) { 219419f3792523fe2d55ea791a9286398a6120920690Adam Cohen View child = mShortcutsAndWidgets.getChildAt(i); 219519f3792523fe2d55ea791a9286398a6120920690Adam Cohen LayoutParams lp = (LayoutParams) child.getLayoutParams(); 219619f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (lp.tmpCellX != lp.cellX || lp.tmpCellY != lp.cellY) { 219719f3792523fe2d55ea791a9286398a6120920690Adam Cohen lp.tmpCellX = lp.cellX; 219819f3792523fe2d55ea791a9286398a6120920690Adam Cohen lp.tmpCellY = lp.cellY; 219919f3792523fe2d55ea791a9286398a6120920690Adam Cohen animateChildToPosition(child, lp.cellX, lp.cellY, REORDER_ANIMATION_DURATION, 220019f3792523fe2d55ea791a9286398a6120920690Adam Cohen 0, false, false); 220119f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 220219f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 220319f3792523fe2d55ea791a9286398a6120920690Adam Cohen completeAndClearReorderHintAnimations(); 220419f3792523fe2d55ea791a9286398a6120920690Adam Cohen setItemPlacementDirty(false); 220519f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 220619f3792523fe2d55ea791a9286398a6120920690Adam Cohen 2207482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int[] createArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, int spanY, 2208482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen View dragView, int[] result, int resultSpan[], int mode) { 2209482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // First we determine if things have moved enough to cause a different layout 221047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen result = findNearestArea(pixelX, pixelY, spanX, spanY, result); 2211482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2212482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (resultSpan == null) { 2213482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen resultSpan = new int[2]; 2214482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2215482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 221619f3792523fe2d55ea791a9286398a6120920690Adam Cohen // When we are checking drop validity or actually dropping, we don't recompute the 221719f3792523fe2d55ea791a9286398a6120920690Adam Cohen // direction vector, since we want the solution to match the preview, and it's possible 221819f3792523fe2d55ea791a9286398a6120920690Adam Cohen // that the exact position of the item has changed to result in a new reordering outcome. 2219b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen if ((mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL || mode == MODE_ACCEPT_DROP) 2220b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen && mPreviousReorderDirection[0] != INVALID_DIRECTION) { 222119f3792523fe2d55ea791a9286398a6120920690Adam Cohen mDirectionVector[0] = mPreviousReorderDirection[0]; 222219f3792523fe2d55ea791a9286398a6120920690Adam Cohen mDirectionVector[1] = mPreviousReorderDirection[1]; 222319f3792523fe2d55ea791a9286398a6120920690Adam Cohen // We reset this vector after drop 2224b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen if (mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL) { 2225b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen mPreviousReorderDirection[0] = INVALID_DIRECTION; 2226b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen mPreviousReorderDirection[1] = INVALID_DIRECTION; 222719f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 2228b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen 222919f3792523fe2d55ea791a9286398a6120920690Adam Cohen } else { 223019f3792523fe2d55ea791a9286398a6120920690Adam Cohen getDirectionVectorForDrop(pixelX, pixelY, spanX, spanY, dragView, mDirectionVector); 223119f3792523fe2d55ea791a9286398a6120920690Adam Cohen mPreviousReorderDirection[0] = mDirectionVector[0]; 223219f3792523fe2d55ea791a9286398a6120920690Adam Cohen mPreviousReorderDirection[1] = mDirectionVector[1]; 223319f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 223419f3792523fe2d55ea791a9286398a6120920690Adam Cohen 2235482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen ItemConfiguration swapSolution = simpleSwap(pixelX, pixelY, minSpanX, minSpanY, 2236482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen spanX, spanY, mDirectionVector, dragView, true, new ItemConfiguration()); 2237482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2238482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // We attempt the approach which doesn't shuffle views at all 2239482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen ItemConfiguration noShuffleSolution = findConfigurationNoShuffle(pixelX, pixelY, minSpanX, 2240482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen minSpanY, spanX, spanY, dragView, new ItemConfiguration()); 2241482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2242482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen ItemConfiguration finalSolution = null; 2243482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (swapSolution.isSolution && swapSolution.area() >= noShuffleSolution.area()) { 2244482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen finalSolution = swapSolution; 2245482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } else if (noShuffleSolution.isSolution) { 2246482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen finalSolution = noShuffleSolution; 2247482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2248482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2249482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean foundSolution = true; 2250482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (!DESTRUCTIVE_REORDER) { 2251482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen setUseTempCoords(true); 2252482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2253482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2254482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (finalSolution != null) { 2255482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result[0] = finalSolution.dragViewX; 2256482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result[1] = finalSolution.dragViewY; 2257482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen resultSpan[0] = finalSolution.dragViewSpanX; 2258482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen resultSpan[1] = finalSolution.dragViewSpanY; 2259482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2260482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // If we're just testing for a possible location (MODE_ACCEPT_DROP), we don't bother 2261482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // committing anything or animating anything as we just want to determine if a solution 2262482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // exists 2263482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (mode == MODE_DRAG_OVER || mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL) { 2264482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (!DESTRUCTIVE_REORDER) { 2265482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen copySolutionToTempState(finalSolution, dragView); 2266482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2267482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen setItemPlacementDirty(true); 2268482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen animateItemsToSolution(finalSolution, dragView, mode == MODE_ON_DROP); 2269482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 227019f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (!DESTRUCTIVE_REORDER && 227119f3792523fe2d55ea791a9286398a6120920690Adam Cohen (mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL)) { 2272482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen commitTempPlacement(); 227319f3792523fe2d55ea791a9286398a6120920690Adam Cohen completeAndClearReorderHintAnimations(); 227419f3792523fe2d55ea791a9286398a6120920690Adam Cohen setItemPlacementDirty(false); 227519f3792523fe2d55ea791a9286398a6120920690Adam Cohen } else { 227619f3792523fe2d55ea791a9286398a6120920690Adam Cohen beginOrAdjustHintAnimations(finalSolution, dragView, 227719f3792523fe2d55ea791a9286398a6120920690Adam Cohen REORDER_ANIMATION_DURATION); 2278482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2279482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2280482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } else { 2281482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen foundSolution = false; 2282482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result[0] = result[1] = resultSpan[0] = resultSpan[1] = -1; 2283482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2284482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2285482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if ((mode == MODE_ON_DROP || !foundSolution) && !DESTRUCTIVE_REORDER) { 2286482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen setUseTempCoords(false); 2287482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2288482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2289a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.requestLayout(); 2290482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return result; 2291482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2292482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 229319f3792523fe2d55ea791a9286398a6120920690Adam Cohen void setItemPlacementDirty(boolean dirty) { 229419f3792523fe2d55ea791a9286398a6120920690Adam Cohen mItemPlacementDirty = dirty; 2295482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 229619f3792523fe2d55ea791a9286398a6120920690Adam Cohen boolean isItemPlacementDirty() { 229719f3792523fe2d55ea791a9286398a6120920690Adam Cohen return mItemPlacementDirty; 2298482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2299482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2300482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private class ItemConfiguration { 23018baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen HashMap<View, CellAndSpan> map = new HashMap<View, CellAndSpan>(); 2302482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean isSolution = false; 2303482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int dragViewX, dragViewY, dragViewSpanX, dragViewSpanY; 2304482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2305482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int area() { 2306482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return dragViewSpanX * dragViewSpanY; 2307482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 23088baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen } 23098baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen 23108baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen private class CellAndSpan { 23118baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen int x, y; 23128baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen int spanX, spanY; 23138baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen 23148baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen public CellAndSpan(int x, int y, int spanX, int spanY) { 23158baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen this.x = x; 23168baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen this.y = y; 23178baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen this.spanX = spanX; 23188baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen this.spanY = spanY; 2319482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2320482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2321482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2322df0353815c629fc678824b07a234b89a1ff94208Adam Cohen /** 2323df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * Find a vacant area that will fit the given bounds nearest the requested 2324df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * cell location. Uses Euclidean distance to score multiple vacant areas. 2325df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * 2326df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param pixelX The X location at which you want to search for a vacant area. 2327df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param pixelY The Y location at which you want to search for a vacant area. 2328df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param spanX Horizontal span of the object. 2329df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param spanY Vertical span of the object. 2330df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param ignoreView Considers space occupied by this view as unoccupied 2331df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param result Previously returned value to possibly recycle. 2332df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @return The X, Y cell of a vacant area that can contain this object, 2333df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * nearest the requested location. 2334df0353815c629fc678824b07a234b89a1ff94208Adam Cohen */ 2335df0353815c629fc678824b07a234b89a1ff94208Adam Cohen int[] findNearestVacantArea( 2336df0353815c629fc678824b07a234b89a1ff94208Adam Cohen int pixelX, int pixelY, int spanX, int spanY, View ignoreView, int[] result) { 2337df0353815c629fc678824b07a234b89a1ff94208Adam Cohen return findNearestArea(pixelX, pixelY, spanX, spanY, ignoreView, true, result); 2338df0353815c629fc678824b07a234b89a1ff94208Adam Cohen } 2339df0353815c629fc678824b07a234b89a1ff94208Adam Cohen 2340df0353815c629fc678824b07a234b89a1ff94208Adam Cohen /** 2341d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * Find a vacant area that will fit the given bounds nearest the requested 2342d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * cell location. Uses Euclidean distance to score multiple vacant areas. 2343d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * 2344d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param pixelX The X location at which you want to search for a vacant area. 2345d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param pixelY The Y location at which you want to search for a vacant area. 2346d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param minSpanX The minimum horizontal span required 2347d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param minSpanY The minimum vertical span required 2348d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param spanX Horizontal span of the object. 2349d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param spanY Vertical span of the object. 2350d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param ignoreView Considers space occupied by this view as unoccupied 2351d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param result Previously returned value to possibly recycle. 2352d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @return The X, Y cell of a vacant area that can contain this object, 2353d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * nearest the requested location. 2354d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen */ 2355d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int[] findNearestVacantArea(int pixelX, int pixelY, int minSpanX, int minSpanY, 2356d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int spanX, int spanY, View ignoreView, int[] result, int[] resultSpan) { 2357482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return findNearestArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, ignoreView, true, 2358482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result, resultSpan, mOccupied); 2359d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 2360d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen 2361d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen /** 2362df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * Find a starting cell position that will fit the given bounds nearest the requested 2363df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * cell location. Uses Euclidean distance to score multiple vacant areas. 2364df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * 2365df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param pixelX The X location at which you want to search for a vacant area. 2366df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param pixelY The Y location at which you want to search for a vacant area. 2367df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param spanX Horizontal span of the object. 2368df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param spanY Vertical span of the object. 2369df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param ignoreView Considers space occupied by this view as unoccupied 2370df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param result Previously returned value to possibly recycle. 2371df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @return The X, Y cell of a vacant area that can contain this object, 2372df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * nearest the requested location. 2373df0353815c629fc678824b07a234b89a1ff94208Adam Cohen */ 2374df0353815c629fc678824b07a234b89a1ff94208Adam Cohen int[] findNearestArea( 2375df0353815c629fc678824b07a234b89a1ff94208Adam Cohen int pixelX, int pixelY, int spanX, int spanY, int[] result) { 2376df0353815c629fc678824b07a234b89a1ff94208Adam Cohen return findNearestArea(pixelX, pixelY, spanX, spanY, null, false, result); 2377df0353815c629fc678824b07a234b89a1ff94208Adam Cohen } 2378df0353815c629fc678824b07a234b89a1ff94208Adam Cohen 23790280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka boolean existsEmptyCell() { 23800280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka return findCellForSpan(null, 1, 1); 23810280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 23820280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 23830280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka /** 23840280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * Finds the upper-left coordinate of the first rectangle in the grid that can 23850280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * hold a cell of the specified dimensions. If intersectX and intersectY are not -1, 23860280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * then this method will only return coordinates for rectangles that contain the cell 23870280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * (intersectX, intersectY) 23880280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * 23890280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param cellXY The array that will contain the position of a vacant cell if such a cell 23900280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * can be found. 23910280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param spanX The horizontal span of the cell we want to find. 23920280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param spanY The vertical span of the cell we want to find. 23930280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * 23940280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @return True if a vacant cell of the specified dimension was found, false otherwise. 23950280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka */ 23960280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka boolean findCellForSpan(int[] cellXY, int spanX, int spanY) { 2397482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return findCellForSpanThatIntersectsIgnoring(cellXY, spanX, spanY, -1, -1, null, mOccupied); 23980280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 23990280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 24000280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka /** 24010280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * Like above, but ignores any cells occupied by the item "ignoreView" 24020280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * 24030280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param cellXY The array that will contain the position of a vacant cell if such a cell 24040280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * can be found. 24050280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param spanX The horizontal span of the cell we want to find. 24060280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param spanY The vertical span of the cell we want to find. 24070280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param ignoreView The home screen item we should treat as not occupying any space 24080280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @return 24090280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka */ 24100280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka boolean findCellForSpanIgnoring(int[] cellXY, int spanX, int spanY, View ignoreView) { 2411482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return findCellForSpanThatIntersectsIgnoring(cellXY, spanX, spanY, -1, -1, 2412482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen ignoreView, mOccupied); 24130280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 24140280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 24150280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka /** 24160280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * Like above, but if intersectX and intersectY are not -1, then this method will try to 24170280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * return coordinates for rectangles that contain the cell [intersectX, intersectY] 24180280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * 24190280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param spanX The horizontal span of the cell we want to find. 24200280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param spanY The vertical span of the cell we want to find. 24210280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param ignoreView The home screen item we should treat as not occupying any space 24220280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param intersectX The X coordinate of the cell that we should try to overlap 24230280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param intersectX The Y coordinate of the cell that we should try to overlap 24240280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * 24250280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @return True if a vacant cell of the specified dimension was found, false otherwise. 24260280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka */ 24270280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka boolean findCellForSpanThatIntersects(int[] cellXY, int spanX, int spanY, 24280280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka int intersectX, int intersectY) { 24290280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka return findCellForSpanThatIntersectsIgnoring( 2430482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen cellXY, spanX, spanY, intersectX, intersectY, null, mOccupied); 24310280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 24320280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 24330280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka /** 24340280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * The superset of the above two methods 24350280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka */ 24360280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka boolean findCellForSpanThatIntersectsIgnoring(int[] cellXY, int spanX, int spanY, 2437482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int intersectX, int intersectY, View ignoreView, boolean occupied[][]) { 2438c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka // mark space take by ignoreView as available (method checks if ignoreView is null) 2439482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsAsUnoccupiedForView(ignoreView, occupied); 24400280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 244128750fba6a2d141eb9a1e566718c17236030b815Michael Jurka boolean foundCell = false; 24420280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka while (true) { 24430280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka int startX = 0; 24440280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka if (intersectX >= 0) { 24450280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka startX = Math.max(startX, intersectX - (spanX - 1)); 24460280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 24470280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka int endX = mCountX - (spanX - 1); 24480280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka if (intersectX >= 0) { 24490280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka endX = Math.min(endX, intersectX + (spanX - 1) + (spanX == 1 ? 1 : 0)); 24500280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 24510280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka int startY = 0; 24520280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka if (intersectY >= 0) { 24530280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka startY = Math.max(startY, intersectY - (spanY - 1)); 24540280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 24550280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka int endY = mCountY - (spanY - 1); 24560280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka if (intersectY >= 0) { 24570280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka endY = Math.min(endY, intersectY + (spanY - 1) + (spanY == 1 ? 1 : 0)); 24580280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 24590280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 2460bbc60d8e79416e37cbede55c159bf6aaa6c171d5Winson Chung for (int y = startY; y < endY && !foundCell; y++) { 24610280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka inner: 2462bbc60d8e79416e37cbede55c159bf6aaa6c171d5Winson Chung for (int x = startX; x < endX; x++) { 24630280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka for (int i = 0; i < spanX; i++) { 24640280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka for (int j = 0; j < spanY; j++) { 2465482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (occupied[x + i][y + j]) { 2466bbc60d8e79416e37cbede55c159bf6aaa6c171d5Winson Chung // small optimization: we can skip to after the column we just found 24670280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // an occupied cell 2468bbc60d8e79416e37cbede55c159bf6aaa6c171d5Winson Chung x += i; 24690280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka continue inner; 24700280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 24710280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 24720280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 24730280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka if (cellXY != null) { 24740280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka cellXY[0] = x; 24750280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka cellXY[1] = y; 24760280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 247728750fba6a2d141eb9a1e566718c17236030b815Michael Jurka foundCell = true; 247828750fba6a2d141eb9a1e566718c17236030b815Michael Jurka break; 24790280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 24800280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 24810280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka if (intersectX == -1 && intersectY == -1) { 24820280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka break; 24830280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } else { 24840280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // if we failed to find anything, try again but without any requirements of 24850280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // intersecting 24860280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka intersectX = -1; 24870280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka intersectY = -1; 24880280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka continue; 24890280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 24900280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 24910280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 2492c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka // re-mark space taken by ignoreView as occupied 2493482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsAsOccupiedForView(ignoreView, occupied); 249428750fba6a2d141eb9a1e566718c17236030b815Michael Jurka return foundCell; 24950280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 24960280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 249731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 2498c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung * A drag event has begun over this layout. 2499c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung * It may have begun over this layout (in which case onDragChild is called first), 2500c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung * or it may have begun on another layout. 2501c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung */ 2502c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung void onDragEnter() { 2503c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung if (!mDragging) { 2504c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung // Fade in the drag indicators 2505c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung if (mCrosshairsAnimator != null) { 2506c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung mCrosshairsAnimator.animateIn(); 2507c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung } 2508c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung } 2509c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung mDragging = true; 2510c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung } 2511c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung 2512c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung /** 25130280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * Called when drag has left this CellLayout or has been completed (successfully or not) 25146569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy */ 25150280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka void onDragExit() { 25164be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // This can actually be called when we aren't in a drag, e.g. when adding a new 25174be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // item to this layout via the customize drawer. 25184be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // Guard against that case. 25194be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato if (mDragging) { 25204be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato mDragging = false; 25216569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 25224be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // Fade out the drag indicators 25234be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato if (mCrosshairsAnimator != null) { 25244be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato mCrosshairsAnimator.animateOut(); 25254be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato } 25264be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato } 252708ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy 252808ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy // Invalidate the drag data 2529d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen mDragCell[0] = mDragCell[1] = -1; 253008ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy mDragOutlineAnims[mDragOutlineCurrent].animateOut(); 253108ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy mDragOutlineCurrent = (mDragOutlineCurrent + 1) % mDragOutlineAnims.length; 253219f3792523fe2d55ea791a9286398a6120920690Adam Cohen revertTempState(); 253333945b21544bc98381df17726a3537c292d8c985Michael Jurka setIsDragOverlapping(false); 25346569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy } 25356569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 25366569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy /** 2537aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * Mark a child as having been dropped. 2538de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy * At the beginning of the drag operation, the child may have been on another 2539ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy * screen, but it is re-parented before this method is called. 254031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 254131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param child The child that is being dropped 254231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 2543716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen void onDropChild(View child) { 2544d94533d04a5f8f5485f106d10af60169857ea899Romain Guy if (child != null) { 2545d94533d04a5f8f5485f106d10af60169857ea899Romain Guy LayoutParams lp = (LayoutParams) child.getLayoutParams(); 254684f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy lp.dropped = true; 2547d94533d04a5f8f5485f106d10af60169857ea899Romain Guy child.requestLayout(); 2548d94533d04a5f8f5485f106d10af60169857ea899Romain Guy } 254931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 255031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 255131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 255231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Computes a bounding rectangle for a range of cells 2553aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * 255431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param cellX X coordinate of upper left corner expressed as a cell position 255531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param cellY Y coordinate of upper left corner expressed as a cell position 2556aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * @param cellHSpan Width in cells 255731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param cellVSpan Height in cells 25586569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy * @param resultRect Rect into which to put the results 255931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 2560d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen public void cellToRect(int cellX, int cellY, int cellHSpan, int cellVSpan, Rect resultRect) { 256131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int cellWidth = mCellWidth; 256231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int cellHeight = mCellHeight; 256331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int widthGap = mWidthGap; 256431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int heightGap = mHeightGap; 2565aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 25664b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung final int hStartPadding = getPaddingLeft(); 25674b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung final int vStartPadding = getPaddingTop(); 2568aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 256931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int width = cellHSpan * cellWidth + ((cellHSpan - 1) * widthGap); 257031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int height = cellVSpan * cellHeight + ((cellVSpan - 1) * heightGap); 257131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 257231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int x = hStartPadding + cellX * (cellWidth + widthGap); 257331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int y = vStartPadding + cellY * (cellHeight + heightGap); 2574aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 25756569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy resultRect.set(x, y, x + width, y + height); 257631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 2577aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 257831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 2579aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * Computes the required horizontal and vertical cell spans to always 258031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * fit the given rectangle. 2581aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * 258231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param width Width in pixels 258331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param height Height in pixels 25848f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy * @param result An array of length 2 in which to store the result (may be null). 258531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 25868f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy public int[] rectToCell(int width, int height, int[] result) { 25879987a5c45e7d01a780d73b269bdce8d8a5309219Michael Jurka return rectToCell(getResources(), width, height, result); 25889987a5c45e7d01a780d73b269bdce8d8a5309219Michael Jurka } 25899987a5c45e7d01a780d73b269bdce8d8a5309219Michael Jurka 25909987a5c45e7d01a780d73b269bdce8d8a5309219Michael Jurka public static int[] rectToCell(Resources resources, int width, int height, int[] result) { 259131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // Always assume we're working with the smallest span to make sure we 259231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // reserve enough space in both orientations. 259379e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato int actualWidth = resources.getDimensionPixelSize(R.dimen.workspace_cell_width); 259479e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato int actualHeight = resources.getDimensionPixelSize(R.dimen.workspace_cell_height); 259531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int smallerSize = Math.min(actualWidth, actualHeight); 259679e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato 259731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // Always round up to next largest cell 259854c725cc294cd43ed0650179bfae64a622547660Winson Chung int spanX = (int) Math.ceil(width / (float) smallerSize); 259954c725cc294cd43ed0650179bfae64a622547660Winson Chung int spanY = (int) Math.ceil(height / (float) smallerSize); 260079e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato 26018f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy if (result == null) { 26028f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy return new int[] { spanX, spanY }; 26038f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy } 26048f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy result[0] = spanX; 26058f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy result[1] = spanY; 26068f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy return result; 260731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 260831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 2609f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka public int[] cellSpansToSize(int hSpans, int vSpans) { 2610f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka int[] size = new int[2]; 2611f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka size[0] = hSpans * mCellWidth + (hSpans - 1) * mWidthGap; 2612f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka size[1] = vSpans * mCellHeight + (vSpans - 1) * mHeightGap; 2613f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka return size; 2614f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka } 2615f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka 261631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 2617047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy * Calculate the grid spans needed to fit given item 2618047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy */ 2619047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy public void calculateSpans(ItemInfo info) { 2620047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy final int minWidth; 2621047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy final int minHeight; 2622047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy 2623047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy if (info instanceof LauncherAppWidgetInfo) { 2624047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy minWidth = ((LauncherAppWidgetInfo) info).minWidth; 2625047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy minHeight = ((LauncherAppWidgetInfo) info).minHeight; 2626047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy } else if (info instanceof PendingAddWidgetInfo) { 2627047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy minWidth = ((PendingAddWidgetInfo) info).minWidth; 2628047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy minHeight = ((PendingAddWidgetInfo) info).minHeight; 2629047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy } else { 2630047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy // It's not a widget, so it must be 1x1 2631047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy info.spanX = info.spanY = 1; 2632047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy return; 2633047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy } 2634047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy int[] spans = rectToCell(minWidth, minHeight, null); 2635047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy info.spanX = spans[0]; 2636047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy info.spanY = spans[1]; 2637047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy } 2638047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy 2639047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy /** 264031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Find the first vacant cell, if there is one. 264131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 264231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param vacant Holds the x and y coordinate of the vacant cell 264331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param spanX Horizontal cell span. 264431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param spanY Vertical cell span. 2645aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * 264631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @return True if a vacant cell was found 264731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 264831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public boolean getVacantCell(int[] vacant, int spanX, int spanY) { 264931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 26500280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka return findVacantCell(vacant, spanX, spanY, mCountX, mCountY, mOccupied); 265131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 265231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 265331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project static boolean findVacantCell(int[] vacant, int spanX, int spanY, 265431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int xCount, int yCount, boolean[][] occupied) { 265531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 26562801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen for (int y = 0; y < yCount; y++) { 26572801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen for (int x = 0; x < xCount; x++) { 265831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project boolean available = !occupied[x][y]; 265931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectout: for (int i = x; i < x + spanX - 1 && x < xCount; i++) { 266031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int j = y; j < y + spanY - 1 && y < yCount; j++) { 266131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project available = available && !occupied[i][j]; 266231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (!available) break out; 266331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 266431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 266531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 266631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (available) { 266731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project vacant[0] = x; 266831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project vacant[1] = y; 266931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return true; 267031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 267131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 267231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 267331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 267431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return false; 267531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 267631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 26770280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka private void clearOccupiedCells() { 26780280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka for (int x = 0; x < mCountX; x++) { 26790280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka for (int y = 0; y < mCountY; y++) { 26800280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka mOccupied[x][y] = false; 268131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 268231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 26830280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 268431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 26851b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen /** 26861b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen * Given a view, determines how much that view can be expanded in all directions, in terms of 26871b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen * whether or not there are other items occupying adjacent cells. Used by the 26881b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen * AppWidgetResizeFrame to determine how the widget can be resized. 26891b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen */ 2690d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen public void getExpandabilityArrayForView(View view, int[] expandability) { 26911b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen final LayoutParams lp = (LayoutParams) view.getLayoutParams(); 2692d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen boolean flag; 2693d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen 26941b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen expandability[AppWidgetResizeFrame.LEFT] = 0; 2695d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen for (int x = lp.cellX - 1; x >= 0; x--) { 2696d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen flag = false; 2697d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen for (int y = lp.cellY; y < lp.cellY + lp.cellVSpan; y++) { 2698d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen if (mOccupied[x][y]) flag = true; 2699d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen } 2700d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen if (flag) break; 27011b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen expandability[AppWidgetResizeFrame.LEFT]++; 2702d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen } 2703d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen 27041b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen expandability[AppWidgetResizeFrame.TOP] = 0; 2705d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen for (int y = lp.cellY - 1; y >= 0; y--) { 2706d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen flag = false; 2707d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen for (int x = lp.cellX; x < lp.cellX + lp.cellHSpan; x++) { 2708d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen if (mOccupied[x][y]) flag = true; 2709d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen } 2710d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen if (flag) break; 27111b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen expandability[AppWidgetResizeFrame.TOP]++; 27121b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen } 2713d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen 27141b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen expandability[AppWidgetResizeFrame.RIGHT] = 0; 2715d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen for (int x = lp.cellX + lp.cellHSpan; x < mCountX; x++) { 2716d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen flag = false; 2717d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen for (int y = lp.cellY; y < lp.cellY + lp.cellVSpan; y++) { 2718d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen if (mOccupied[x][y]) flag = true; 2719d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen } 2720d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen if (flag) break; 27211b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen expandability[AppWidgetResizeFrame.RIGHT]++; 27221b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen } 2723d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen 27241b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen expandability[AppWidgetResizeFrame.BOTTOM] = 0; 2725d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen for (int y = lp.cellY + lp.cellVSpan; y < mCountY; y++) { 2726d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen flag = false; 2727d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen for (int x = lp.cellX; x < lp.cellX + lp.cellHSpan; x++) { 2728d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen if (mOccupied[x][y]) flag = true; 2729d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen } 2730d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen if (flag) break; 27311b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen expandability[AppWidgetResizeFrame.BOTTOM]++; 27321b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen } 2733d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen } 2734d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen 2735d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen public void onMove(View view, int newCellX, int newCellY, int newSpanX, int newSpanY) { 27360280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka markCellsAsUnoccupiedForView(view); 2737482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsForView(newCellX, newCellY, newSpanX, newSpanY, mOccupied, true); 27380280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 273931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 2740d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen public void markCellsAsOccupiedForView(View view) { 2741482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsAsOccupiedForView(view, mOccupied); 2742482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2743482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public void markCellsAsOccupiedForView(View view, boolean[][] occupied) { 2744a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka if (view == null || view.getParent() != mShortcutsAndWidgets) return; 27450280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka LayoutParams lp = (LayoutParams) view.getLayoutParams(); 2746482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, occupied, true); 27470280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 27480280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 2749d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen public void markCellsAsUnoccupiedForView(View view) { 2750482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsAsUnoccupiedForView(view, mOccupied); 2751482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2752482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public void markCellsAsUnoccupiedForView(View view, boolean occupied[][]) { 2753a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka if (view == null || view.getParent() != mShortcutsAndWidgets) return; 27540280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka LayoutParams lp = (LayoutParams) view.getLayoutParams(); 2755482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, occupied, false); 27560280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 27570280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 2758482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private void markCellsForView(int cellX, int cellY, int spanX, int spanY, boolean[][] occupied, 2759482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean value) { 2760482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (cellX < 0 || cellY < 0) return; 27610280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka for (int x = cellX; x < cellX + spanX && x < mCountX; x++) { 27620280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka for (int y = cellY; y < cellY + spanY && y < mCountY; y++) { 2763482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen occupied[x][y] = value; 276431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 276531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 276631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 276731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 27682801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen public int getDesiredWidth() { 27694b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung return mPaddingLeft + mPaddingRight + (mCountX * mCellWidth) + 27702801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen (Math.max((mCountX - 1), 0) * mWidthGap); 27712801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen } 27722801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen 27732801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen public int getDesiredHeight() { 27744b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung return mPaddingTop + mPaddingBottom + (mCountY * mCellHeight) + 27752801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen (Math.max((mCountY - 1), 0) * mHeightGap); 27762801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen } 27772801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen 277866d72178af91d455700875635473be942bc90e54Michael Jurka public boolean isOccupied(int x, int y) { 277966d72178af91d455700875635473be942bc90e54Michael Jurka if (x < mCountX && y < mCountY) { 278066d72178af91d455700875635473be942bc90e54Michael Jurka return mOccupied[x][y]; 278166d72178af91d455700875635473be942bc90e54Michael Jurka } else { 278266d72178af91d455700875635473be942bc90e54Michael Jurka throw new RuntimeException("Position exceeds the bound of this CellLayout"); 278366d72178af91d455700875635473be942bc90e54Michael Jurka } 278466d72178af91d455700875635473be942bc90e54Michael Jurka } 278566d72178af91d455700875635473be942bc90e54Michael Jurka 278631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 278731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) { 278831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return new CellLayout.LayoutParams(getContext(), attrs); 278931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 279031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 279131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 279231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { 279331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return p instanceof CellLayout.LayoutParams; 279431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 279531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 279631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 279731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { 279831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return new CellLayout.LayoutParams(p); 279931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 280031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 2801aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung public static class CellLayoutAnimationController extends LayoutAnimationController { 2802aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung public CellLayoutAnimationController(Animation animation, float delay) { 2803aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung super(animation, delay); 2804aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung } 2805aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 2806aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung @Override 2807aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung protected long getDelayForView(View view) { 2808aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung return (int) (Math.random() * 150); 2809aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung } 2810aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung } 2811aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 281231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public static class LayoutParams extends ViewGroup.MarginLayoutParams { 281331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 281431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Horizontal location of the item in the grid. 281531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 281631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @ViewDebug.ExportedProperty 281731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public int cellX; 281831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 281931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 282031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Vertical location of the item in the grid. 282131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 282231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @ViewDebug.ExportedProperty 282331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public int cellY; 282431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 282531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 2826482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * Temporary horizontal location of the item in the grid during reorder 2827482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen */ 2828482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public int tmpCellX; 2829482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2830482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen /** 2831482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * Temporary vertical location of the item in the grid during reorder 2832482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen */ 2833482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public int tmpCellY; 2834482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2835482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen /** 2836482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * Indicates that the temporary coordinates should be used to layout the items 2837482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen */ 2838482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public boolean useTmpCoords; 2839482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2840482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen /** 284131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Number of cells spanned horizontally by the item. 284231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 284331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @ViewDebug.ExportedProperty 284431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public int cellHSpan; 284531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 284631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 284731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Number of cells spanned vertically by the item. 284831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 284931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @ViewDebug.ExportedProperty 285031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public int cellVSpan; 2851aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 28521b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen /** 28531b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen * Indicates whether the item will set its x, y, width and height parameters freely, 28541b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen * or whether these will be computed based on cellX, cellY, cellHSpan and cellVSpan. 28551b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen */ 2856d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen public boolean isLockedToGrid = true; 2857d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen 2858482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen /** 2859482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * Indicates whether this item can be reordered. Always true except in the case of the 2860482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * the AllApps button. 2861482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen */ 2862482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public boolean canReorder = true; 2863482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 286431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // X coordinate of the view in the layout. 286531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @ViewDebug.ExportedProperty 286631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int x; 286731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // Y coordinate of the view in the layout. 286831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @ViewDebug.ExportedProperty 286931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int y; 287031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 287184f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy boolean dropped; 2872fcb9e7144e58614f5ae0e9b272fb7ce040848c67Romain Guy 287331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public LayoutParams(Context c, AttributeSet attrs) { 287431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project super(c, attrs); 287531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellHSpan = 1; 287631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellVSpan = 1; 287731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 287831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 287931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public LayoutParams(ViewGroup.LayoutParams source) { 288031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project super(source); 288131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellHSpan = 1; 288231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellVSpan = 1; 288331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 2884aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 2885aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung public LayoutParams(LayoutParams source) { 2886aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung super(source); 2887aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung this.cellX = source.cellX; 2888aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung this.cellY = source.cellY; 2889aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung this.cellHSpan = source.cellHSpan; 2890aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung this.cellVSpan = source.cellVSpan; 2891aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung } 2892aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 289331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public LayoutParams(int cellX, int cellY, int cellHSpan, int cellVSpan) { 28948f19cdd62f6e2be05e3890916eabd11317ae1bc2Romain Guy super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); 289531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this.cellX = cellX; 289631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this.cellY = cellY; 289731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this.cellHSpan = cellHSpan; 289831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this.cellVSpan = cellVSpan; 289931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 290031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 29017f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public void setup(int cellWidth, int cellHeight, int widthGap, int heightGap) { 2902d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen if (isLockedToGrid) { 2903d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen final int myCellHSpan = cellHSpan; 2904d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen final int myCellVSpan = cellVSpan; 2905482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int myCellX = useTmpCoords ? tmpCellX : cellX; 2906482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int myCellY = useTmpCoords ? tmpCellY : cellY; 29071b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen 2908d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen width = myCellHSpan * cellWidth + ((myCellHSpan - 1) * widthGap) - 2909d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen leftMargin - rightMargin; 2910d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen height = myCellVSpan * cellHeight + ((myCellVSpan - 1) * heightGap) - 2911d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen topMargin - bottomMargin; 2912eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung x = (int) (myCellX * (cellWidth + widthGap) + leftMargin); 2913eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung y = (int) (myCellY * (cellHeight + heightGap) + topMargin); 2914d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen } 2915d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen } 2916d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen 2917aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung public String toString() { 2918aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung return "(" + this.cellX + ", " + this.cellY + ")"; 2919aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung } 29207f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 29217f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public void setWidth(int width) { 29227f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen this.width = width; 29237f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 29247f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 29257f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public int getWidth() { 29267f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen return width; 29277f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 29287f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 29297f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public void setHeight(int height) { 29307f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen this.height = height; 29317f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 29327f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 29337f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public int getHeight() { 29347f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen return height; 29357f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 29367f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 29377f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public void setX(int x) { 29387f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen this.x = x; 29397f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 29407f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 29417f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public int getX() { 29427f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen return x; 29437f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 29447f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 29457f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public void setY(int y) { 29467f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen this.y = y; 29477f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 29487f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 29497f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public int getY() { 29507f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen return y; 29517f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 295231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 295331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 29540280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // This class stores info for two purposes: 29550280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // 1. When dragging items (mDragInfo in Workspace), we store the View, its cellX & cellY, 29560280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // its spanX, spanY, and the screen it is on 29570280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // 2. When long clicking on an empty cell in a CellLayout, we save information about the 29580280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // cellX and cellY coordinates and which page was clicked. We then set this as a tag on 29590280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // the CellLayout that was long clicked 2960e5fb0f27bca7afb996258a7163c76ca7390d7bffMichael Jurka static final class CellInfo { 296131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project View cell; 2962a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka int cellX = -1; 2963a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka int cellY = -1; 296431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int spanX; 296531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int spanY; 296631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int screen; 29673d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung long container; 296831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 296931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 297031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public String toString() { 2971aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung return "Cell[view=" + (cell == null ? "null" : cell.getClass()) 2972aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung + ", x=" + cellX + ", y=" + cellY + "]"; 297331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 297431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 2975d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka 2976d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka public boolean lastDownOnOccupiedCell() { 2977d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka return mLastDownOnOccupiedCell; 2978d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka } 297931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project} 2980