CellLayout.java revision bebf042666cffe52039b875a549a582abd78a431
131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project/* 231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project 331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * you may not use this file except in compliance with the License. 631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * You may obtain a copy of the License at 731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 1031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 1131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 1231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * See the License for the specific language governing permissions and 1431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * limitations under the License. 1531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 1631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 17a5902524d4403885eb4c50360bf3465c6be796efJoe Onoratopackage com.android.launcher2; 1831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 194be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onoratoimport android.animation.Animator; 204be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onoratoimport android.animation.AnimatorListenerAdapter; 2100397b1d9233409d9d6b233b077ae12d09768ce8Chet Haaseimport android.animation.TimeInterpolator; 22de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroyimport android.animation.ValueAnimator; 23de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroyimport android.animation.ValueAnimator.AnimatorUpdateListener; 2431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.content.Context; 2579e56263dbcbe85dc434df372bc6e6730aa13477Joe Onoratoimport android.content.res.Resources; 26aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chungimport android.content.res.TypedArray; 274be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onoratoimport android.graphics.Bitmap; 28aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chungimport android.graphics.Canvas; 290dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynnimport android.graphics.Color; 304be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onoratoimport android.graphics.Paint; 31de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroyimport android.graphics.Point; 32de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroyimport android.graphics.PointF; 33b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohenimport android.graphics.PorterDuff; 34b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohenimport android.graphics.PorterDuffXfermode; 3531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.graphics.Rect; 36482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohenimport android.graphics.drawable.ColorDrawable; 376569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroyimport android.graphics.drawable.Drawable; 38b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohenimport android.graphics.drawable.NinePatchDrawable; 3931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.util.AttributeSet; 404be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onoratoimport android.util.Log; 4131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.MotionEvent; 4231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.View; 4331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.ViewDebug; 4431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.ViewGroup; 45aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chungimport android.view.animation.Animation; 46150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chungimport android.view.animation.DecelerateInterpolator; 47aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chungimport android.view.animation.LayoutAnimationController; 4831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 496639687cd67bab1aeef2a75e5c6bc458b20dc082Adam Cohenimport com.android.launcher.R; 5069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohenimport com.android.launcher2.FolderIcon.FolderRingAnimator; 518e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy 5269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohenimport java.util.ArrayList; 53c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohenimport java.util.Arrays; 54bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohenimport java.util.HashMap; 55d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohenimport java.util.Stack; 56c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen 57bdb5c5342adc550559fd723af461e53248f2fba8Michael Jurkapublic class CellLayout extends ViewGroup { 58aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung static final String TAG = "CellLayout"; 59aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 602acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen private Launcher mLauncher; 614b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung private int mOriginalCellWidth; 624b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung private int mOriginalCellHeight; 6331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private int mCellWidth; 6431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private int mCellHeight; 65aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 66d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen private int mCountX; 67d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen private int mCountY; 6831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 69234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen private int mOriginalWidthGap; 70234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen private int mOriginalHeightGap; 7131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private int mWidthGap; 7231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private int mHeightGap; 734b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung private int mMaxGap; 74ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen private boolean mScrollingTransformsDirty = false; 7531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 7631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private final Rect mRect = new Rect(); 7731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private final CellInfo mCellInfo = new CellInfo(); 78aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 79de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy // These are temporary variables to prevent having to allocate a new object just to 80de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy // return an (x, y) value from helper functions. Do NOT use them to maintain other state. 810be025d64c1f84138fe430a58875886e66aae767Winson Chung private final int[] mTmpXY = new int[2]; 82de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy private final int[] mTmpPoint = new int[2]; 83de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy private final PointF mTmpPointF = new PointF(); 8469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen int[] mTempLocation = new int[2]; 856569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 8631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project boolean[][] mOccupied; 87482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean[][] mTmpOccupied; 88d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka private boolean mLastDownOnOccupiedCell = false; 8931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 90dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka private OnTouchListener mInterceptTouchListener; 91dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka 9269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen private ArrayList<FolderRingAnimator> mFolderOuterRings = new ArrayList<FolderRingAnimator>(); 93c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen private int[] mFolderLeaveBehindCell = {-1, -1}; 9469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 95b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen private int mForegroundAlpha = 0; 965f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka private float mBackgroundAlpha; 971b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen private float mBackgroundAlphaMultiplier = 1.0f; 98f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen 9933945b21544bc98381df17726a3537c292d8c985Michael Jurka private Drawable mNormalBackground; 10033945b21544bc98381df17726a3537c292d8c985Michael Jurka private Drawable mActiveGlowBackground; 101b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen private Drawable mOverScrollForegroundDrawable; 102b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen private Drawable mOverScrollLeft; 103b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen private Drawable mOverScrollRight; 10418014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka private Rect mBackgroundRect; 105b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen private Rect mForegroundRect; 106b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen private int mForegroundPadding; 10733945b21544bc98381df17726a3537c292d8c985Michael Jurka 10833945b21544bc98381df17726a3537c292d8c985Michael Jurka // If we're actively dragging something over this screen, mIsDragOverlapping is true 10933945b21544bc98381df17726a3537c292d8c985Michael Jurka private boolean mIsDragOverlapping = false; 110de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy private final Point mDragCenter = new Point(); 1116569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 112150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung // These arrays are used to implement the drag visualization on x-large screens. 1134be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // They are used as circular arrays, indexed by mDragOutlineCurrent. 114d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen private Rect[] mDragOutlines = new Rect[4]; 115472b281d5cb4f5660df981a6c912266b9f5703feChet Haase private float[] mDragOutlineAlphas = new float[mDragOutlines.length]; 1164be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato private InterruptibleInOutAnimator[] mDragOutlineAnims = 1174be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato new InterruptibleInOutAnimator[mDragOutlines.length]; 118150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung 119150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung // Used as an index into the above 3 arrays; indicates which is the most current value. 1204be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato private int mDragOutlineCurrent = 0; 1218e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy private final Paint mDragOutlinePaint = new Paint(); 122150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung 12396864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy private BubbleTextView mPressedOrFocusedIcon; 12496864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy 125de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy private Drawable mCrosshairsDrawable = null; 12649250ad530385fcdd6072ca54697f670ec503b59Patrick Dubroy private InterruptibleInOutAnimator mCrosshairsAnimator = null; 127de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy private float mCrosshairsVisibility = 0.0f; 128de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy 129482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private HashMap<CellLayout.LayoutParams, Animator> mReorderAnimators = new 130482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen HashMap<CellLayout.LayoutParams, Animator>(); 13119f3792523fe2d55ea791a9286398a6120920690Adam Cohen private HashMap<View, ReorderHintAnimation> 13219f3792523fe2d55ea791a9286398a6120920690Adam Cohen mShakeAnimators = new HashMap<View, ReorderHintAnimation>(); 13319f3792523fe2d55ea791a9286398a6120920690Adam Cohen 13419f3792523fe2d55ea791a9286398a6120920690Adam Cohen private boolean mItemPlacementDirty = false; 135bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen 1366569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy // When a drag operation is in progress, holds the nearest cell to the touch point 1376569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy private final int[] mDragCell = new int[2]; 13831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 1394be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato private boolean mDragging = false; 1404be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato 141ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy private TimeInterpolator mEaseOutInterpolator; 142a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka private ShortcutAndWidgetContainer mShortcutsAndWidgets; 143ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy 1440dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn private boolean mIsHotseat = false; 145eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung private float mChildScale = 1f; 146eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung private float mHotseatChildScale = 1f; 1470dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn 148482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public static final int MODE_DRAG_OVER = 0; 149482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public static final int MODE_ON_DROP = 1; 150482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public static final int MODE_ON_DROP_EXTERNAL = 2; 151482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public static final int MODE_ACCEPT_DROP = 3; 15219f3792523fe2d55ea791a9286398a6120920690Adam Cohen private static final boolean DESTRUCTIVE_REORDER = false; 153482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private static final boolean DEBUG_VISUALIZE_OCCUPIED = false; 154482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 15519f3792523fe2d55ea791a9286398a6120920690Adam Cohen private static final float REORDER_HINT_MAGNITUDE = 0.27f; 15619f3792523fe2d55ea791a9286398a6120920690Adam Cohen private static final int REORDER_ANIMATION_DURATION = 150; 15719f3792523fe2d55ea791a9286398a6120920690Adam Cohen private float mReorderHintAnimationMagnitude; 15819f3792523fe2d55ea791a9286398a6120920690Adam Cohen 159482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private ArrayList<View> mIntersectingViews = new ArrayList<View>(); 160482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private Rect mOccupiedRect = new Rect(); 161482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private int[] mDirectionVector = new int[2]; 16219f3792523fe2d55ea791a9286398a6120920690Adam Cohen int[] mPreviousReorderDirection = new int[2]; 163b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen private static final int INVALID_DIRECTION = -100; 164c6cc61d45836e4081920883cc4d448ccb0bb8417Adam Cohen private DropTarget.DragEnforcer mDragEnforcer; 165482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 16631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public CellLayout(Context context) { 16731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this(context, null); 16831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 16931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 17031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public CellLayout(Context context, AttributeSet attrs) { 17131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this(context, attrs, 0); 17231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 17331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 17431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public CellLayout(Context context, AttributeSet attrs, int defStyle) { 17531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project super(context, attrs, defStyle); 176c6cc61d45836e4081920883cc4d448ccb0bb8417Adam Cohen mDragEnforcer = new DropTarget.DragEnforcer(mContext); 1776569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 1786569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy // A ViewGroup usually does not draw, but CellLayout needs to draw a rectangle to show 1796569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy // the user where a dragged item will land when dropped. 1806569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy setWillNotDraw(false); 1812acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen mLauncher = (Launcher) context; 182a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka 18331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CellLayout, defStyle, 0); 18431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 1854b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung mOriginalCellWidth = 1864b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung mCellWidth = a.getDimensionPixelSize(R.styleable.CellLayout_cellWidth, 10); 1874b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung mOriginalCellHeight = 1884b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung mCellHeight = a.getDimensionPixelSize(R.styleable.CellLayout_cellHeight, 10); 189234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen mWidthGap = mOriginalWidthGap = a.getDimensionPixelSize(R.styleable.CellLayout_widthGap, 0); 190234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen mHeightGap = mOriginalHeightGap = a.getDimensionPixelSize(R.styleable.CellLayout_heightGap, 0); 1914b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung mMaxGap = a.getDimensionPixelSize(R.styleable.CellLayout_maxGap, 0); 192d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen mCountX = LauncherModel.getCellCountX(); 193d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen mCountY = LauncherModel.getCellCountY(); 1940280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka mOccupied = new boolean[mCountX][mCountY]; 195482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mTmpOccupied = new boolean[mCountX][mCountY]; 1965b53f29f809a0dad4a1e0717ba610ce737ee0f43Adam Cohen mPreviousReorderDirection[0] = INVALID_DIRECTION; 1975b53f29f809a0dad4a1e0717ba610ce737ee0f43Adam Cohen mPreviousReorderDirection[1] = INVALID_DIRECTION; 19831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 19931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project a.recycle(); 20031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 20131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project setAlwaysDrawnWithCacheEnabled(false); 20231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 203046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy final Resources res = getResources(); 204de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy 205967289b6d5fec77f5c381d11ffb2319f3bb5e737Winson Chung mNormalBackground = res.getDrawable(R.drawable.homescreen_blue_normal_holo); 206dea74b7d12b0fcd50bfdb4274f9867ba76d75238Winson Chung mActiveGlowBackground = res.getDrawable(R.drawable.homescreen_blue_strong_holo); 207b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung 208b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mOverScrollLeft = res.getDrawable(R.drawable.overscroll_glow_left); 209b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mOverScrollRight = res.getDrawable(R.drawable.overscroll_glow_right); 210b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mForegroundPadding = 211b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen res.getDimensionPixelSize(R.dimen.workspace_overscroll_drawable_padding); 212b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung 21319f3792523fe2d55ea791a9286398a6120920690Adam Cohen mReorderHintAnimationMagnitude = (REORDER_HINT_MAGNITUDE * 21419f3792523fe2d55ea791a9286398a6120920690Adam Cohen res.getDimensionPixelSize(R.dimen.app_icon_size)); 21519f3792523fe2d55ea791a9286398a6120920690Adam Cohen 216b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung mNormalBackground.setFilterBitmap(true); 217b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung mActiveGlowBackground.setFilterBitmap(true); 218de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy 219eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung int iconScale = res.getInteger(R.integer.app_icon_scale_percent); 220eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung if (iconScale >= 0) { 221eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung mChildScale = iconScale / 100f; 222eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung } 223eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung int hotseatIconScale = res.getInteger(R.integer.app_icon_hotseat_scale_percent); 224eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung if (hotseatIconScale >= 0) { 225eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung mHotseatChildScale = hotseatIconScale / 100f; 226eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung } 2270dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn 228046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy // Initialize the data structures used for the drag visualization. 229150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung 230046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy mCrosshairsDrawable = res.getDrawable(R.drawable.gardening_crosshairs); 231ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy mEaseOutInterpolator = new DecelerateInterpolator(2.5f); // Quint ease out 232de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy 233046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy // Set up the animation for fading the crosshairs in and out 234046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy int animDuration = res.getInteger(R.integer.config_crosshairsFadeInTime); 23549250ad530385fcdd6072ca54697f670ec503b59Patrick Dubroy mCrosshairsAnimator = new InterruptibleInOutAnimator(animDuration, 0.0f, 1.0f); 236472b281d5cb4f5660df981a6c912266b9f5703feChet Haase mCrosshairsAnimator.getAnimator().addUpdateListener(new AnimatorUpdateListener() { 237046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy public void onAnimationUpdate(ValueAnimator animation) { 238046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy mCrosshairsVisibility = ((Float) animation.getAnimatedValue()).floatValue(); 2398e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy invalidate(); 240046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy } 241046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy }); 242ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy mCrosshairsAnimator.getAnimator().setInterpolator(mEaseOutInterpolator); 243046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy 244b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung mDragCell[0] = mDragCell[1] = -1; 2454be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato for (int i = 0; i < mDragOutlines.length; i++) { 246d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen mDragOutlines[i] = new Rect(-1, -1, -1, -1); 247046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy } 248046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy 249046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy // When dragging things around the home screens, we show a green outline of 250046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy // where the item will land. The outlines gradually fade out, leaving a trail 251046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy // behind the drag path. 252046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy // Set up all the animations that are used to implement this fading. 253046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy final int duration = res.getInteger(R.integer.config_dragOutlineFadeTime); 254472b281d5cb4f5660df981a6c912266b9f5703feChet Haase final float fromAlphaValue = 0; 255472b281d5cb4f5660df981a6c912266b9f5703feChet Haase final float toAlphaValue = (float)res.getInteger(R.integer.config_dragOutlineMaxAlpha); 2564be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato 2578e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy Arrays.fill(mDragOutlineAlphas, fromAlphaValue); 2584be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato 2594be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato for (int i = 0; i < mDragOutlineAnims.length; i++) { 260046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy final InterruptibleInOutAnimator anim = 261046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy new InterruptibleInOutAnimator(duration, fromAlphaValue, toAlphaValue); 262ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy anim.getAnimator().setInterpolator(mEaseOutInterpolator); 263046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy final int thisIndex = i; 264472b281d5cb4f5660df981a6c912266b9f5703feChet Haase anim.getAnimator().addUpdateListener(new AnimatorUpdateListener() { 265de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy public void onAnimationUpdate(ValueAnimator animation) { 2664be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato final Bitmap outline = (Bitmap)anim.getTag(); 2674be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato 2684be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // If an animation is started and then stopped very quickly, we can still 2694be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // get spurious updates we've cleared the tag. Guard against this. 2704be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato if (outline == null) { 271fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy if (false) { 272fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy Object val = animation.getAnimatedValue(); 273fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy Log.d(TAG, "anim " + thisIndex + " update: " + val + 274fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy ", isStopped " + anim.isStopped()); 275fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy } 2764be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // Try to prevent it from continuing to run 2774be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato animation.cancel(); 2784be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato } else { 279472b281d5cb4f5660df981a6c912266b9f5703feChet Haase mDragOutlineAlphas[thisIndex] = (Float) animation.getAnimatedValue(); 280d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen CellLayout.this.invalidate(mDragOutlines[thisIndex]); 2814be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato } 282de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy } 283de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy }); 2844be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // The animation holds a reference to the drag outline bitmap as long is it's 2854be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // running. This way the bitmap can be GCed when the animations are complete. 286472b281d5cb4f5660df981a6c912266b9f5703feChet Haase anim.getAnimator().addListener(new AnimatorListenerAdapter() { 2873c4c20fbe682cb4b3ef94f09afe0af09171583f3Michael Jurka @Override 2884be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato public void onAnimationEnd(Animator animation) { 289472b281d5cb4f5660df981a6c912266b9f5703feChet Haase if ((Float) ((ValueAnimator) animation).getAnimatedValue() == 0f) { 2904be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato anim.setTag(null); 2914be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato } 2924be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato } 2934be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato }); 2944be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato mDragOutlineAnims[i] = anim; 295de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy } 296ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy 29718014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka mBackgroundRect = new Rect(); 298b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mForegroundRect = new Rect(); 299bea15195346bab3c52b0156e92f2b71f0811b210Michael Jurka 300a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets = new ShortcutAndWidgetContainer(context); 301a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.setCellDimensions(mCellWidth, mCellHeight, mWidthGap, mHeightGap); 302a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka addView(mShortcutsAndWidgets); 30318014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka } 30418014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka 305f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka static int widthInPortrait(Resources r, int numCells) { 306f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka // We use this method from Workspace to figure out how many rows/columns Launcher should 307f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka // have. We ignore the left/right padding on CellLayout because it turns out in our design 308f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka // the padding extends outside the visible screen size, but it looked fine anyway. 309f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka int cellWidth = r.getDimensionPixelSize(R.dimen.workspace_cell_width); 3104b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung int minGap = Math.min(r.getDimensionPixelSize(R.dimen.workspace_width_gap), 3114b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung r.getDimensionPixelSize(R.dimen.workspace_height_gap)); 312f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka 3134b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung return minGap * (numCells - 1) + cellWidth * numCells; 314f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka } 315f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka 316f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka static int heightInLandscape(Resources r, int numCells) { 317f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka // We use this method from Workspace to figure out how many rows/columns Launcher should 318f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka // have. We ignore the left/right padding on CellLayout because it turns out in our design 319f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka // the padding extends outside the visible screen size, but it looked fine anyway. 320f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka int cellHeight = r.getDimensionPixelSize(R.dimen.workspace_cell_height); 3214b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung int minGap = Math.min(r.getDimensionPixelSize(R.dimen.workspace_width_gap), 3224b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung r.getDimensionPixelSize(R.dimen.workspace_height_gap)); 323f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka 3244b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung return minGap * (numCells - 1) + cellHeight * numCells; 325f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka } 326f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka 3272801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen public void enableHardwareLayers() { 328a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.enableHardwareLayers(); 3292801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen } 3302801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen 3312801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen public void setGridSize(int x, int y) { 3322801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen mCountX = x; 3332801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen mCountY = y; 3342801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen mOccupied = new boolean[mCountX][mCountY]; 335482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mTmpOccupied = new boolean[mCountX][mCountY]; 3367fbec10b36818f100b631f3d73fe1ad5360975aaAdam Cohen mTempRectStack.clear(); 33776fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen requestLayout(); 3382801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen } 3392801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen 34096864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy private void invalidateBubbleTextView(BubbleTextView icon) { 34196864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy final int padding = icon.getPressedOrFocusedBackgroundPadding(); 3424b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung invalidate(icon.getLeft() + getPaddingLeft() - padding, 3434b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung icon.getTop() + getPaddingTop() - padding, 3444b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung icon.getRight() + getPaddingLeft() + padding, 3454b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung icon.getBottom() + getPaddingTop() + padding); 34696864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy } 34796864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy 348b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen void setOverScrollAmount(float r, boolean left) { 349b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen if (left && mOverScrollForegroundDrawable != mOverScrollLeft) { 350b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mOverScrollForegroundDrawable = mOverScrollLeft; 351b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen } else if (!left && mOverScrollForegroundDrawable != mOverScrollRight) { 352b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mOverScrollForegroundDrawable = mOverScrollRight; 353b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen } 354b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen 355b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mForegroundAlpha = (int) Math.round((r * 255)); 356b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mOverScrollForegroundDrawable.setAlpha(mForegroundAlpha); 357b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen invalidate(); 358b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen } 359b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen 36096864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy void setPressedOrFocusedIcon(BubbleTextView icon) { 36196864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy // We draw the pressed or focused BubbleTextView's background in CellLayout because it 36296864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy // requires an expanded clip rect (due to the glow's blur radius) 36396864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy BubbleTextView oldIcon = mPressedOrFocusedIcon; 36496864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy mPressedOrFocusedIcon = icon; 36596864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy if (oldIcon != null) { 36696864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy invalidateBubbleTextView(oldIcon); 36796864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy } 36896864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy if (mPressedOrFocusedIcon != null) { 36996864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy invalidateBubbleTextView(mPressedOrFocusedIcon); 37096864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy } 37196864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy } 37296864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy 37333945b21544bc98381df17726a3537c292d8c985Michael Jurka void setIsDragOverlapping(boolean isDragOverlapping) { 37433945b21544bc98381df17726a3537c292d8c985Michael Jurka if (mIsDragOverlapping != isDragOverlapping) { 37533945b21544bc98381df17726a3537c292d8c985Michael Jurka mIsDragOverlapping = isDragOverlapping; 37633945b21544bc98381df17726a3537c292d8c985Michael Jurka invalidate(); 37733945b21544bc98381df17726a3537c292d8c985Michael Jurka } 37833945b21544bc98381df17726a3537c292d8c985Michael Jurka } 37933945b21544bc98381df17726a3537c292d8c985Michael Jurka 38033945b21544bc98381df17726a3537c292d8c985Michael Jurka boolean getIsDragOverlapping() { 38133945b21544bc98381df17726a3537c292d8c985Michael Jurka return mIsDragOverlapping; 38233945b21544bc98381df17726a3537c292d8c985Michael Jurka } 38333945b21544bc98381df17726a3537c292d8c985Michael Jurka 384ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen protected void setOverscrollTransformsDirty(boolean dirty) { 385ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen mScrollingTransformsDirty = dirty; 386ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen } 387ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen 388ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen protected void resetOverscrollTransforms() { 389ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen if (mScrollingTransformsDirty) { 390ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen setOverscrollTransformsDirty(false); 391ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen setTranslationX(0); 392ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen setRotationY(0); 393ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen // It doesn't matter if we pass true or false here, the important thing is that we 394ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen // pass 0, which results in the overscroll drawable not being drawn any more. 395ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen setOverScrollAmount(0, false); 396ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen setPivotX(getMeasuredWidth() / 2); 397ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen setPivotY(getMeasuredHeight() / 2); 398ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen } 399ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen } 400ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen 401a6abce8464b57ce91e8f083951ad263370fc2da8Romain Guy @Override 4021262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy protected void onDraw(Canvas canvas) { 4033e7c7634531302271270c8cf418abc959d621cbcMichael Jurka // When we're large, we are either drawn in a "hover" state (ie when dragging an item to 4043e7c7634531302271270c8cf418abc959d621cbcMichael Jurka // a neighboring page) or with just a normal background (if backgroundAlpha > 0.0f) 4053e7c7634531302271270c8cf418abc959d621cbcMichael Jurka // When we're small, we are either drawn normally or in the "accepts drops" state (during 4063e7c7634531302271270c8cf418abc959d621cbcMichael Jurka // a drag). However, we also drag the mini hover background *over* one of those two 4073e7c7634531302271270c8cf418abc959d621cbcMichael Jurka // backgrounds 408b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung if (mBackgroundAlpha > 0.0f) { 409f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen Drawable bg; 41033945b21544bc98381df17726a3537c292d8c985Michael Jurka 41133945b21544bc98381df17726a3537c292d8c985Michael Jurka if (mIsDragOverlapping) { 41233945b21544bc98381df17726a3537c292d8c985Michael Jurka // In the mini case, we draw the active_glow bg *over* the active background 413bdf78559f223ac11e01e3311edd5a48a80383e1eMichael Jurka bg = mActiveGlowBackground; 414f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen } else { 415bdf78559f223ac11e01e3311edd5a48a80383e1eMichael Jurka bg = mNormalBackground; 416f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen } 41733945b21544bc98381df17726a3537c292d8c985Michael Jurka 41833945b21544bc98381df17726a3537c292d8c985Michael Jurka bg.setAlpha((int) (mBackgroundAlpha * mBackgroundAlphaMultiplier * 255)); 41933945b21544bc98381df17726a3537c292d8c985Michael Jurka bg.setBounds(mBackgroundRect); 42033945b21544bc98381df17726a3537c292d8c985Michael Jurka bg.draw(canvas); 421a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka } 42231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 423de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy if (mCrosshairsVisibility > 0.0f) { 424de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy final int countX = mCountX; 425de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy final int countY = mCountY; 426de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy 427de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy final float MAX_ALPHA = 0.4f; 428de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy final int MAX_VISIBLE_DISTANCE = 600; 429de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy final float DISTANCE_MULTIPLIER = 0.002f; 430de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy 431de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy final Drawable d = mCrosshairsDrawable; 432de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy final int width = d.getIntrinsicWidth(); 433de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy final int height = d.getIntrinsicHeight(); 434de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy 4354b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung int x = getPaddingLeft() - (mWidthGap / 2) - (width / 2); 436de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy for (int col = 0; col <= countX; col++) { 4374b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung int y = getPaddingTop() - (mHeightGap / 2) - (height / 2); 438de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy for (int row = 0; row <= countY; row++) { 439de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy mTmpPointF.set(x - mDragCenter.x, y - mDragCenter.y); 440de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy float dist = mTmpPointF.length(); 441de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy // Crosshairs further from the drag point are more faint 442de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy float alpha = Math.min(MAX_ALPHA, 443de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy DISTANCE_MULTIPLIER * (MAX_VISIBLE_DISTANCE - dist)); 444de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy if (alpha > 0.0f) { 445de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy d.setBounds(x, y, x + width, y + height); 446de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy d.setAlpha((int) (alpha * 255 * mCrosshairsVisibility)); 447de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy d.draw(canvas); 448de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy } 449de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy y += mCellHeight + mHeightGap; 450de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy } 451de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy x += mCellWidth + mWidthGap; 452de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy } 4534be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato } 454150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung 4558e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy final Paint paint = mDragOutlinePaint; 4564be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato for (int i = 0; i < mDragOutlines.length; i++) { 457472b281d5cb4f5660df981a6c912266b9f5703feChet Haase final float alpha = mDragOutlineAlphas[i]; 4584be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato if (alpha > 0) { 459d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen final Rect r = mDragOutlines[i]; 4604be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato final Bitmap b = (Bitmap) mDragOutlineAnims[i].getTag(); 461472b281d5cb4f5660df981a6c912266b9f5703feChet Haase paint.setAlpha((int)(alpha + .5f)); 462d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen canvas.drawBitmap(b, null, r, paint); 463150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung } 4646569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy } 46596864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy 46696864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy // We draw the pressed or focused BubbleTextView's background in CellLayout because it 46796864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy // requires an expanded clip rect (due to the glow's blur radius) 46896864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy if (mPressedOrFocusedIcon != null) { 46996864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy final int padding = mPressedOrFocusedIcon.getPressedOrFocusedBackgroundPadding(); 47096864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy final Bitmap b = mPressedOrFocusedIcon.getPressedOrFocusedBackground(); 47196864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy if (b != null) { 47296864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy canvas.drawBitmap(b, 4734b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung mPressedOrFocusedIcon.getLeft() + getPaddingLeft() - padding, 4744b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung mPressedOrFocusedIcon.getTop() + getPaddingTop() - padding, 47596864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy null); 47696864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy } 47796864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy } 47869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 479482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (DEBUG_VISUALIZE_OCCUPIED) { 480482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int[] pt = new int[2]; 481482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen ColorDrawable cd = new ColorDrawable(Color.RED); 482482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen cd.setBounds(0, 0, 80, 80); 483482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < mCountX; i++) { 484482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int j = 0; j < mCountY; j++) { 485482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (mOccupied[i][j]) { 486482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen cellToPoint(i, j, pt); 487482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen canvas.save(); 488482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen canvas.translate(pt[0], pt[1]); 489482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen cd.draw(canvas); 490482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen canvas.restore(); 491482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 492482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 493482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 494482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 495482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 49669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen // The folder outer / inner ring image(s) 49769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen for (int i = 0; i < mFolderOuterRings.size(); i++) { 49869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen FolderRingAnimator fra = mFolderOuterRings.get(i); 49969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 50069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen // Draw outer ring 50169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen Drawable d = FolderRingAnimator.sSharedOuterRingDrawable; 50269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen int width = (int) fra.getOuterRingSize(); 50369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen int height = width; 50469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen cellToPoint(fra.mCellX, fra.mCellY, mTempLocation); 50569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 50669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen int centerX = mTempLocation[0] + mCellWidth / 2; 50769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen int centerY = mTempLocation[1] + FolderRingAnimator.sPreviewSize / 2; 50869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 50969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen canvas.save(); 51069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen canvas.translate(centerX - width / 2, centerY - height / 2); 51169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen d.setBounds(0, 0, width, height); 51269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen d.draw(canvas); 51369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen canvas.restore(); 51469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 51569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen // Draw inner ring 51669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen d = FolderRingAnimator.sSharedInnerRingDrawable; 51769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen width = (int) fra.getInnerRingSize(); 51869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen height = width; 51969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen cellToPoint(fra.mCellX, fra.mCellY, mTempLocation); 52069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 52169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen centerX = mTempLocation[0] + mCellWidth / 2; 52269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen centerY = mTempLocation[1] + FolderRingAnimator.sPreviewSize / 2; 52369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen canvas.save(); 52469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen canvas.translate(centerX - width / 2, centerY - width / 2); 52569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen d.setBounds(0, 0, width, height); 52669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen d.draw(canvas); 52769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen canvas.restore(); 52869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen } 529c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen 530c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen if (mFolderLeaveBehindCell[0] >= 0 && mFolderLeaveBehindCell[1] >= 0) { 531c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen Drawable d = FolderIcon.sSharedFolderLeaveBehind; 532c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen int width = d.getIntrinsicWidth(); 533c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen int height = d.getIntrinsicHeight(); 534c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen 535c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen cellToPoint(mFolderLeaveBehindCell[0], mFolderLeaveBehindCell[1], mTempLocation); 536c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen int centerX = mTempLocation[0] + mCellWidth / 2; 537c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen int centerY = mTempLocation[1] + FolderRingAnimator.sPreviewSize / 2; 538c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen 539c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen canvas.save(); 540c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen canvas.translate(centerX - width / 2, centerY - width / 2); 541c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen d.setBounds(0, 0, width, height); 542c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen d.draw(canvas); 543c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen canvas.restore(); 544c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen } 54569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen } 54669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 547b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen @Override 548b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen protected void dispatchDraw(Canvas canvas) { 549b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen super.dispatchDraw(canvas); 550b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen if (mForegroundAlpha > 0) { 551b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mOverScrollForegroundDrawable.setBounds(mForegroundRect); 552b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen Paint p = ((NinePatchDrawable) mOverScrollForegroundDrawable).getPaint(); 553b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen p.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.ADD)); 554b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mOverScrollForegroundDrawable.draw(canvas); 555b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen p.setXfermode(null); 556b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen } 557b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen } 558b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen 55969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen public void showFolderAccept(FolderRingAnimator fra) { 56069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen mFolderOuterRings.add(fra); 56169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen } 56269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 56369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen public void hideFolderAccept(FolderRingAnimator fra) { 56469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen if (mFolderOuterRings.contains(fra)) { 56569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen mFolderOuterRings.remove(fra); 56669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen } 56769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen invalidate(); 5686569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy } 5696569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 570c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen public void setFolderLeaveBehindCell(int x, int y) { 571c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen mFolderLeaveBehindCell[0] = x; 572c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen mFolderLeaveBehindCell[1] = y; 573c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen invalidate(); 574c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen } 575c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen 576c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen public void clearFolderLeaveBehind() { 577c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen mFolderLeaveBehindCell[0] = -1; 578c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen mFolderLeaveBehindCell[1] = -1; 579c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen invalidate(); 580c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen } 581c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen 5826569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy @Override 583e6235dd225404239b55c459245543f3302326112Michael Jurka public boolean shouldDelayChildPressedState() { 584e6235dd225404239b55c459245543f3302326112Michael Jurka return false; 585e6235dd225404239b55c459245543f3302326112Michael Jurka } 586e6235dd225404239b55c459245543f3302326112Michael Jurka 587e6235dd225404239b55c459245543f3302326112Michael Jurka @Override 58883f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey public void cancelLongPress() { 58983f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey super.cancelLongPress(); 59083f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey 59183f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey // Cancel long press for all children 59283f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey final int count = getChildCount(); 59383f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey for (int i = 0; i < count; i++) { 59483f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey final View child = getChildAt(i); 59583f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey child.cancelLongPress(); 59683f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey } 59783f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey } 59883f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey 599dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka public void setOnInterceptTouchListener(View.OnTouchListener listener) { 600dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka mInterceptTouchListener = listener; 601dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } 602dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka 60331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int getCountX() { 604d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen return mCountX; 60531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 60631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 60731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int getCountY() { 608d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen return mCountY; 60931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 61031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 6110dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn public void setIsHotseat(boolean isHotseat) { 6120dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn mIsHotseat = isHotseat; 6130dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn } 6140dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn 615eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung public float getChildrenScale() { 616eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung return mIsHotseat ? mHotseatChildScale : mChildScale; 617eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung } 618eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung 619f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka public boolean addViewToCellLayout( 620f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka View child, int index, int childId, LayoutParams params, boolean markCells) { 6210dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn return addViewToCellLayout(child, index, childId, params, markCells, false); 6220dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn } 6230dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn 624eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung private void scaleChild(BubbleTextView bubbleChild, float pivot, float scale) { 625bc239a15464f543a41b960b946aa77258454efafAndrew Flynn // If we haven't measured the child yet, do it now 626bc239a15464f543a41b960b946aa77258454efafAndrew Flynn // (this happens if we're being dropped from all-apps 627bc239a15464f543a41b960b946aa77258454efafAndrew Flynn if (bubbleChild.getLayoutParams() instanceof LayoutParams && 628bc239a15464f543a41b960b946aa77258454efafAndrew Flynn (bubbleChild.getMeasuredWidth() | bubbleChild.getMeasuredHeight()) == 0) { 629a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka getShortcutsAndWidgets().measureChild(bubbleChild); 630bc239a15464f543a41b960b946aa77258454efafAndrew Flynn } 631bc239a15464f543a41b960b946aa77258454efafAndrew Flynn 632bc239a15464f543a41b960b946aa77258454efafAndrew Flynn bubbleChild.setScaleX(scale); 633bc239a15464f543a41b960b946aa77258454efafAndrew Flynn bubbleChild.setScaleY(scale); 634bc239a15464f543a41b960b946aa77258454efafAndrew Flynn } 635bc239a15464f543a41b960b946aa77258454efafAndrew Flynn 636bc239a15464f543a41b960b946aa77258454efafAndrew Flynn private void resetChild(BubbleTextView bubbleChild) { 637bc239a15464f543a41b960b946aa77258454efafAndrew Flynn bubbleChild.setScaleX(1f); 638bc239a15464f543a41b960b946aa77258454efafAndrew Flynn bubbleChild.setScaleY(1f); 639bc239a15464f543a41b960b946aa77258454efafAndrew Flynn 640bc239a15464f543a41b960b946aa77258454efafAndrew Flynn bubbleChild.setTextColor(getResources().getColor(R.color.workspace_icon_text_color)); 641bc239a15464f543a41b960b946aa77258454efafAndrew Flynn } 642bc239a15464f543a41b960b946aa77258454efafAndrew Flynn 6430dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn public boolean addViewToCellLayout(View child, int index, int childId, LayoutParams params, 6440dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn boolean markCells, boolean allApps) { 645aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung final LayoutParams lp = params; 646aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 6470dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn // Hotseat icons - scale down and remove text 6480dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn // Don't scale the all apps button 6490dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn // scale percent set to -1 means do not scale 6500dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn // Only scale BubbleTextViews 6510dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn if (child instanceof BubbleTextView) { 6520dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn BubbleTextView bubbleChild = (BubbleTextView) child; 6530dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn 654bc239a15464f543a41b960b946aa77258454efafAndrew Flynn // Start the child with 100% scale and visible text 655bc239a15464f543a41b960b946aa77258454efafAndrew Flynn resetChild(bubbleChild); 656bc239a15464f543a41b960b946aa77258454efafAndrew Flynn 657eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung if (mIsHotseat && !allApps && mHotseatChildScale >= 0) { 658bc239a15464f543a41b960b946aa77258454efafAndrew Flynn // Scale/make transparent for a hotseat 659eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung scaleChild(bubbleChild, 0f, mHotseatChildScale); 6600dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn 661bc239a15464f543a41b960b946aa77258454efafAndrew Flynn bubbleChild.setTextColor(getResources().getColor(android.R.color.transparent)); 662eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung } else if (mChildScale >= 0) { 663bc239a15464f543a41b960b946aa77258454efafAndrew Flynn // Else possibly still scale it if we need to for smaller icons 664eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung scaleChild(bubbleChild, 0f, mChildScale); 6650dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn } 6660dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn } 6670dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn 66831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // Generate an id for each view, this assumes we have at most 256x256 cells 66931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // per workspace screen 670d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen if (lp.cellX >= 0 && lp.cellX <= mCountX - 1 && lp.cellY >= 0 && lp.cellY <= mCountY - 1) { 671aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung // If the horizontal or vertical span is set to -1, it is taken to 672aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung // mean that it spans the extent of the CellLayout 673d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen if (lp.cellHSpan < 0) lp.cellHSpan = mCountX; 674d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen if (lp.cellVSpan < 0) lp.cellVSpan = mCountY; 675aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 676aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung child.setId(childId); 67731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 678a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.addView(child, index, lp); 679dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka 680f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka if (markCells) markCellsAsOccupiedForView(child); 6810280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 682aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung return true; 683aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung } 684aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung return false; 68531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 6863e7c7634531302271270c8cf418abc959d621cbcMichael Jurka 68731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 6880280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka public void removeAllViews() { 6890280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka clearOccupiedCells(); 690a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.removeAllViews(); 6910280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 6920280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 6930280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka @Override 6940280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka public void removeAllViewsInLayout() { 695a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka if (mShortcutsAndWidgets.getChildCount() > 0) { 6967cfc2825c3a1029f962d2fc387ae2eaa85b51798Michael Jurka clearOccupiedCells(); 697a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.removeAllViewsInLayout(); 6987cfc2825c3a1029f962d2fc387ae2eaa85b51798Michael Jurka } 6990280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 7000280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 701f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka public void removeViewWithoutMarkingCells(View view) { 702a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.removeView(view); 703f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka } 704f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka 7050280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka @Override 7060280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka public void removeView(View view) { 7070280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka markCellsAsUnoccupiedForView(view); 708a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.removeView(view); 7090280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 7100280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 7110280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka @Override 7120280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka public void removeViewAt(int index) { 713a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka markCellsAsUnoccupiedForView(mShortcutsAndWidgets.getChildAt(index)); 714a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.removeViewAt(index); 7150280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 7160280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 7170280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka @Override 7180280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka public void removeViewInLayout(View view) { 7190280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka markCellsAsUnoccupiedForView(view); 720a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.removeViewInLayout(view); 7210280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 7220280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 7230280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka @Override 7240280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka public void removeViews(int start, int count) { 7250280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka for (int i = start; i < start + count; i++) { 726a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka markCellsAsUnoccupiedForView(mShortcutsAndWidgets.getChildAt(i)); 7270280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 728a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.removeViews(start, count); 7290280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 7300280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 7310280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka @Override 7320280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka public void removeViewsInLayout(int start, int count) { 7330280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka for (int i = start; i < start + count; i++) { 734a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka markCellsAsUnoccupiedForView(mShortcutsAndWidgets.getChildAt(i)); 7350280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 736a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.removeViewsInLayout(start, count); 737abded66084680bb31cc7ea403c88f44f79a3c884Michael Jurka } 738abded66084680bb31cc7ea403c88f44f79a3c884Michael Jurka 73931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 74031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected void onAttachedToWindow() { 74131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project super.onAttachedToWindow(); 74231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mCellInfo.screen = ((ViewGroup) getParent()).indexOfChild(this); 74331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 74431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 745af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka public void setTagToCellInfoForPoint(int touchX, int touchY) { 74631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final CellInfo cellInfo = mCellInfo; 747eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung Rect frame = mRect; 748af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka final int x = touchX + mScrollX; 749af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka final int y = touchY + mScrollY; 750a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka final int count = mShortcutsAndWidgets.getChildCount(); 75131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 752af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka boolean found = false; 753af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka for (int i = count - 1; i >= 0; i--) { 754a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka final View child = mShortcutsAndWidgets.getChildAt(i); 755d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 756af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka 7571b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen if ((child.getVisibility() == VISIBLE || child.getAnimation() != null) && 7581b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen lp.isLockedToGrid) { 759af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka child.getHitRect(frame); 7600be025d64c1f84138fe430a58875886e66aae767Winson Chung 761eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung float scale = child.getScaleX(); 762eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung frame = new Rect(child.getLeft(), child.getTop(), child.getRight(), 763eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung child.getBottom()); 7640be025d64c1f84138fe430a58875886e66aae767Winson Chung // The child hit rect is relative to the CellLayoutChildren parent, so we need to 7650be025d64c1f84138fe430a58875886e66aae767Winson Chung // offset that by this CellLayout's padding to test an (x,y) point that is relative 7660be025d64c1f84138fe430a58875886e66aae767Winson Chung // to this view. 7674b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung frame.offset(mPaddingLeft, mPaddingTop); 768eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung frame.inset((int) (frame.width() * (1f - scale) / 2), 769eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung (int) (frame.height() * (1f - scale) / 2)); 7700be025d64c1f84138fe430a58875886e66aae767Winson Chung 771af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka if (frame.contains(x, y)) { 772af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.cell = child; 773af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.cellX = lp.cellX; 774af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.cellY = lp.cellY; 775af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.spanX = lp.cellHSpan; 776af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.spanY = lp.cellVSpan; 777af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka found = true; 778af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka break; 77931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 78031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 781af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka } 782aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 783d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka mLastDownOnOccupiedCell = found; 784d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka 785af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka if (!found) { 7860be025d64c1f84138fe430a58875886e66aae767Winson Chung final int cellXY[] = mTmpXY; 787af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka pointToCellExact(x, y, cellXY); 78831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 789af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.cell = null; 790af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.cellX = cellXY[0]; 791af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.cellY = cellXY[1]; 792af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.spanX = 1; 793af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.spanY = 1; 794af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka } 795af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka setTag(cellInfo); 796af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka } 79731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 798af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka @Override 799af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka public boolean onInterceptTouchEvent(MotionEvent ev) { 800c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen // First we clear the tag to ensure that on every touch down we start with a fresh slate, 801c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen // even in the case where we return early. Not clearing here was causing bugs whereby on 802c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen // long-press we'd end up picking up an item from a previous drag operation. 803c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen final int action = ev.getAction(); 804c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen 805c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen if (action == MotionEvent.ACTION_DOWN) { 806c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen clearTagCellInfo(); 807c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen } 808c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen 809dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka if (mInterceptTouchListener != null && mInterceptTouchListener.onTouch(this, ev)) { 810dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka return true; 811dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } 81231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 813af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka if (action == MotionEvent.ACTION_DOWN) { 814af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka setTagToCellInfoForPoint((int) ev.getX(), (int) ev.getY()); 81531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 816eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung 81731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return false; 81831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 81931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 820c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen private void clearTagCellInfo() { 821c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen final CellInfo cellInfo = mCellInfo; 822c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen cellInfo.cell = null; 823c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen cellInfo.cellX = -1; 824c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen cellInfo.cellY = -1; 825c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen cellInfo.spanX = 0; 826c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen cellInfo.spanY = 0; 827c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen setTag(cellInfo); 828c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen } 829c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen 83031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public CellInfo getTag() { 8310280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka return (CellInfo) super.getTag(); 83231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 83331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 8346569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy /** 835aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * Given a point, return the cell that strictly encloses that point 83631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param x X coordinate of the point 83731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param y Y coordinate of the point 83831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param result Array of 2 ints to hold the x and y coordinate of the cell 83931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 84031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project void pointToCellExact(int x, int y, int[] result) { 8414b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung final int hStartPadding = getPaddingLeft(); 8424b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung final int vStartPadding = getPaddingTop(); 84331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 84431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project result[0] = (x - hStartPadding) / (mCellWidth + mWidthGap); 84531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project result[1] = (y - vStartPadding) / (mCellHeight + mHeightGap); 84631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 847d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen final int xAxis = mCountX; 848d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen final int yAxis = mCountY; 84931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 85031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (result[0] < 0) result[0] = 0; 85131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (result[0] >= xAxis) result[0] = xAxis - 1; 85231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (result[1] < 0) result[1] = 0; 85331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (result[1] >= yAxis) result[1] = yAxis - 1; 85431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 855aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 85631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 85731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Given a point, return the cell that most closely encloses that point 85831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param x X coordinate of the point 85931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param y Y coordinate of the point 86031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param result Array of 2 ints to hold the x and y coordinate of the cell 86131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 86231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project void pointToCellRounded(int x, int y, int[] result) { 86331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project pointToCellExact(x + (mCellWidth / 2), y + (mCellHeight / 2), result); 86431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 86531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 86631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 86731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Given a cell coordinate, return the point that represents the upper left corner of that cell 868aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * 869aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * @param cellX X coordinate of the cell 87031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param cellY Y coordinate of the cell 871aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * 87231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param result Array of 2 ints to hold the x and y coordinate of the point 87331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 87431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project void cellToPoint(int cellX, int cellY, int[] result) { 8754b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung final int hStartPadding = getPaddingLeft(); 8764b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung final int vStartPadding = getPaddingTop(); 87731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 87831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project result[0] = hStartPadding + cellX * (mCellWidth + mWidthGap); 87931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project result[1] = vStartPadding + cellY * (mCellHeight + mHeightGap); 88031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 88131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 882e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen /** 883482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * Given a cell coordinate, return the point that represents the center of the cell 884e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen * 885e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen * @param cellX X coordinate of the cell 886e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen * @param cellY Y coordinate of the cell 887e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen * 888e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen * @param result Array of 2 ints to hold the x and y coordinate of the point 889e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen */ 890e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen void cellToCenterPoint(int cellX, int cellY, int[] result) { 89147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen regionToCenterPoint(cellX, cellY, 1, 1, result); 89247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 89347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 89447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen /** 89547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * Given a cell coordinate and span return the point that represents the center of the regio 89647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * 89747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param cellX X coordinate of the cell 89847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param cellY Y coordinate of the cell 89947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * 90047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param result Array of 2 ints to hold the x and y coordinate of the point 90147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen */ 90247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen void regionToCenterPoint(int cellX, int cellY, int spanX, int spanY, int[] result) { 9034b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung final int hStartPadding = getPaddingLeft(); 9044b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung final int vStartPadding = getPaddingTop(); 90547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen result[0] = hStartPadding + cellX * (mCellWidth + mWidthGap) + 90647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen (spanX * mCellWidth + (spanX - 1) * mWidthGap) / 2; 90747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen result[1] = vStartPadding + cellY * (mCellHeight + mHeightGap) + 90847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen (spanY * mCellHeight + (spanY - 1) * mHeightGap) / 2; 909e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen } 910e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen 91119f3792523fe2d55ea791a9286398a6120920690Adam Cohen /** 91219f3792523fe2d55ea791a9286398a6120920690Adam Cohen * Given a cell coordinate and span fills out a corresponding pixel rect 91319f3792523fe2d55ea791a9286398a6120920690Adam Cohen * 91419f3792523fe2d55ea791a9286398a6120920690Adam Cohen * @param cellX X coordinate of the cell 91519f3792523fe2d55ea791a9286398a6120920690Adam Cohen * @param cellY Y coordinate of the cell 91619f3792523fe2d55ea791a9286398a6120920690Adam Cohen * @param result Rect in which to write the result 91719f3792523fe2d55ea791a9286398a6120920690Adam Cohen */ 91819f3792523fe2d55ea791a9286398a6120920690Adam Cohen void regionToRect(int cellX, int cellY, int spanX, int spanY, Rect result) { 91919f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int hStartPadding = getPaddingLeft(); 92019f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int vStartPadding = getPaddingTop(); 92119f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int left = hStartPadding + cellX * (mCellWidth + mWidthGap); 92219f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int top = vStartPadding + cellY * (mCellHeight + mHeightGap); 92319f3792523fe2d55ea791a9286398a6120920690Adam Cohen result.set(left, top, left + (spanX * mCellWidth + (spanX - 1) * mWidthGap), 92419f3792523fe2d55ea791a9286398a6120920690Adam Cohen top + (spanY * mCellHeight + (spanY - 1) * mHeightGap)); 92519f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 92619f3792523fe2d55ea791a9286398a6120920690Adam Cohen 927482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public float getDistanceFromCell(float x, float y, int[] cell) { 928482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen cellToCenterPoint(cell[0], cell[1], mTmpPoint); 929482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen float distance = (float) Math.sqrt( Math.pow(x - mTmpPoint[0], 2) + 930482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen Math.pow(y - mTmpPoint[1], 2)); 931482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return distance; 932482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 933482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 93484f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy int getCellWidth() { 93584f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy return mCellWidth; 93684f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy } 93784f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy 93884f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy int getCellHeight() { 93984f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy return mCellHeight; 94084f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy } 94184f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy 942d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen int getWidthGap() { 943d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen return mWidthGap; 944d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen } 945d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen 946d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen int getHeightGap() { 947d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen return mHeightGap; 948d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen } 949d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen 9507f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen Rect getContentRect(Rect r) { 9517f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen if (r == null) { 9527f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen r = new Rect(); 9537f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 9547f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen int left = getPaddingLeft(); 9557f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen int top = getPaddingTop(); 9564b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung int right = left + getWidth() - mPaddingLeft - mPaddingRight; 9574b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung int bottom = top + getHeight() - mPaddingTop - mPaddingBottom; 9587f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen r.set(left, top, right, bottom); 9597f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen return r; 9607f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 9617f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 96231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 96331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 96431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // TODO: currently ignoring padding 965aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 96631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec); 967aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec); 968aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 96931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec); 97031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec); 971aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 97231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (widthSpecMode == MeasureSpec.UNSPECIFIED || heightSpecMode == MeasureSpec.UNSPECIFIED) { 97331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project throw new RuntimeException("CellLayout cannot have UNSPECIFIED dimensions"); 97431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 97531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 976d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen int numWidthGaps = mCountX - 1; 977d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen int numHeightGaps = mCountY - 1; 978d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen 979234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen if (mOriginalWidthGap < 0 || mOriginalHeightGap < 0) { 9804b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung int hSpace = widthSpecSize - mPaddingLeft - mPaddingRight; 9814b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung int vSpace = heightSpecSize - mPaddingTop - mPaddingBottom; 9824b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung int hFreeSpace = hSpace - (mCountX * mOriginalCellWidth); 9834b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung int vFreeSpace = vSpace - (mCountY * mOriginalCellHeight); 9844b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung mWidthGap = Math.min(mMaxGap, numWidthGaps > 0 ? (hFreeSpace / numWidthGaps) : 0); 9854b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung mHeightGap = Math.min(mMaxGap,numHeightGaps > 0 ? (vFreeSpace / numHeightGaps) : 0); 986a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.setCellDimensions(mCellWidth, mCellHeight, mWidthGap, mHeightGap); 987234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen } else { 988234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen mWidthGap = mOriginalWidthGap; 989234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen mHeightGap = mOriginalHeightGap; 990ece7f5b3b55cab646941123e03589241a61678e2Winson Chung } 9915f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka 9928c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka // Initial values correspond to widthSpecMode == MeasureSpec.EXACTLY 9938c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka int newWidth = widthSpecSize; 9948c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka int newHeight = heightSpecSize; 9958c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka if (widthSpecMode == MeasureSpec.AT_MOST) { 9964b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung newWidth = mPaddingLeft + mPaddingRight + (mCountX * mCellWidth) + 9978c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka ((mCountX - 1) * mWidthGap); 9984b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung newHeight = mPaddingTop + mPaddingBottom + (mCountY * mCellHeight) + 9998c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka ((mCountY - 1) * mHeightGap); 10008c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka setMeasuredDimension(newWidth, newHeight); 10018c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka } 100231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 10038c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka int count = getChildCount(); 100431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int i = 0; i < count; i++) { 100531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project View child = getChildAt(i); 10064b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(newWidth - mPaddingLeft - 10074b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung mPaddingRight, MeasureSpec.EXACTLY); 10084b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung int childheightMeasureSpec = MeasureSpec.makeMeasureSpec(newHeight - mPaddingTop - 10094b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung mPaddingBottom, MeasureSpec.EXACTLY); 101031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project child.measure(childWidthMeasureSpec, childheightMeasureSpec); 101131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 10128c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka setMeasuredDimension(newWidth, newHeight); 101331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 101431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 101531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 101628750fba6a2d141eb9a1e566718c17236030b815Michael Jurka protected void onLayout(boolean changed, int l, int t, int r, int b) { 101731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int count = getChildCount(); 101831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int i = 0; i < count; i++) { 10198c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka View child = getChildAt(i); 10204b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung child.layout(mPaddingLeft, mPaddingTop, 10214b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung r - l - mPaddingRight, b - t - mPaddingBottom); 102231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 102331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 102431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 102531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 1026dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka protected void onSizeChanged(int w, int h, int oldw, int oldh) { 1027dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka super.onSizeChanged(w, h, oldw, oldh); 102818014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka mBackgroundRect.set(0, 0, w, h); 1029b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mForegroundRect.set(mForegroundPadding, mForegroundPadding, 1030b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen w - 2 * mForegroundPadding, h - 2 * mForegroundPadding); 1031dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } 1032dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka 1033dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka @Override 103431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected void setChildrenDrawingCacheEnabled(boolean enabled) { 1035a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.setChildrenDrawingCacheEnabled(enabled); 103631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 103731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 103831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 103931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected void setChildrenDrawnWithCacheEnabled(boolean enabled) { 1040a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.setChildrenDrawnWithCacheEnabled(enabled); 104131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 104231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 10435f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka public float getBackgroundAlpha() { 10445f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka return mBackgroundAlpha; 1045dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } 1046dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka 10471b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen public void setBackgroundAlphaMultiplier(float multiplier) { 10481b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen mBackgroundAlphaMultiplier = multiplier; 10491b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen } 10501b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen 1051ddb821981e0919bbd3b4c9a2b6aa1811d6c86bb6Adam Cohen public float getBackgroundAlphaMultiplier() { 1052ddb821981e0919bbd3b4c9a2b6aa1811d6c86bb6Adam Cohen return mBackgroundAlphaMultiplier; 1053ddb821981e0919bbd3b4c9a2b6aa1811d6c86bb6Adam Cohen } 1054ddb821981e0919bbd3b4c9a2b6aa1811d6c86bb6Adam Cohen 10555f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka public void setBackgroundAlpha(float alpha) { 1056afaa05014e0bf3ed1192f9ddec2af4283bc50248Michael Jurka if (mBackgroundAlpha != alpha) { 1057afaa05014e0bf3ed1192f9ddec2af4283bc50248Michael Jurka mBackgroundAlpha = alpha; 1058afaa05014e0bf3ed1192f9ddec2af4283bc50248Michael Jurka invalidate(); 1059afaa05014e0bf3ed1192f9ddec2af4283bc50248Michael Jurka } 1060dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } 1061dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka 1062a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka public void setShortcutAndWidgetAlpha(float alpha) { 10630142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka final int childCount = getChildCount(); 10640142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka for (int i = 0; i < childCount; i++) { 1065dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka getChildAt(i).setAlpha(alpha); 1066dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } 1067dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } 1068dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka 1069a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka public ShortcutAndWidgetContainer getShortcutsAndWidgets() { 1070a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka if (getChildCount() > 0) { 1071a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka return (ShortcutAndWidgetContainer) getChildAt(0); 1072a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka } 1073a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka return null; 1074a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka } 1075a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka 1076440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy public View getChildAt(int x, int y) { 1077a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka return mShortcutsAndWidgets.getChildAt(x, y); 1078440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy } 1079440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy 108076fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen public boolean animateChildToPosition(final View child, int cellX, int cellY, int duration, 1081482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int delay, boolean permanent, boolean adjustOccupied) { 1082a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka ShortcutAndWidgetContainer clc = getShortcutsAndWidgets(); 1083482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean[][] occupied = mOccupied; 1084482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (!permanent) { 1085482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen occupied = mTmpOccupied; 1086482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1087482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 108819f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (clc.indexOfChild(child) != -1) { 1089bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 1090bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen final ItemInfo info = (ItemInfo) child.getTag(); 1091bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen 1092bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen // We cancel any existing animations 1093bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen if (mReorderAnimators.containsKey(lp)) { 1094bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen mReorderAnimators.get(lp).cancel(); 1095bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen mReorderAnimators.remove(lp); 1096bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 1097bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen 1098482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int oldX = lp.x; 1099482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int oldY = lp.y; 1100482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (adjustOccupied) { 1101482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen occupied[lp.cellX][lp.cellY] = false; 1102482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen occupied[cellX][cellY] = true; 1103482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1104bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen lp.isLockedToGrid = true; 1105482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (permanent) { 1106482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen lp.cellX = info.cellX = cellX; 1107482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen lp.cellY = info.cellY = cellY; 1108482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } else { 1109482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen lp.tmpCellX = cellX; 1110482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen lp.tmpCellY = cellY; 1111482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1112bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen clc.setupLp(lp); 1113bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen lp.isLockedToGrid = false; 1114482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int newX = lp.x; 1115482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int newY = lp.y; 1116bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen 111776fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen lp.x = oldX; 111876fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen lp.y = oldY; 111976fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen 1120482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // Exit early if we're not actually moving the view 1121482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (oldX == newX && oldY == newY) { 1122482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen lp.isLockedToGrid = true; 1123482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return true; 1124482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1125482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1126482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen ValueAnimator va = ValueAnimator.ofFloat(0f, 1f); 1127482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen va.setDuration(duration); 1128482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mReorderAnimators.put(lp, va); 1129482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1130482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen va.addUpdateListener(new AnimatorUpdateListener() { 1131482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen @Override 1132bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen public void onAnimationUpdate(ValueAnimator animation) { 1133482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen float r = ((Float) animation.getAnimatedValue()).floatValue(); 113419f3792523fe2d55ea791a9286398a6120920690Adam Cohen lp.x = (int) ((1 - r) * oldX + r * newX); 113519f3792523fe2d55ea791a9286398a6120920690Adam Cohen lp.y = (int) ((1 - r) * oldY + r * newY); 11366b8a02d63a5d9cab8209381993e37db6a6afb753Adam Cohen child.requestLayout(); 1137bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 1138bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen }); 1139482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen va.addListener(new AnimatorListenerAdapter() { 1140bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen boolean cancelled = false; 1141bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen public void onAnimationEnd(Animator animation) { 1142bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen // If the animation was cancelled, it means that another animation 1143bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen // has interrupted this one, and we don't want to lock the item into 1144bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen // place just yet. 1145bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen if (!cancelled) { 1146bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen lp.isLockedToGrid = true; 1147482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen child.requestLayout(); 1148bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 1149bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen if (mReorderAnimators.containsKey(lp)) { 1150bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen mReorderAnimators.remove(lp); 1151bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 1152bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 1153bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen public void onAnimationCancel(Animator animation) { 1154bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen cancelled = true; 1155bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 1156bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen }); 1157482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen va.setStartDelay(delay); 1158482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen va.start(); 1159bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen return true; 1160bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 1161bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen return false; 1162bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 1163bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen 11646569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy /** 11656569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy * Estimate where the top left cell of the dragged item will land if it is dropped. 11666569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy * 11676569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy * @param originX The X value of the top left corner of the item 11686569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy * @param originY The Y value of the top left corner of the item 11696569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy * @param spanX The number of horizontal cells that the item spans 11706569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy * @param spanY The number of vertical cells that the item spans 11716569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy * @param result The estimated drop cell X and Y. 11726569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy */ 11736569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy void estimateDropCell(int originX, int originY, int spanX, int spanY, int[] result) { 1174d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen final int countX = mCountX; 1175d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen final int countY = mCountY; 11766569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 1177a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka // pointToCellRounded takes the top left of a cell but will pad that with 1178a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka // cellWidth/2 and cellHeight/2 when finding the matching cell 1179a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka pointToCellRounded(originX, originY, result); 11806569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 11816569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy // If the item isn't fully on this screen, snap to the edges 11826569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy int rightOverhang = result[0] + spanX - countX; 11836569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy if (rightOverhang > 0) { 11846569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy result[0] -= rightOverhang; // Snap to right 11856569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy } 11866569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy result[0] = Math.max(0, result[0]); // Snap to left 11876569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy int bottomOverhang = result[1] + spanY - countY; 11886569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy if (bottomOverhang > 0) { 11896569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy result[1] -= bottomOverhang; // Snap to bottom 11906569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy } 11916569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy result[1] = Math.max(0, result[1]); // Snap to top 11926569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy } 11936569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 1194482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen void visualizeDropLocation(View v, Bitmap dragOutline, int originX, int originY, int cellX, 1195482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int cellY, int spanX, int spanY, boolean resize, Point dragOffset, Rect dragRegion) { 119608ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy final int oldDragCellX = mDragCell[0]; 119708ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy final int oldDragCellY = mDragCell[1]; 1198482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1199b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung if (v != null && dragOffset == null) { 1200a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung mDragCenter.set(originX + (v.getWidth() / 2), originY + (v.getHeight() / 2)); 1201a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung } else { 1202a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung mDragCenter.set(originX, originY); 1203a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung } 12046569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 12052801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen if (dragOutline == null && v == null) { 12062801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen if (mCrosshairsDrawable != null) { 12072801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen invalidate(); 12082801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen } 12092801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen return; 12102801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen } 12112801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen 1212482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (cellX != oldDragCellX || cellY != oldDragCellY) { 1213482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mDragCell[0] = cellX; 1214482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mDragCell[1] = cellY; 12156569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy // Find the top left corner of the rect the object will occupy 1216de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy final int[] topLeft = mTmpPoint; 1217482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen cellToPoint(cellX, cellY, topLeft); 1218de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy 12194be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato int left = topLeft[0]; 12204be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato int top = topLeft[1]; 12216569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 1222b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung if (v != null && dragOffset == null) { 122399e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen // When drawing the drag outline, it did not account for margin offsets 122499e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen // added by the view's parent. 122599e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen MarginLayoutParams lp = (MarginLayoutParams) v.getLayoutParams(); 122699e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen left += lp.leftMargin; 122799e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen top += lp.topMargin; 122899e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen 122999e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen // Offsets due to the size difference between the View and the dragOutline. 123099e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen // There is a size difference to account for the outer blur, which may lie 123199e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen // outside the bounds of the view. 1232a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung top += (v.getHeight() - dragOutline.getHeight()) / 2; 1233ae915cecd36af4973061a1cb0b58c5be1be699a0Adam Cohen // We center about the x axis 1234ae915cecd36af4973061a1cb0b58c5be1be699a0Adam Cohen left += ((mCellWidth * spanX) + ((spanX - 1) * mWidthGap) 1235ae915cecd36af4973061a1cb0b58c5be1be699a0Adam Cohen - dragOutline.getWidth()) / 2; 12366639687cd67bab1aeef2a75e5c6bc458b20dc082Adam Cohen } else { 1237b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung if (dragOffset != null && dragRegion != null) { 1238b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung // Center the drag region *horizontally* in the cell and apply a drag 1239b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung // outline offset 1240b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung left += dragOffset.x + ((mCellWidth * spanX) + ((spanX - 1) * mWidthGap) 1241b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung - dragRegion.width()) / 2; 1242b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung top += dragOffset.y; 1243b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung } else { 1244b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung // Center the drag outline in the cell 1245b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung left += ((mCellWidth * spanX) + ((spanX - 1) * mWidthGap) 1246b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung - dragOutline.getWidth()) / 2; 1247b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung top += ((mCellHeight * spanY) + ((spanY - 1) * mHeightGap) 1248b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung - dragOutline.getHeight()) / 2; 1249b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung } 1250a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung } 12514be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato final int oldIndex = mDragOutlineCurrent; 125208ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy mDragOutlineAnims[oldIndex].animateOut(); 125308ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy mDragOutlineCurrent = (oldIndex + 1) % mDragOutlines.length; 1254d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen Rect r = mDragOutlines[mDragOutlineCurrent]; 1255d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen r.set(left, top, left + dragOutline.getWidth(), top + dragOutline.getHeight()); 1256d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (resize) { 1257482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen cellToRect(cellX, cellY, spanX, spanY, r); 1258d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1259150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung 126008ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy mDragOutlineAnims[mDragOutlineCurrent].setTag(dragOutline); 126108ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy mDragOutlineAnims[mDragOutlineCurrent].animateIn(); 12626569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy } 126349250ad530385fcdd6072ca54697f670ec503b59Patrick Dubroy 126449250ad530385fcdd6072ca54697f670ec503b59Patrick Dubroy // If we are drawing crosshairs, the entire CellLayout needs to be invalidated 126549250ad530385fcdd6072ca54697f670ec503b59Patrick Dubroy if (mCrosshairsDrawable != null) { 126649250ad530385fcdd6072ca54697f670ec503b59Patrick Dubroy invalidate(); 126749250ad530385fcdd6072ca54697f670ec503b59Patrick Dubroy } 12686569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy } 12696569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 1270e0310965022e7a1adb7ad489505d404186608689Adam Cohen public void clearDragOutlines() { 1271e0310965022e7a1adb7ad489505d404186608689Adam Cohen final int oldIndex = mDragOutlineCurrent; 1272e0310965022e7a1adb7ad489505d404186608689Adam Cohen mDragOutlineAnims[oldIndex].animateOut(); 1273d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen mDragCell[0] = mDragCell[1] = -1; 1274e0310965022e7a1adb7ad489505d404186608689Adam Cohen } 1275e0310965022e7a1adb7ad489505d404186608689Adam Cohen 127631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 127770864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * Find a vacant area that will fit the given bounds nearest the requested 127870864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * cell location. Uses Euclidean distance to score multiple vacant areas. 1279aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * 128051afc022fa76c79f0d1ece470ddc126c08fea8a4Romain Guy * @param pixelX The X location at which you want to search for a vacant area. 128151afc022fa76c79f0d1ece470ddc126c08fea8a4Romain Guy * @param pixelY The Y location at which you want to search for a vacant area. 128270864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * @param spanX Horizontal span of the object. 128370864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * @param spanY Vertical span of the object. 1284de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy * @param result Array in which to place the result, or null (in which case a new array will 1285de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy * be allocated) 128670864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * @return The X, Y cell of a vacant area that can contain this object, 128770864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * nearest the requested location. 128831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 1289d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int[] findNearestVacantArea(int pixelX, int pixelY, int spanX, int spanY, 1290d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int[] result) { 1291de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy return findNearestVacantArea(pixelX, pixelY, spanX, spanY, null, result); 12926a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka } 1293aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 12946a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka /** 12956a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * Find a vacant area that will fit the given bounds nearest the requested 12966a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * cell location. Uses Euclidean distance to score multiple vacant areas. 12976a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * 12986a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * @param pixelX The X location at which you want to search for a vacant area. 12996a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * @param pixelY The Y location at which you want to search for a vacant area. 1300d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param minSpanX The minimum horizontal span required 1301d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param minSpanY The minimum vertical span required 1302d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param spanX Horizontal span of the object. 1303d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param spanY Vertical span of the object. 1304d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param result Array in which to place the result, or null (in which case a new array will 1305d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * be allocated) 1306d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @return The X, Y cell of a vacant area that can contain this object, 1307d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * nearest the requested location. 1308d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen */ 1309d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int[] findNearestVacantArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, 1310d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int spanY, int[] result, int[] resultSpan) { 1311d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen return findNearestVacantArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, null, 1312d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen result, resultSpan); 1313d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1314d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen 1315d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen /** 1316d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * Find a vacant area that will fit the given bounds nearest the requested 1317d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * cell location. Uses Euclidean distance to score multiple vacant areas. 1318d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * 1319d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param pixelX The X location at which you want to search for a vacant area. 1320d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param pixelY The Y location at which you want to search for a vacant area. 13216a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * @param spanX Horizontal span of the object. 13226a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * @param spanY Vertical span of the object. 1323df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param ignoreOccupied If true, the result can be an occupied cell 1324df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param result Array in which to place the result, or null (in which case a new array will 1325df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * be allocated) 13266a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * @return The X, Y cell of a vacant area that can contain this object, 13276a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * nearest the requested location. 13286a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka */ 1329df0353815c629fc678824b07a234b89a1ff94208Adam Cohen int[] findNearestArea(int pixelX, int pixelY, int spanX, int spanY, View ignoreView, 1330df0353815c629fc678824b07a234b89a1ff94208Adam Cohen boolean ignoreOccupied, int[] result) { 1331d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen return findNearestArea(pixelX, pixelY, spanX, spanY, 1332482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen spanX, spanY, ignoreView, ignoreOccupied, result, null, mOccupied); 1333d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1334d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen 1335d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen private final Stack<Rect> mTempRectStack = new Stack<Rect>(); 1336d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen private void lazyInitTempRectStack() { 1337d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (mTempRectStack.isEmpty()) { 1338d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen for (int i = 0; i < mCountX * mCountY; i++) { 1339d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen mTempRectStack.push(new Rect()); 1340d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1341d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1342d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1343482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1344d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen private void recycleTempRects(Stack<Rect> used) { 1345d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen while (!used.isEmpty()) { 1346d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen mTempRectStack.push(used.pop()); 1347d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1348d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1349d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen 1350d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen /** 1351d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * Find a vacant area that will fit the given bounds nearest the requested 1352d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * cell location. Uses Euclidean distance to score multiple vacant areas. 1353d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * 1354d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param pixelX The X location at which you want to search for a vacant area. 1355d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param pixelY The Y location at which you want to search for a vacant area. 1356d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param minSpanX The minimum horizontal span required 1357d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param minSpanY The minimum vertical span required 1358d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param spanX Horizontal span of the object. 1359d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param spanY Vertical span of the object. 1360d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param ignoreOccupied If true, the result can be an occupied cell 1361d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param result Array in which to place the result, or null (in which case a new array will 1362d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * be allocated) 1363d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @return The X, Y cell of a vacant area that can contain this object, 1364d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * nearest the requested location. 1365d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen */ 1366d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int[] findNearestArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, int spanY, 1367482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen View ignoreView, boolean ignoreOccupied, int[] result, int[] resultSpan, 1368482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean[][] occupied) { 1369d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen lazyInitTempRectStack(); 1370c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka // mark space take by ignoreView as available (method checks if ignoreView is null) 1371482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsAsUnoccupiedForView(ignoreView, occupied); 1372c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka 1373e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen // For items with a spanX / spanY > 1, the passed in point (pixelX, pixelY) corresponds 1374e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen // to the center of the item, but we are searching based on the top-left cell, so 1375e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen // we translate the point over to correspond to the top-left. 1376e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen pixelX -= (mCellWidth + mWidthGap) * (spanX - 1) / 2f; 1377e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen pixelY -= (mCellHeight + mHeightGap) * (spanY - 1) / 2f; 1378e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen 137970864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey // Keep track of best-scoring drop area 1380de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy final int[] bestXY = result != null ? result : new int[2]; 138170864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey double bestDistance = Double.MAX_VALUE; 1382d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen final Rect bestRect = new Rect(-1, -1, -1, -1); 1383d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen final Stack<Rect> validRegions = new Stack<Rect>(); 1384aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 1385de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy final int countX = mCountX; 1386de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy final int countY = mCountY; 1387de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy 1388d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (minSpanX <= 0 || minSpanY <= 0 || spanX <= 0 || spanY <= 0 || 1389d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen spanX < minSpanX || spanY < minSpanY) { 1390d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen return bestXY; 1391d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1392d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen 1393d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen for (int y = 0; y < countY - (minSpanY - 1); y++) { 1394c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka inner: 1395d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen for (int x = 0; x < countX - (minSpanX - 1); x++) { 1396d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int ySize = -1; 1397d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int xSize = -1; 1398df0353815c629fc678824b07a234b89a1ff94208Adam Cohen if (ignoreOccupied) { 1399d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // First, let's see if this thing fits anywhere 1400d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen for (int i = 0; i < minSpanX; i++) { 1401d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen for (int j = 0; j < minSpanY; j++) { 1402df0353815c629fc678824b07a234b89a1ff94208Adam Cohen if (occupied[x + i][y + j]) { 1403df0353815c629fc678824b07a234b89a1ff94208Adam Cohen continue inner; 1404df0353815c629fc678824b07a234b89a1ff94208Adam Cohen } 1405c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka } 1406c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka } 1407d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen xSize = minSpanX; 1408d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen ySize = minSpanY; 1409d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen 1410d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // We know that the item will fit at _some_ acceptable size, now let's see 1411d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // how big we can make it. We'll alternate between incrementing x and y spans 1412d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // until we hit a limit. 1413d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen boolean incX = true; 1414d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen boolean hitMaxX = xSize >= spanX; 1415d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen boolean hitMaxY = ySize >= spanY; 1416d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen while (!(hitMaxX && hitMaxY)) { 1417d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (incX && !hitMaxX) { 1418d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen for (int j = 0; j < ySize; j++) { 1419d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (x + xSize > countX -1 || occupied[x + xSize][y + j]) { 1420d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // We can't move out horizontally 1421d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen hitMaxX = true; 1422d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1423d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1424d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (!hitMaxX) { 1425d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen xSize++; 1426d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1427d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } else if (!hitMaxY) { 1428d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen for (int i = 0; i < xSize; i++) { 1429d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (y + ySize > countY - 1 || occupied[x + i][y + ySize]) { 1430d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // We can't move out vertically 1431d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen hitMaxY = true; 1432d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1433d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1434d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (!hitMaxY) { 1435d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen ySize++; 1436d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1437d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1438d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen hitMaxX |= xSize >= spanX; 1439d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen hitMaxY |= ySize >= spanY; 1440d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen incX = !incX; 1441d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1442d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen incX = true; 1443d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen hitMaxX = xSize >= spanX; 1444d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen hitMaxY = ySize >= spanY; 1445c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka } 14460be025d64c1f84138fe430a58875886e66aae767Winson Chung final int[] cellXY = mTmpXY; 1447e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen cellToCenterPoint(x, y, cellXY); 1448c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka 1449d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // We verify that the current rect is not a sub-rect of any of our previous 1450d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // candidates. In this case, the current rect is disqualified in favour of the 1451d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // containing rect. 1452d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen Rect currentRect = mTempRectStack.pop(); 1453d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen currentRect.set(x, y, x + xSize, y + ySize); 1454d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen boolean contained = false; 1455d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen for (Rect r : validRegions) { 1456d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (r.contains(currentRect)) { 1457d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen contained = true; 1458d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen break; 1459d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1460d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1461d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen validRegions.push(currentRect); 1462c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka double distance = Math.sqrt(Math.pow(cellXY[0] - pixelX, 2) 1463c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka + Math.pow(cellXY[1] - pixelY, 2)); 1464482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1465d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if ((distance <= bestDistance && !contained) || 1466d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen currentRect.contains(bestRect)) { 1467c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka bestDistance = distance; 1468c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka bestXY[0] = x; 1469c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka bestXY[1] = y; 1470d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (resultSpan != null) { 1471d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen resultSpan[0] = xSize; 1472d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen resultSpan[1] = ySize; 1473d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1474d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen bestRect.set(currentRect); 1475c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka } 147631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 147731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 1478c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka // re-mark space taken by ignoreView as occupied 1479482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsAsOccupiedForView(ignoreView, occupied); 148031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 1481c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen // Return -1, -1 if no suitable location found 1482c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen if (bestDistance == Double.MAX_VALUE) { 1483c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen bestXY[0] = -1; 1484c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen bestXY[1] = -1; 148570864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey } 1486d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen recycleTempRects(validRegions); 1487c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen return bestXY; 148831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 1489aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 1490482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen /** 1491482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * Find a vacant area that will fit the given bounds nearest the requested 1492482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * cell location, and will also weigh in a suggested direction vector of the 1493482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * desired location. This method computers distance based on unit grid distances, 1494482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * not pixel distances. 1495482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * 149647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param cellX The X cell nearest to which you want to search for a vacant area. 149747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param cellY The Y cell nearest which you want to search for a vacant area. 1498482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * @param spanX Horizontal span of the object. 1499482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * @param spanY Vertical span of the object. 150047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param direction The favored direction in which the views should move from x, y 150147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param exactDirectionOnly If this parameter is true, then only solutions where the direction 150247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * matches exactly. Otherwise we find the best matching direction. 150347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param occoupied The array which represents which cells in the CellLayout are occupied 150447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param blockOccupied The array which represents which cells in the specified block (cellX, 150547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * cellY, spanX, spanY) are occupied. This is used when try to move a group of views. 1506482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * @param result Array in which to place the result, or null (in which case a new array will 1507482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * be allocated) 1508482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * @return The X, Y cell of a vacant area that can contain this object, 1509482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * nearest the requested location. 1510482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen */ 1511482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private int[] findNearestArea(int cellX, int cellY, int spanX, int spanY, int[] direction, 151247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean[][] occupied, boolean blockOccupied[][], int[] result) { 1513482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // Keep track of best-scoring drop area 1514482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int[] bestXY = result != null ? result : new int[2]; 1515482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen float bestDistance = Float.MAX_VALUE; 1516482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int bestDirectionScore = Integer.MIN_VALUE; 1517482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1518482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int countX = mCountX; 1519482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int countY = mCountY; 1520482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1521482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int y = 0; y < countY - (spanY - 1); y++) { 1522482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen inner: 1523482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int x = 0; x < countX - (spanX - 1); x++) { 1524482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // First, let's see if this thing fits anywhere 1525482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < spanX; i++) { 1526482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int j = 0; j < spanY; j++) { 152747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (occupied[x + i][y + j] && (blockOccupied == null || blockOccupied[i][j])) { 1528482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen continue inner; 1529482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1530482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1531482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1532482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1533482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen float distance = (float) 1534482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen Math.sqrt((x - cellX) * (x - cellX) + (y - cellY) * (y - cellY)); 1535482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int[] curDirection = mTmpPoint; 153647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen computeDirectionVector(x - cellX, y - cellY, curDirection); 153747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen // The direction score is just the dot product of the two candidate direction 153847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen // and that passed in. 1539482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int curDirectionScore = direction[0] * curDirection[0] + 1540482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen direction[1] * curDirection[1]; 154147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean exactDirectionOnly = false; 154247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean directionMatches = direction[0] == curDirection[0] && 154347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen direction[0] == curDirection[0]; 154447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if ((directionMatches || !exactDirectionOnly) && 154547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen Float.compare(distance, bestDistance) < 0 || (Float.compare(distance, 1546482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen bestDistance) == 0 && curDirectionScore > bestDirectionScore)) { 1547482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen bestDistance = distance; 1548482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen bestDirectionScore = curDirectionScore; 1549482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen bestXY[0] = x; 1550482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen bestXY[1] = y; 1551482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1552482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1553482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1554482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1555482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // Return -1, -1 if no suitable location found 1556482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (bestDistance == Float.MAX_VALUE) { 1557482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen bestXY[0] = -1; 1558482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen bestXY[1] = -1; 1559482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1560482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return bestXY; 1561482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1562482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 156347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen private int[] findNearestAreaInDirection(int cellX, int cellY, int spanX, int spanY, 156447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen int[] direction,boolean[][] occupied, 156547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean blockOccupied[][], int[] result) { 156647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen // Keep track of best-scoring drop area 156747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen final int[] bestXY = result != null ? result : new int[2]; 156847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen bestXY[0] = -1; 156947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen bestXY[1] = -1; 157047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen float bestDistance = Float.MAX_VALUE; 157147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 157247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen // We use this to march in a single direction 15735b53f29f809a0dad4a1e0717ba610ce737ee0f43Adam Cohen if ((direction[0] != 0 && direction[1] != 0) || 15745b53f29f809a0dad4a1e0717ba610ce737ee0f43Adam Cohen (direction[0] == 0 && direction[1] == 0)) { 157547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen return bestXY; 157647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 157747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 157847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen // This will only incrememnet one of x or y based on the assertion above 157947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen int x = cellX + direction[0]; 158047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen int y = cellY + direction[1]; 158147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen while (x >= 0 && x + spanX <= mCountX && y >= 0 && y + spanY <= mCountY) { 158247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 158347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean fail = false; 158447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen for (int i = 0; i < spanX; i++) { 158547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen for (int j = 0; j < spanY; j++) { 158647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (occupied[x + i][y + j] && (blockOccupied == null || blockOccupied[i][j])) { 158747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen fail = true; 158847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 158947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 159047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 159147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (!fail) { 159247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen float distance = (float) 159347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen Math.sqrt((x - cellX) * (x - cellX) + (y - cellY) * (y - cellY)); 159447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (Float.compare(distance, bestDistance) < 0) { 159547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen bestDistance = distance; 159647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen bestXY[0] = x; 159747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen bestXY[1] = y; 159847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 159947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 160047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen x += direction[0]; 160147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen y += direction[1]; 160247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 160347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen return bestXY; 160447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 160547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 1606482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private boolean addViewToTempLocation(View v, Rect rectOccupiedByPotentialDrop, 16078baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen int[] direction, ItemConfiguration currentState) { 16088baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = currentState.map.get(v); 1609482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean success = false; 16108baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, false); 1611482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsForRect(rectOccupiedByPotentialDrop, mTmpOccupied, true); 1612482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 16138baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen findNearestArea(c.x, c.y, c.spanX, c.spanY, direction, mTmpOccupied, null, mTempLocation); 1614482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1615482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (mTempLocation[0] >= 0 && mTempLocation[1] >= 0) { 16168baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen c.x = mTempLocation[0]; 16178baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen c.y = mTempLocation[1]; 1618482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen success = true; 1619482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1620482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 16218baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, true); 1622482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return success; 1623482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1624482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 162547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen // This method looks in the specified direction to see if there is an additional view 162647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen // immediately adjecent in that direction 162747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen private boolean addViewInDirection(ArrayList<View> views, Rect boundingRect, int[] direction, 162819f3792523fe2d55ea791a9286398a6120920690Adam Cohen boolean[][] occupied, View dragView, ItemConfiguration currentState) { 162947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean found = false; 163047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 1631a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka int childCount = mShortcutsAndWidgets.getChildCount(); 163247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen Rect r0 = new Rect(boundingRect); 163347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen Rect r1 = new Rect(); 163447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 163547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen int deltaX = 0; 163647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen int deltaY = 0; 163747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (direction[1] < 0) { 163847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen r0.set(r0.left, r0.top - 1, r0.right, r0.bottom); 163947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen deltaY = -1; 164047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } else if (direction[1] > 0) { 164147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen r0.set(r0.left, r0.top, r0.right, r0.bottom + 1); 164247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen deltaY = 1; 164347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } else if (direction[0] < 0) { 164447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen r0.set(r0.left - 1, r0.top, r0.right, r0.bottom); 164547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen deltaX = -1; 164647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } else if (direction[0] > 0) { 164747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen r0.set(r0.left, r0.top, r0.right + 1, r0.bottom); 164847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen deltaX = 1; 164947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 165047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 165147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen for (int i = 0; i < childCount; i++) { 1652a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka View child = mShortcutsAndWidgets.getChildAt(i); 165319f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (views.contains(child) || child == dragView) continue; 16548baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = currentState.map.get(child); 165547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 16568baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen LayoutParams lp = (LayoutParams) child.getLayoutParams(); 16578baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen r1.set(c.x, c.y, c.x + c.spanX, c.y + c.spanY); 165847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (Rect.intersects(r0, r1)) { 165947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (!lp.canReorder) { 166047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen return false; 166147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 166247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean pushed = false; 16638baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen for (int x = c.x; x < c.x + c.spanX; x++) { 16648baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen for (int y = c.y; y < c.y + c.spanY; y++) { 166547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean inBounds = x - deltaX >= 0 && x -deltaX < mCountX 166647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen && y - deltaY >= 0 && y - deltaY < mCountY; 166747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (inBounds && occupied[x - deltaX][y - deltaY]) { 166847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen pushed = true; 166947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 167047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 167147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 167247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (pushed) { 167347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen views.add(child); 16748baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen boundingRect.union(c.x, c.y, c.x + c.spanX, c.y + c.spanY); 167547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen found = true; 167647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 167747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 167847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 167947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen return found; 168047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 168147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 16828baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen private boolean addViewsToTempLocation(ArrayList<View> views, Rect rectOccupiedByPotentialDrop, 168319f3792523fe2d55ea791a9286398a6120920690Adam Cohen int[] direction, boolean push, View dragView, ItemConfiguration currentState) { 168447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (views.size() == 0) return true; 168547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 168647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean success = false; 168747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen Rect boundingRect = null; 16888baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // We construct a rect which represents the entire group of views passed in 168947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen for (View v: views) { 16908baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = currentState.map.get(v); 169147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (boundingRect == null) { 16928baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen boundingRect = new Rect(c.x, c.y, c.x + c.spanX, c.y + c.spanY); 169347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } else { 16948baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen boundingRect.union(c.x, c.y, c.x + c.spanX, c.y + c.spanY); 169547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 169647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 169747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 16988baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen @SuppressWarnings("unchecked") 169947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen ArrayList<View> dup = (ArrayList<View>) views.clone(); 17008baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // We try and expand the group of views in the direction vector passed, based on 17018baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // whether they are physically adjacent, ie. based on "push mechanics". 170219f3792523fe2d55ea791a9286398a6120920690Adam Cohen while (push && addViewInDirection(dup, boundingRect, direction, mTmpOccupied, dragView, 17038baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen currentState)) { 170447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 17058baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen 17068baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // Mark the occupied state as false for the group of views we want to move. 170747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen for (View v: dup) { 17088baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = currentState.map.get(v); 17098baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, false); 171047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 171147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 171247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean[][] blockOccupied = new boolean[boundingRect.width()][boundingRect.height()]; 171347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen int top = boundingRect.top; 171447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen int left = boundingRect.left; 17158baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // We mark more precisely which parts of the bounding rect are truly occupied, allowing 17168baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // for tetris-style interlocking. 171747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen for (View v: dup) { 17188baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = currentState.map.get(v); 17198baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen markCellsForView(c.x - left, c.y - top, c.spanX, c.spanY, blockOccupied, true); 172047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 172147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 172247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen markCellsForRect(rectOccupiedByPotentialDrop, mTmpOccupied, true); 172347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 17248baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen if (push) { 17258baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen findNearestAreaInDirection(boundingRect.left, boundingRect.top, boundingRect.width(), 17268baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen boundingRect.height(), direction, mTmpOccupied, blockOccupied, mTempLocation); 17278baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen } else { 17288baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen findNearestArea(boundingRect.left, boundingRect.top, boundingRect.width(), 17298baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen boundingRect.height(), direction, mTmpOccupied, blockOccupied, mTempLocation); 17308baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen } 173147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 17328baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // If we successfuly found a location by pushing the block of views, we commit it 173347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (mTempLocation[0] >= 0 && mTempLocation[1] >= 0) { 17348baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen int deltaX = mTempLocation[0] - boundingRect.left; 17358baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen int deltaY = mTempLocation[1] - boundingRect.top; 173647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen for (View v: dup) { 17378baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = currentState.map.get(v); 17388baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen c.x += deltaX; 17398baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen c.y += deltaY; 174047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 174147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen success = true; 174247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 1743482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 17448baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // In either case, we set the occupied array as marked for the location of the views 17458baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen for (View v: dup) { 17468baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = currentState.map.get(v); 17478baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, true); 1748482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1749482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return success; 1750482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1751482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1752482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private void markCellsForRect(Rect r, boolean[][] occupied, boolean value) { 1753482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsForView(r.left, r.top, r.width(), r.height(), occupied, value); 1754482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1755482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1756482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private boolean rearrangementExists(int cellX, int cellY, int spanX, int spanY, int[] direction, 17578baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen View ignoreView, ItemConfiguration solution) { 1758482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 17598baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen mIntersectingViews.clear(); 1760482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mOccupiedRect.set(cellX, cellY, cellX + spanX, cellY + spanY); 1761482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 17628baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // Mark the desired location of the view currently being dragged. 1763482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (ignoreView != null) { 17648baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = solution.map.get(ignoreView); 176519f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (c != null) { 176619f3792523fe2d55ea791a9286398a6120920690Adam Cohen c.x = cellX; 176719f3792523fe2d55ea791a9286398a6120920690Adam Cohen c.y = cellY; 176819f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 1769482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1770482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen Rect r0 = new Rect(cellX, cellY, cellX + spanX, cellY + spanY); 1771482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen Rect r1 = new Rect(); 17728baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen for (View child: solution.map.keySet()) { 1773482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (child == ignoreView) continue; 17748baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = solution.map.get(child); 1775482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen LayoutParams lp = (LayoutParams) child.getLayoutParams(); 17768baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen r1.set(c.x, c.y, c.x + c.spanX, c.y + c.spanY); 1777482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (Rect.intersects(r0, r1)) { 1778482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (!lp.canReorder) { 1779482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return false; 1780482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1781482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mIntersectingViews.add(child); 1782482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1783482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 178447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 17858baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // We try to move the intersecting views as a block using the push mechanic 178619f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (addViewsToTempLocation(mIntersectingViews, mOccupiedRect, direction, true, ignoreView, 178719f3792523fe2d55ea791a9286398a6120920690Adam Cohen solution)) { 178847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen return true; 178947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 179047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen // Try the opposite direction 179147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen direction[0] *= -1; 179247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen direction[1] *= -1; 179319f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (addViewsToTempLocation(mIntersectingViews, mOccupiedRect, direction, true, ignoreView, 179419f3792523fe2d55ea791a9286398a6120920690Adam Cohen solution)) { 179547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen return true; 179647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 179747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen // Switch the direction back 179847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen direction[0] *= -1; 179947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen direction[1] *= -1; 180047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 18018baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // Next we try moving the views as a block , but without requiring the push mechanic 180219f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (addViewsToTempLocation(mIntersectingViews, mOccupiedRect, direction, false, ignoreView, 180319f3792523fe2d55ea791a9286398a6120920690Adam Cohen solution)) { 1804482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return true; 1805482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 180647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 1807482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // Ok, they couldn't move as a block, let's move them individually 1808482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (View v : mIntersectingViews) { 18098baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen if (!addViewToTempLocation(v, mOccupiedRect, direction, solution)) { 1810482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return false; 1811482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1812482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1813482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return true; 1814482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1815482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1816482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen /* 1817482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * Returns a pair (x, y), where x,y are in {-1, 0, 1} corresponding to vector between 1818482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * the provided point and the provided cell 1819482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen */ 182047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen private void computeDirectionVector(float deltaX, float deltaY, int[] result) { 1821482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen double angle = Math.atan(((float) deltaY) / deltaX); 1822482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1823482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result[0] = 0; 1824482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result[1] = 0; 1825482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (Math.abs(Math.cos(angle)) > 0.5f) { 1826482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result[0] = (int) Math.signum(deltaX); 1827482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1828482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (Math.abs(Math.sin(angle)) > 0.5f) { 1829482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result[1] = (int) Math.signum(deltaY); 1830482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1831482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1832482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 18338baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen private void copyOccupiedArray(boolean[][] occupied) { 18348baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen for (int i = 0; i < mCountX; i++) { 18358baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen for (int j = 0; j < mCountY; j++) { 18368baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen occupied[i][j] = mOccupied[i][j]; 18378baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen } 18388baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen } 18398baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen } 18408baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen 1841482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen ItemConfiguration simpleSwap(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, 1842482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int spanY, int[] direction, View dragView, boolean decX, ItemConfiguration solution) { 18438baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // Copy the current state into the solution. This solution will be manipulated as necessary. 18448baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen copyCurrentStateToSolution(solution, false); 18458baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // Copy the current occupied array into the temporary occupied array. This array will be 18468baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // manipulated as necessary to find a solution. 18478baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen copyOccupiedArray(mTmpOccupied); 1848482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1849482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // We find the nearest cell into which we would place the dragged item, assuming there's 1850482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // nothing in its way. 1851482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int result[] = new int[2]; 1852482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result = findNearestArea(pixelX, pixelY, spanX, spanY, result); 1853482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1854482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean success = false; 1855482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // First we try the exact nearest position of the item being dragged, 1856482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // we will then want to try to move this around to other neighbouring positions 18578baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen success = rearrangementExists(result[0], result[1], spanX, spanY, direction, dragView, 18588baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen solution); 1859482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1860482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (!success) { 1861482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // We try shrinking the widget down to size in an alternating pattern, shrink 1 in 1862482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // x, then 1 in y etc. 1863482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (spanX > minSpanX && (minSpanY == spanY || decX)) { 1864482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return simpleSwap(pixelX, pixelY, minSpanX, minSpanY, spanX - 1, spanY, direction, 1865482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen dragView, false, solution); 1866482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } else if (spanY > minSpanY) { 1867482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return simpleSwap(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY - 1, direction, 1868482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen dragView, true, solution); 1869482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1870482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.isSolution = false; 1871482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } else { 1872482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.isSolution = true; 1873482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewX = result[0]; 1874482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewY = result[1]; 1875482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewSpanX = spanX; 1876482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewSpanY = spanY; 1877482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1878482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return solution; 1879482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1880482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1881482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private void copyCurrentStateToSolution(ItemConfiguration solution, boolean temp) { 1882a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka int childCount = mShortcutsAndWidgets.getChildCount(); 1883482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < childCount; i++) { 1884a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka View child = mShortcutsAndWidgets.getChildAt(i); 1885482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen LayoutParams lp = (LayoutParams) child.getLayoutParams(); 18868baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c; 1887482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (temp) { 18888baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen c = new CellAndSpan(lp.tmpCellX, lp.tmpCellY, lp.cellHSpan, lp.cellVSpan); 1889482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } else { 18908baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen c = new CellAndSpan(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan); 1891482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 18928baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen solution.map.put(child, c); 1893482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1894482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1895482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1896482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private void copySolutionToTempState(ItemConfiguration solution, View dragView) { 1897482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < mCountX; i++) { 1898482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int j = 0; j < mCountY; j++) { 1899482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mTmpOccupied[i][j] = false; 1900482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1901482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1902482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1903a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka int childCount = mShortcutsAndWidgets.getChildCount(); 1904482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < childCount; i++) { 1905a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka View child = mShortcutsAndWidgets.getChildAt(i); 1906482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (child == dragView) continue; 1907482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen LayoutParams lp = (LayoutParams) child.getLayoutParams(); 19088baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = solution.map.get(child); 19098baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen if (c != null) { 19108baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen lp.tmpCellX = c.x; 19118baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen lp.tmpCellY = c.y; 19128baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen lp.cellHSpan = c.spanX; 19138baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen lp.cellVSpan = c.spanY; 19148baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, true); 1915482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1916482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1917482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsForView(solution.dragViewX, solution.dragViewY, solution.dragViewSpanX, 1918482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewSpanY, mTmpOccupied, true); 1919482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1920482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1921482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private void animateItemsToSolution(ItemConfiguration solution, View dragView, boolean 1922482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen commitDragView) { 1923482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1924482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean[][] occupied = DESTRUCTIVE_REORDER ? mOccupied : mTmpOccupied; 1925482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < mCountX; i++) { 1926482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int j = 0; j < mCountY; j++) { 1927482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen occupied[i][j] = false; 1928482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1929482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1930482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1931a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka int childCount = mShortcutsAndWidgets.getChildCount(); 1932482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < childCount; i++) { 1933a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka View child = mShortcutsAndWidgets.getChildAt(i); 1934482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (child == dragView) continue; 19358baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = solution.map.get(child); 19368baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen if (c != null) { 193719f3792523fe2d55ea791a9286398a6120920690Adam Cohen animateChildToPosition(child, c.x, c.y, REORDER_ANIMATION_DURATION, 0, 193819f3792523fe2d55ea791a9286398a6120920690Adam Cohen DESTRUCTIVE_REORDER, false); 19398baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen markCellsForView(c.x, c.y, c.spanX, c.spanY, occupied, true); 1940482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1941482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1942482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (commitDragView) { 1943482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsForView(solution.dragViewX, solution.dragViewY, solution.dragViewSpanX, 1944482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewSpanY, occupied, true); 1945482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1946482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1947482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 194819f3792523fe2d55ea791a9286398a6120920690Adam Cohen // This method starts or changes the reorder hint animations 194919f3792523fe2d55ea791a9286398a6120920690Adam Cohen private void beginOrAdjustHintAnimations(ItemConfiguration solution, View dragView, int delay) { 195019f3792523fe2d55ea791a9286398a6120920690Adam Cohen int childCount = mShortcutsAndWidgets.getChildCount(); 195119f3792523fe2d55ea791a9286398a6120920690Adam Cohen int timeForPriorAnimationToComplete = getMaxCompletionTime(); 195219f3792523fe2d55ea791a9286398a6120920690Adam Cohen for (int i = 0; i < childCount; i++) { 195319f3792523fe2d55ea791a9286398a6120920690Adam Cohen View child = mShortcutsAndWidgets.getChildAt(i); 195419f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (child == dragView) continue; 195519f3792523fe2d55ea791a9286398a6120920690Adam Cohen CellAndSpan c = solution.map.get(child); 195619f3792523fe2d55ea791a9286398a6120920690Adam Cohen LayoutParams lp = (LayoutParams) child.getLayoutParams(); 195719f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (c != null) { 195819f3792523fe2d55ea791a9286398a6120920690Adam Cohen ReorderHintAnimation rha = new ReorderHintAnimation(child, lp.cellX, lp.cellY, 195919f3792523fe2d55ea791a9286398a6120920690Adam Cohen c.x, c.y, c.spanX, c.spanY); 196019f3792523fe2d55ea791a9286398a6120920690Adam Cohen rha.animate(timeForPriorAnimationToComplete); 196119f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 196219f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 196319f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 196419f3792523fe2d55ea791a9286398a6120920690Adam Cohen 196519f3792523fe2d55ea791a9286398a6120920690Adam Cohen // Class which represents the reorder hint animations. These animations show that an item is 196619f3792523fe2d55ea791a9286398a6120920690Adam Cohen // in a temporary state, and hint at where the item will return to. 196719f3792523fe2d55ea791a9286398a6120920690Adam Cohen class ReorderHintAnimation { 196819f3792523fe2d55ea791a9286398a6120920690Adam Cohen View child; 196919f3792523fe2d55ea791a9286398a6120920690Adam Cohen float deltaX; 197019f3792523fe2d55ea791a9286398a6120920690Adam Cohen float deltaY; 197119f3792523fe2d55ea791a9286398a6120920690Adam Cohen private static final int DURATION = 140; 197219f3792523fe2d55ea791a9286398a6120920690Adam Cohen private int repeatCount; 197319f3792523fe2d55ea791a9286398a6120920690Adam Cohen private boolean cancelOnCycleComplete = false; 197419f3792523fe2d55ea791a9286398a6120920690Adam Cohen ValueAnimator va; 197519f3792523fe2d55ea791a9286398a6120920690Adam Cohen 197619f3792523fe2d55ea791a9286398a6120920690Adam Cohen public ReorderHintAnimation(View child, int cellX0, int cellY0, int cellX1, int cellY1, 197719f3792523fe2d55ea791a9286398a6120920690Adam Cohen int spanX, int spanY) { 197819f3792523fe2d55ea791a9286398a6120920690Adam Cohen regionToCenterPoint(cellX0, cellY0, spanX, spanY, mTmpPoint); 197919f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int x0 = mTmpPoint[0]; 198019f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int y0 = mTmpPoint[1]; 198119f3792523fe2d55ea791a9286398a6120920690Adam Cohen regionToCenterPoint(cellX1, cellY1, spanX, spanY, mTmpPoint); 198219f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int x1 = mTmpPoint[0]; 198319f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int y1 = mTmpPoint[1]; 198419f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int dX = x1 - x0; 198519f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int dY = y1 - y0; 198619f3792523fe2d55ea791a9286398a6120920690Adam Cohen deltaX = 0; 198719f3792523fe2d55ea791a9286398a6120920690Adam Cohen deltaY = 0; 198819f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (dX == dY && dX == 0) { 198919f3792523fe2d55ea791a9286398a6120920690Adam Cohen } else { 199019f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (dY == 0) { 199119f3792523fe2d55ea791a9286398a6120920690Adam Cohen deltaX = mReorderHintAnimationMagnitude; 199219f3792523fe2d55ea791a9286398a6120920690Adam Cohen } else if (dX == 0) { 199319f3792523fe2d55ea791a9286398a6120920690Adam Cohen deltaY = mReorderHintAnimationMagnitude; 199419f3792523fe2d55ea791a9286398a6120920690Adam Cohen } else { 199519f3792523fe2d55ea791a9286398a6120920690Adam Cohen double angle = Math.atan( (float) (dY) / dX); 199619f3792523fe2d55ea791a9286398a6120920690Adam Cohen deltaX = (int) (Math.cos(angle) * mReorderHintAnimationMagnitude); 199719f3792523fe2d55ea791a9286398a6120920690Adam Cohen deltaY = (int) (Math.sin(angle) * mReorderHintAnimationMagnitude); 199819f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 199919f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 200019f3792523fe2d55ea791a9286398a6120920690Adam Cohen this.child = child; 200119f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 200219f3792523fe2d55ea791a9286398a6120920690Adam Cohen 200319f3792523fe2d55ea791a9286398a6120920690Adam Cohen void animate(int delay) { 200419f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (mShakeAnimators.containsKey(child)) { 200519f3792523fe2d55ea791a9286398a6120920690Adam Cohen ReorderHintAnimation oldAnimation = mShakeAnimators.get(child); 200619f3792523fe2d55ea791a9286398a6120920690Adam Cohen oldAnimation.completeAnimation(); 200719f3792523fe2d55ea791a9286398a6120920690Adam Cohen mShakeAnimators.remove(child); 200819f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 200919f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (deltaX == 0 && deltaY == 0) { 201019f3792523fe2d55ea791a9286398a6120920690Adam Cohen return; 201119f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 201219f3792523fe2d55ea791a9286398a6120920690Adam Cohen va = ValueAnimator.ofFloat(0f, 1f); 201319f3792523fe2d55ea791a9286398a6120920690Adam Cohen va.setRepeatMode(ValueAnimator.REVERSE); 201419f3792523fe2d55ea791a9286398a6120920690Adam Cohen va.setRepeatCount(ValueAnimator.INFINITE); 201519f3792523fe2d55ea791a9286398a6120920690Adam Cohen va.setDuration(DURATION); 201619f3792523fe2d55ea791a9286398a6120920690Adam Cohen va.addUpdateListener(new AnimatorUpdateListener() { 201719f3792523fe2d55ea791a9286398a6120920690Adam Cohen @Override 201819f3792523fe2d55ea791a9286398a6120920690Adam Cohen public void onAnimationUpdate(ValueAnimator animation) { 201919f3792523fe2d55ea791a9286398a6120920690Adam Cohen float r = ((Float) animation.getAnimatedValue()).floatValue(); 202019f3792523fe2d55ea791a9286398a6120920690Adam Cohen float x = r * deltaX; 202119f3792523fe2d55ea791a9286398a6120920690Adam Cohen float y = r * deltaY; 202219f3792523fe2d55ea791a9286398a6120920690Adam Cohen child.setTranslationX(x); 202319f3792523fe2d55ea791a9286398a6120920690Adam Cohen child.setTranslationY(y); 202419f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 202519f3792523fe2d55ea791a9286398a6120920690Adam Cohen }); 202619f3792523fe2d55ea791a9286398a6120920690Adam Cohen va.addListener(new AnimatorListenerAdapter() { 202719f3792523fe2d55ea791a9286398a6120920690Adam Cohen public void onAnimationRepeat(Animator animation) { 202819f3792523fe2d55ea791a9286398a6120920690Adam Cohen repeatCount++; 202919f3792523fe2d55ea791a9286398a6120920690Adam Cohen // We make sure to end only after a full period 203019f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (cancelOnCycleComplete && repeatCount % 2 == 0) { 203119f3792523fe2d55ea791a9286398a6120920690Adam Cohen va.cancel(); 203219f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 203319f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 203419f3792523fe2d55ea791a9286398a6120920690Adam Cohen }); 203519f3792523fe2d55ea791a9286398a6120920690Adam Cohen va.setStartDelay(Math.max(REORDER_ANIMATION_DURATION, delay)); 203619f3792523fe2d55ea791a9286398a6120920690Adam Cohen mShakeAnimators.put(child, this); 203719f3792523fe2d55ea791a9286398a6120920690Adam Cohen va.start(); 203819f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 203919f3792523fe2d55ea791a9286398a6120920690Adam Cohen 204019f3792523fe2d55ea791a9286398a6120920690Adam Cohen 204119f3792523fe2d55ea791a9286398a6120920690Adam Cohen private void completeAnimation() { 204219f3792523fe2d55ea791a9286398a6120920690Adam Cohen cancelOnCycleComplete = true; 204319f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 204419f3792523fe2d55ea791a9286398a6120920690Adam Cohen 204519f3792523fe2d55ea791a9286398a6120920690Adam Cohen // Returns the time required to complete the current oscillating animation 204619f3792523fe2d55ea791a9286398a6120920690Adam Cohen private int completionTime() { 204719f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (repeatCount % 2 == 0) { 204819f3792523fe2d55ea791a9286398a6120920690Adam Cohen return (int) (va.getDuration() - va.getCurrentPlayTime() + DURATION); 204919f3792523fe2d55ea791a9286398a6120920690Adam Cohen } else { 205019f3792523fe2d55ea791a9286398a6120920690Adam Cohen return (int) (va.getDuration() - va.getCurrentPlayTime()); 205119f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 205219f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 205319f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 205419f3792523fe2d55ea791a9286398a6120920690Adam Cohen 205519f3792523fe2d55ea791a9286398a6120920690Adam Cohen private void completeAndClearReorderHintAnimations() { 205619f3792523fe2d55ea791a9286398a6120920690Adam Cohen for (ReorderHintAnimation a: mShakeAnimators.values()) { 205719f3792523fe2d55ea791a9286398a6120920690Adam Cohen a.completeAnimation(); 205819f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 205919f3792523fe2d55ea791a9286398a6120920690Adam Cohen mShakeAnimators.clear(); 206019f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 206119f3792523fe2d55ea791a9286398a6120920690Adam Cohen 206219f3792523fe2d55ea791a9286398a6120920690Adam Cohen private int getMaxCompletionTime() { 206319f3792523fe2d55ea791a9286398a6120920690Adam Cohen int maxTime = 0; 206419f3792523fe2d55ea791a9286398a6120920690Adam Cohen for (ReorderHintAnimation a: mShakeAnimators.values()) { 206519f3792523fe2d55ea791a9286398a6120920690Adam Cohen maxTime = Math.max(maxTime, a.completionTime()); 206619f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 206719f3792523fe2d55ea791a9286398a6120920690Adam Cohen return maxTime; 206819f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 206919f3792523fe2d55ea791a9286398a6120920690Adam Cohen 2070482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private void commitTempPlacement() { 2071482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < mCountX; i++) { 2072482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int j = 0; j < mCountY; j++) { 2073482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mOccupied[i][j] = mTmpOccupied[i][j]; 2074482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2075482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2076a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka int childCount = mShortcutsAndWidgets.getChildCount(); 2077482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < childCount; i++) { 2078ea889a294be004f4b1c21e9b874f9e63abfb8bd6Adam Cohen View child = mShortcutsAndWidgets.getChildAt(i); 2079ea889a294be004f4b1c21e9b874f9e63abfb8bd6Adam Cohen LayoutParams lp = (LayoutParams) child.getLayoutParams(); 2080ea889a294be004f4b1c21e9b874f9e63abfb8bd6Adam Cohen ItemInfo info = (ItemInfo) child.getTag(); 20812acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen // We do a null check here because the item info can be null in the case of the 20822acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen // AllApps button in the hotseat. 20832acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen if (info != null) { 20842acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen info.cellX = lp.cellX = lp.tmpCellX; 20852acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen info.cellY = lp.cellY = lp.tmpCellY; 2086bebf042666cffe52039b875a549a582abd78a431Adam Cohen info.spanX = lp.cellHSpan; 2087bebf042666cffe52039b875a549a582abd78a431Adam Cohen info.spanY = lp.cellVSpan; 20882acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen } 2089482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 20902acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen mLauncher.getWorkspace().updateItemLocationsInDatabase(this); 2091482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2092482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2093482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public void setUseTempCoords(boolean useTempCoords) { 2094a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka int childCount = mShortcutsAndWidgets.getChildCount(); 2095482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < childCount; i++) { 2096a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka LayoutParams lp = (LayoutParams) mShortcutsAndWidgets.getChildAt(i).getLayoutParams(); 2097482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen lp.useTmpCoords = useTempCoords; 2098482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2099482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2100482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2101482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen ItemConfiguration findConfigurationNoShuffle(int pixelX, int pixelY, int minSpanX, int minSpanY, 2102482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int spanX, int spanY, View dragView, ItemConfiguration solution) { 2103482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int[] result = new int[2]; 2104482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int[] resultSpan = new int[2]; 2105482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen findNearestVacantArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, null, result, 2106482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen resultSpan); 2107482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (result[0] >= 0 && result[1] >= 0) { 2108482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen copyCurrentStateToSolution(solution, false); 2109482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewX = result[0]; 2110482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewY = result[1]; 2111482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewSpanX = resultSpan[0]; 2112482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewSpanY = resultSpan[1]; 2113482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.isSolution = true; 2114482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } else { 2115482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.isSolution = false; 2116482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2117482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return solution; 2118482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2119482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2120482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public void prepareChildForDrag(View child) { 2121482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsAsUnoccupiedForView(child); 2122482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2123482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 212419f3792523fe2d55ea791a9286398a6120920690Adam Cohen /* This seems like it should be obvious and straight-forward, but when the direction vector 212519f3792523fe2d55ea791a9286398a6120920690Adam Cohen needs to match with the notion of the dragView pushing other views, we have to employ 212619f3792523fe2d55ea791a9286398a6120920690Adam Cohen a slightly more subtle notion of the direction vector. The question is what two points is 212719f3792523fe2d55ea791a9286398a6120920690Adam Cohen the vector between? The center of the dragView and its desired destination? Not quite, as 212819f3792523fe2d55ea791a9286398a6120920690Adam Cohen this doesn't necessarily coincide with the interaction of the dragView and items occupying 212919f3792523fe2d55ea791a9286398a6120920690Adam Cohen those cells. Instead we use some heuristics to often lock the vector to up, down, left 213019f3792523fe2d55ea791a9286398a6120920690Adam Cohen or right, which helps make pushing feel right. 213119f3792523fe2d55ea791a9286398a6120920690Adam Cohen */ 213219f3792523fe2d55ea791a9286398a6120920690Adam Cohen private void getDirectionVectorForDrop(int dragViewCenterX, int dragViewCenterY, int spanX, 213319f3792523fe2d55ea791a9286398a6120920690Adam Cohen int spanY, View dragView, int[] resultDirection) { 213419f3792523fe2d55ea791a9286398a6120920690Adam Cohen int[] targetDestination = new int[2]; 213519f3792523fe2d55ea791a9286398a6120920690Adam Cohen 213619f3792523fe2d55ea791a9286398a6120920690Adam Cohen findNearestArea(dragViewCenterX, dragViewCenterY, spanX, spanY, targetDestination); 213719f3792523fe2d55ea791a9286398a6120920690Adam Cohen Rect dragRect = new Rect(); 213819f3792523fe2d55ea791a9286398a6120920690Adam Cohen regionToRect(targetDestination[0], targetDestination[1], spanX, spanY, dragRect); 213919f3792523fe2d55ea791a9286398a6120920690Adam Cohen dragRect.offset(dragViewCenterX - dragRect.centerX(), dragViewCenterY - dragRect.centerY()); 214019f3792523fe2d55ea791a9286398a6120920690Adam Cohen 214119f3792523fe2d55ea791a9286398a6120920690Adam Cohen Rect dropRegionRect = new Rect(); 214219f3792523fe2d55ea791a9286398a6120920690Adam Cohen getViewsIntersectingRegion(targetDestination[0], targetDestination[1], spanX, spanY, 214319f3792523fe2d55ea791a9286398a6120920690Adam Cohen dragView, dropRegionRect, mIntersectingViews); 214419f3792523fe2d55ea791a9286398a6120920690Adam Cohen 214519f3792523fe2d55ea791a9286398a6120920690Adam Cohen int dropRegionSpanX = dropRegionRect.width(); 214619f3792523fe2d55ea791a9286398a6120920690Adam Cohen int dropRegionSpanY = dropRegionRect.height(); 214719f3792523fe2d55ea791a9286398a6120920690Adam Cohen 214819f3792523fe2d55ea791a9286398a6120920690Adam Cohen regionToRect(dropRegionRect.left, dropRegionRect.top, dropRegionRect.width(), 214919f3792523fe2d55ea791a9286398a6120920690Adam Cohen dropRegionRect.height(), dropRegionRect); 215019f3792523fe2d55ea791a9286398a6120920690Adam Cohen 215119f3792523fe2d55ea791a9286398a6120920690Adam Cohen int deltaX = (dropRegionRect.centerX() - dragViewCenterX) / spanX; 215219f3792523fe2d55ea791a9286398a6120920690Adam Cohen int deltaY = (dropRegionRect.centerY() - dragViewCenterY) / spanY; 215319f3792523fe2d55ea791a9286398a6120920690Adam Cohen 215419f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (dropRegionSpanX == mCountX || spanX == mCountX) { 215519f3792523fe2d55ea791a9286398a6120920690Adam Cohen deltaX = 0; 215619f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 215719f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (dropRegionSpanY == mCountY || spanY == mCountY) { 215819f3792523fe2d55ea791a9286398a6120920690Adam Cohen deltaY = 0; 215919f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 216019f3792523fe2d55ea791a9286398a6120920690Adam Cohen 216119f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (deltaX == 0 && deltaY == 0) { 216219f3792523fe2d55ea791a9286398a6120920690Adam Cohen // No idea what to do, give a random direction. 216319f3792523fe2d55ea791a9286398a6120920690Adam Cohen resultDirection[0] = 1; 216419f3792523fe2d55ea791a9286398a6120920690Adam Cohen resultDirection[1] = 0; 216519f3792523fe2d55ea791a9286398a6120920690Adam Cohen } else { 216619f3792523fe2d55ea791a9286398a6120920690Adam Cohen computeDirectionVector(deltaX, deltaY, resultDirection); 216719f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 216819f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 216919f3792523fe2d55ea791a9286398a6120920690Adam Cohen 217019f3792523fe2d55ea791a9286398a6120920690Adam Cohen // For a given cell and span, fetch the set of views intersecting the region. 217119f3792523fe2d55ea791a9286398a6120920690Adam Cohen private void getViewsIntersectingRegion(int cellX, int cellY, int spanX, int spanY, 217219f3792523fe2d55ea791a9286398a6120920690Adam Cohen View dragView, Rect boundingRect, ArrayList<View> intersectingViews) { 217319f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (boundingRect != null) { 217419f3792523fe2d55ea791a9286398a6120920690Adam Cohen boundingRect.set(cellX, cellY, cellX + spanX, cellY + spanY); 217519f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 217619f3792523fe2d55ea791a9286398a6120920690Adam Cohen intersectingViews.clear(); 217719f3792523fe2d55ea791a9286398a6120920690Adam Cohen Rect r0 = new Rect(cellX, cellY, cellX + spanX, cellY + spanY); 217819f3792523fe2d55ea791a9286398a6120920690Adam Cohen Rect r1 = new Rect(); 217919f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int count = mShortcutsAndWidgets.getChildCount(); 218019f3792523fe2d55ea791a9286398a6120920690Adam Cohen for (int i = 0; i < count; i++) { 218119f3792523fe2d55ea791a9286398a6120920690Adam Cohen View child = mShortcutsAndWidgets.getChildAt(i); 218219f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (child == dragView) continue; 218319f3792523fe2d55ea791a9286398a6120920690Adam Cohen LayoutParams lp = (LayoutParams) child.getLayoutParams(); 218419f3792523fe2d55ea791a9286398a6120920690Adam Cohen r1.set(lp.cellX, lp.cellY, lp.cellX + lp.cellHSpan, lp.cellY + lp.cellVSpan); 218519f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (Rect.intersects(r0, r1)) { 218619f3792523fe2d55ea791a9286398a6120920690Adam Cohen mIntersectingViews.add(child); 218719f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (boundingRect != null) { 218819f3792523fe2d55ea791a9286398a6120920690Adam Cohen boundingRect.union(r1); 218919f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 219019f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 219119f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 219219f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 219319f3792523fe2d55ea791a9286398a6120920690Adam Cohen 219419f3792523fe2d55ea791a9286398a6120920690Adam Cohen boolean isNearestDropLocationOccupied(int pixelX, int pixelY, int spanX, int spanY, 219519f3792523fe2d55ea791a9286398a6120920690Adam Cohen View dragView, int[] result) { 219619f3792523fe2d55ea791a9286398a6120920690Adam Cohen result = findNearestArea(pixelX, pixelY, spanX, spanY, result); 219719f3792523fe2d55ea791a9286398a6120920690Adam Cohen getViewsIntersectingRegion(result[0], result[1], spanX, spanY, dragView, null, 219819f3792523fe2d55ea791a9286398a6120920690Adam Cohen mIntersectingViews); 219919f3792523fe2d55ea791a9286398a6120920690Adam Cohen return !mIntersectingViews.isEmpty(); 220019f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 220119f3792523fe2d55ea791a9286398a6120920690Adam Cohen 220219f3792523fe2d55ea791a9286398a6120920690Adam Cohen void revertTempState() { 220319f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (!isItemPlacementDirty() || DESTRUCTIVE_REORDER) return; 220419f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int count = mShortcutsAndWidgets.getChildCount(); 220519f3792523fe2d55ea791a9286398a6120920690Adam Cohen for (int i = 0; i < count; i++) { 220619f3792523fe2d55ea791a9286398a6120920690Adam Cohen View child = mShortcutsAndWidgets.getChildAt(i); 220719f3792523fe2d55ea791a9286398a6120920690Adam Cohen LayoutParams lp = (LayoutParams) child.getLayoutParams(); 220819f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (lp.tmpCellX != lp.cellX || lp.tmpCellY != lp.cellY) { 220919f3792523fe2d55ea791a9286398a6120920690Adam Cohen lp.tmpCellX = lp.cellX; 221019f3792523fe2d55ea791a9286398a6120920690Adam Cohen lp.tmpCellY = lp.cellY; 221119f3792523fe2d55ea791a9286398a6120920690Adam Cohen animateChildToPosition(child, lp.cellX, lp.cellY, REORDER_ANIMATION_DURATION, 221219f3792523fe2d55ea791a9286398a6120920690Adam Cohen 0, false, false); 221319f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 221419f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 221519f3792523fe2d55ea791a9286398a6120920690Adam Cohen completeAndClearReorderHintAnimations(); 221619f3792523fe2d55ea791a9286398a6120920690Adam Cohen setItemPlacementDirty(false); 221719f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 221819f3792523fe2d55ea791a9286398a6120920690Adam Cohen 2219bebf042666cffe52039b875a549a582abd78a431Adam Cohen boolean createAreaForResize(int cellX, int cellY, int spanX, int spanY, 2220bebf042666cffe52039b875a549a582abd78a431Adam Cohen View dragView, int[] direction, boolean commit) { 2221bebf042666cffe52039b875a549a582abd78a431Adam Cohen int[] pixelXY = new int[2]; 2222bebf042666cffe52039b875a549a582abd78a431Adam Cohen regionToCenterPoint(cellX, cellY, spanX, spanY, pixelXY); 2223bebf042666cffe52039b875a549a582abd78a431Adam Cohen 2224bebf042666cffe52039b875a549a582abd78a431Adam Cohen // First we determine if things have moved enough to cause a different layout 2225bebf042666cffe52039b875a549a582abd78a431Adam Cohen ItemConfiguration swapSolution = simpleSwap(pixelXY[0], pixelXY[1], spanX, spanY, 2226bebf042666cffe52039b875a549a582abd78a431Adam Cohen spanX, spanY, direction, dragView, true, new ItemConfiguration()); 2227bebf042666cffe52039b875a549a582abd78a431Adam Cohen 2228bebf042666cffe52039b875a549a582abd78a431Adam Cohen setUseTempCoords(true); 2229bebf042666cffe52039b875a549a582abd78a431Adam Cohen if (swapSolution != null && swapSolution.isSolution) { 2230bebf042666cffe52039b875a549a582abd78a431Adam Cohen // If we're just testing for a possible location (MODE_ACCEPT_DROP), we don't bother 2231bebf042666cffe52039b875a549a582abd78a431Adam Cohen // committing anything or animating anything as we just want to determine if a solution 2232bebf042666cffe52039b875a549a582abd78a431Adam Cohen // exists 2233bebf042666cffe52039b875a549a582abd78a431Adam Cohen copySolutionToTempState(swapSolution, dragView); 2234bebf042666cffe52039b875a549a582abd78a431Adam Cohen setItemPlacementDirty(true); 2235bebf042666cffe52039b875a549a582abd78a431Adam Cohen animateItemsToSolution(swapSolution, dragView, commit); 2236bebf042666cffe52039b875a549a582abd78a431Adam Cohen 2237bebf042666cffe52039b875a549a582abd78a431Adam Cohen if (commit) { 2238bebf042666cffe52039b875a549a582abd78a431Adam Cohen commitTempPlacement(); 2239bebf042666cffe52039b875a549a582abd78a431Adam Cohen completeAndClearReorderHintAnimations(); 2240bebf042666cffe52039b875a549a582abd78a431Adam Cohen setItemPlacementDirty(false); 2241bebf042666cffe52039b875a549a582abd78a431Adam Cohen } else { 2242bebf042666cffe52039b875a549a582abd78a431Adam Cohen beginOrAdjustHintAnimations(swapSolution, dragView, 2243bebf042666cffe52039b875a549a582abd78a431Adam Cohen REORDER_ANIMATION_DURATION); 2244bebf042666cffe52039b875a549a582abd78a431Adam Cohen } 2245bebf042666cffe52039b875a549a582abd78a431Adam Cohen mShortcutsAndWidgets.requestLayout(); 2246bebf042666cffe52039b875a549a582abd78a431Adam Cohen } 2247bebf042666cffe52039b875a549a582abd78a431Adam Cohen return swapSolution.isSolution; 2248bebf042666cffe52039b875a549a582abd78a431Adam Cohen } 2249bebf042666cffe52039b875a549a582abd78a431Adam Cohen 2250482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int[] createArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, int spanY, 2251482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen View dragView, int[] result, int resultSpan[], int mode) { 2252482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // First we determine if things have moved enough to cause a different layout 225347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen result = findNearestArea(pixelX, pixelY, spanX, spanY, result); 2254482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2255482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (resultSpan == null) { 2256482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen resultSpan = new int[2]; 2257482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2258482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 225919f3792523fe2d55ea791a9286398a6120920690Adam Cohen // When we are checking drop validity or actually dropping, we don't recompute the 226019f3792523fe2d55ea791a9286398a6120920690Adam Cohen // direction vector, since we want the solution to match the preview, and it's possible 226119f3792523fe2d55ea791a9286398a6120920690Adam Cohen // that the exact position of the item has changed to result in a new reordering outcome. 2262b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen if ((mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL || mode == MODE_ACCEPT_DROP) 2263b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen && mPreviousReorderDirection[0] != INVALID_DIRECTION) { 226419f3792523fe2d55ea791a9286398a6120920690Adam Cohen mDirectionVector[0] = mPreviousReorderDirection[0]; 226519f3792523fe2d55ea791a9286398a6120920690Adam Cohen mDirectionVector[1] = mPreviousReorderDirection[1]; 226619f3792523fe2d55ea791a9286398a6120920690Adam Cohen // We reset this vector after drop 2267b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen if (mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL) { 2268b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen mPreviousReorderDirection[0] = INVALID_DIRECTION; 2269b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen mPreviousReorderDirection[1] = INVALID_DIRECTION; 227019f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 227119f3792523fe2d55ea791a9286398a6120920690Adam Cohen } else { 227219f3792523fe2d55ea791a9286398a6120920690Adam Cohen getDirectionVectorForDrop(pixelX, pixelY, spanX, spanY, dragView, mDirectionVector); 227319f3792523fe2d55ea791a9286398a6120920690Adam Cohen mPreviousReorderDirection[0] = mDirectionVector[0]; 227419f3792523fe2d55ea791a9286398a6120920690Adam Cohen mPreviousReorderDirection[1] = mDirectionVector[1]; 227519f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 227619f3792523fe2d55ea791a9286398a6120920690Adam Cohen 2277482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen ItemConfiguration swapSolution = simpleSwap(pixelX, pixelY, minSpanX, minSpanY, 2278482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen spanX, spanY, mDirectionVector, dragView, true, new ItemConfiguration()); 2279482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2280482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // We attempt the approach which doesn't shuffle views at all 2281482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen ItemConfiguration noShuffleSolution = findConfigurationNoShuffle(pixelX, pixelY, minSpanX, 2282482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen minSpanY, spanX, spanY, dragView, new ItemConfiguration()); 2283482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2284482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen ItemConfiguration finalSolution = null; 2285482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (swapSolution.isSolution && swapSolution.area() >= noShuffleSolution.area()) { 2286482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen finalSolution = swapSolution; 2287482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } else if (noShuffleSolution.isSolution) { 2288482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen finalSolution = noShuffleSolution; 2289482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2290482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2291482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean foundSolution = true; 2292482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (!DESTRUCTIVE_REORDER) { 2293482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen setUseTempCoords(true); 2294482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2295482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2296482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (finalSolution != null) { 2297482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result[0] = finalSolution.dragViewX; 2298482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result[1] = finalSolution.dragViewY; 2299482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen resultSpan[0] = finalSolution.dragViewSpanX; 2300482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen resultSpan[1] = finalSolution.dragViewSpanY; 2301482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2302482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // If we're just testing for a possible location (MODE_ACCEPT_DROP), we don't bother 2303482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // committing anything or animating anything as we just want to determine if a solution 2304482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // exists 2305482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (mode == MODE_DRAG_OVER || mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL) { 2306482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (!DESTRUCTIVE_REORDER) { 2307482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen copySolutionToTempState(finalSolution, dragView); 2308482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2309482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen setItemPlacementDirty(true); 2310482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen animateItemsToSolution(finalSolution, dragView, mode == MODE_ON_DROP); 2311482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 231219f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (!DESTRUCTIVE_REORDER && 231319f3792523fe2d55ea791a9286398a6120920690Adam Cohen (mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL)) { 2314482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen commitTempPlacement(); 231519f3792523fe2d55ea791a9286398a6120920690Adam Cohen completeAndClearReorderHintAnimations(); 231619f3792523fe2d55ea791a9286398a6120920690Adam Cohen setItemPlacementDirty(false); 231719f3792523fe2d55ea791a9286398a6120920690Adam Cohen } else { 231819f3792523fe2d55ea791a9286398a6120920690Adam Cohen beginOrAdjustHintAnimations(finalSolution, dragView, 231919f3792523fe2d55ea791a9286398a6120920690Adam Cohen REORDER_ANIMATION_DURATION); 2320482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2321482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2322482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } else { 2323482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen foundSolution = false; 2324482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result[0] = result[1] = resultSpan[0] = resultSpan[1] = -1; 2325482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2326482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2327482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if ((mode == MODE_ON_DROP || !foundSolution) && !DESTRUCTIVE_REORDER) { 2328482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen setUseTempCoords(false); 2329482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2330482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2331a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.requestLayout(); 2332482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return result; 2333482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2334482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 233519f3792523fe2d55ea791a9286398a6120920690Adam Cohen void setItemPlacementDirty(boolean dirty) { 233619f3792523fe2d55ea791a9286398a6120920690Adam Cohen mItemPlacementDirty = dirty; 2337482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 233819f3792523fe2d55ea791a9286398a6120920690Adam Cohen boolean isItemPlacementDirty() { 233919f3792523fe2d55ea791a9286398a6120920690Adam Cohen return mItemPlacementDirty; 2340482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2341482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2342482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private class ItemConfiguration { 23438baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen HashMap<View, CellAndSpan> map = new HashMap<View, CellAndSpan>(); 2344482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean isSolution = false; 2345482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int dragViewX, dragViewY, dragViewSpanX, dragViewSpanY; 2346482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2347482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int area() { 2348482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return dragViewSpanX * dragViewSpanY; 2349482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 23508baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen } 23518baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen 23528baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen private class CellAndSpan { 23538baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen int x, y; 23548baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen int spanX, spanY; 23558baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen 23568baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen public CellAndSpan(int x, int y, int spanX, int spanY) { 23578baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen this.x = x; 23588baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen this.y = y; 23598baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen this.spanX = spanX; 23608baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen this.spanY = spanY; 2361482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2362482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2363482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2364df0353815c629fc678824b07a234b89a1ff94208Adam Cohen /** 2365df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * Find a vacant area that will fit the given bounds nearest the requested 2366df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * cell location. Uses Euclidean distance to score multiple vacant areas. 2367df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * 2368df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param pixelX The X location at which you want to search for a vacant area. 2369df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param pixelY The Y location at which you want to search for a vacant area. 2370df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param spanX Horizontal span of the object. 2371df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param spanY Vertical span of the object. 2372df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param ignoreView Considers space occupied by this view as unoccupied 2373df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param result Previously returned value to possibly recycle. 2374df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @return The X, Y cell of a vacant area that can contain this object, 2375df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * nearest the requested location. 2376df0353815c629fc678824b07a234b89a1ff94208Adam Cohen */ 2377df0353815c629fc678824b07a234b89a1ff94208Adam Cohen int[] findNearestVacantArea( 2378df0353815c629fc678824b07a234b89a1ff94208Adam Cohen int pixelX, int pixelY, int spanX, int spanY, View ignoreView, int[] result) { 2379df0353815c629fc678824b07a234b89a1ff94208Adam Cohen return findNearestArea(pixelX, pixelY, spanX, spanY, ignoreView, true, result); 2380df0353815c629fc678824b07a234b89a1ff94208Adam Cohen } 2381df0353815c629fc678824b07a234b89a1ff94208Adam Cohen 2382df0353815c629fc678824b07a234b89a1ff94208Adam Cohen /** 2383d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * Find a vacant area that will fit the given bounds nearest the requested 2384d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * cell location. Uses Euclidean distance to score multiple vacant areas. 2385d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * 2386d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param pixelX The X location at which you want to search for a vacant area. 2387d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param pixelY The Y location at which you want to search for a vacant area. 2388d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param minSpanX The minimum horizontal span required 2389d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param minSpanY The minimum vertical span required 2390d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param spanX Horizontal span of the object. 2391d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param spanY Vertical span of the object. 2392d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param ignoreView Considers space occupied by this view as unoccupied 2393d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param result Previously returned value to possibly recycle. 2394d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @return The X, Y cell of a vacant area that can contain this object, 2395d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * nearest the requested location. 2396d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen */ 2397d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int[] findNearestVacantArea(int pixelX, int pixelY, int minSpanX, int minSpanY, 2398d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int spanX, int spanY, View ignoreView, int[] result, int[] resultSpan) { 2399482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return findNearestArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, ignoreView, true, 2400482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result, resultSpan, mOccupied); 2401d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 2402d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen 2403d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen /** 2404df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * Find a starting cell position that will fit the given bounds nearest the requested 2405df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * cell location. Uses Euclidean distance to score multiple vacant areas. 2406df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * 2407df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param pixelX The X location at which you want to search for a vacant area. 2408df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param pixelY The Y location at which you want to search for a vacant area. 2409df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param spanX Horizontal span of the object. 2410df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param spanY Vertical span of the object. 2411df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param ignoreView Considers space occupied by this view as unoccupied 2412df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param result Previously returned value to possibly recycle. 2413df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @return The X, Y cell of a vacant area that can contain this object, 2414df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * nearest the requested location. 2415df0353815c629fc678824b07a234b89a1ff94208Adam Cohen */ 2416df0353815c629fc678824b07a234b89a1ff94208Adam Cohen int[] findNearestArea( 2417df0353815c629fc678824b07a234b89a1ff94208Adam Cohen int pixelX, int pixelY, int spanX, int spanY, int[] result) { 2418df0353815c629fc678824b07a234b89a1ff94208Adam Cohen return findNearestArea(pixelX, pixelY, spanX, spanY, null, false, result); 2419df0353815c629fc678824b07a234b89a1ff94208Adam Cohen } 2420df0353815c629fc678824b07a234b89a1ff94208Adam Cohen 24210280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka boolean existsEmptyCell() { 24220280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka return findCellForSpan(null, 1, 1); 24230280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 24240280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 24250280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka /** 24260280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * Finds the upper-left coordinate of the first rectangle in the grid that can 24270280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * hold a cell of the specified dimensions. If intersectX and intersectY are not -1, 24280280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * then this method will only return coordinates for rectangles that contain the cell 24290280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * (intersectX, intersectY) 24300280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * 24310280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param cellXY The array that will contain the position of a vacant cell if such a cell 24320280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * can be found. 24330280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param spanX The horizontal span of the cell we want to find. 24340280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param spanY The vertical span of the cell we want to find. 24350280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * 24360280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @return True if a vacant cell of the specified dimension was found, false otherwise. 24370280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka */ 24380280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka boolean findCellForSpan(int[] cellXY, int spanX, int spanY) { 2439482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return findCellForSpanThatIntersectsIgnoring(cellXY, spanX, spanY, -1, -1, null, mOccupied); 24400280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 24410280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 24420280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka /** 24430280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * Like above, but ignores any cells occupied by the item "ignoreView" 24440280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * 24450280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param cellXY The array that will contain the position of a vacant cell if such a cell 24460280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * can be found. 24470280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param spanX The horizontal span of the cell we want to find. 24480280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param spanY The vertical span of the cell we want to find. 24490280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param ignoreView The home screen item we should treat as not occupying any space 24500280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @return 24510280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka */ 24520280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka boolean findCellForSpanIgnoring(int[] cellXY, int spanX, int spanY, View ignoreView) { 2453482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return findCellForSpanThatIntersectsIgnoring(cellXY, spanX, spanY, -1, -1, 2454482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen ignoreView, mOccupied); 24550280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 24560280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 24570280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka /** 24580280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * Like above, but if intersectX and intersectY are not -1, then this method will try to 24590280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * return coordinates for rectangles that contain the cell [intersectX, intersectY] 24600280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * 24610280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param spanX The horizontal span of the cell we want to find. 24620280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param spanY The vertical span of the cell we want to find. 24630280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param ignoreView The home screen item we should treat as not occupying any space 24640280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param intersectX The X coordinate of the cell that we should try to overlap 24650280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param intersectX The Y coordinate of the cell that we should try to overlap 24660280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * 24670280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @return True if a vacant cell of the specified dimension was found, false otherwise. 24680280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka */ 24690280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka boolean findCellForSpanThatIntersects(int[] cellXY, int spanX, int spanY, 24700280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka int intersectX, int intersectY) { 24710280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka return findCellForSpanThatIntersectsIgnoring( 2472482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen cellXY, spanX, spanY, intersectX, intersectY, null, mOccupied); 24730280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 24740280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 24750280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka /** 24760280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * The superset of the above two methods 24770280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka */ 24780280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka boolean findCellForSpanThatIntersectsIgnoring(int[] cellXY, int spanX, int spanY, 2479482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int intersectX, int intersectY, View ignoreView, boolean occupied[][]) { 2480c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka // mark space take by ignoreView as available (method checks if ignoreView is null) 2481482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsAsUnoccupiedForView(ignoreView, occupied); 24820280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 248328750fba6a2d141eb9a1e566718c17236030b815Michael Jurka boolean foundCell = false; 24840280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka while (true) { 24850280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka int startX = 0; 24860280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka if (intersectX >= 0) { 24870280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka startX = Math.max(startX, intersectX - (spanX - 1)); 24880280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 24890280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka int endX = mCountX - (spanX - 1); 24900280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka if (intersectX >= 0) { 24910280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka endX = Math.min(endX, intersectX + (spanX - 1) + (spanX == 1 ? 1 : 0)); 24920280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 24930280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka int startY = 0; 24940280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka if (intersectY >= 0) { 24950280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka startY = Math.max(startY, intersectY - (spanY - 1)); 24960280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 24970280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka int endY = mCountY - (spanY - 1); 24980280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka if (intersectY >= 0) { 24990280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka endY = Math.min(endY, intersectY + (spanY - 1) + (spanY == 1 ? 1 : 0)); 25000280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 25010280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 2502bbc60d8e79416e37cbede55c159bf6aaa6c171d5Winson Chung for (int y = startY; y < endY && !foundCell; y++) { 25030280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka inner: 2504bbc60d8e79416e37cbede55c159bf6aaa6c171d5Winson Chung for (int x = startX; x < endX; x++) { 25050280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka for (int i = 0; i < spanX; i++) { 25060280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka for (int j = 0; j < spanY; j++) { 2507482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (occupied[x + i][y + j]) { 2508bbc60d8e79416e37cbede55c159bf6aaa6c171d5Winson Chung // small optimization: we can skip to after the column we just found 25090280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // an occupied cell 2510bbc60d8e79416e37cbede55c159bf6aaa6c171d5Winson Chung x += i; 25110280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka continue inner; 25120280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 25130280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 25140280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 25150280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka if (cellXY != null) { 25160280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka cellXY[0] = x; 25170280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka cellXY[1] = y; 25180280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 251928750fba6a2d141eb9a1e566718c17236030b815Michael Jurka foundCell = true; 252028750fba6a2d141eb9a1e566718c17236030b815Michael Jurka break; 25210280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 25220280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 25230280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka if (intersectX == -1 && intersectY == -1) { 25240280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka break; 25250280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } else { 25260280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // if we failed to find anything, try again but without any requirements of 25270280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // intersecting 25280280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka intersectX = -1; 25290280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka intersectY = -1; 25300280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka continue; 25310280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 25320280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 25330280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 2534c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka // re-mark space taken by ignoreView as occupied 2535482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsAsOccupiedForView(ignoreView, occupied); 253628750fba6a2d141eb9a1e566718c17236030b815Michael Jurka return foundCell; 25370280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 25380280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 253931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 2540c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung * A drag event has begun over this layout. 2541c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung * It may have begun over this layout (in which case onDragChild is called first), 2542c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung * or it may have begun on another layout. 2543c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung */ 2544c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung void onDragEnter() { 2545c6cc61d45836e4081920883cc4d448ccb0bb8417Adam Cohen mDragEnforcer.onDragEnter(); 2546c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung if (!mDragging) { 2547c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung // Fade in the drag indicators 2548c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung if (mCrosshairsAnimator != null) { 2549c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung mCrosshairsAnimator.animateIn(); 2550c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung } 2551c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung } 2552c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung mDragging = true; 2553c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung } 2554c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung 2555c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung /** 25560280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * Called when drag has left this CellLayout or has been completed (successfully or not) 25576569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy */ 25580280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka void onDragExit() { 2559c6cc61d45836e4081920883cc4d448ccb0bb8417Adam Cohen mDragEnforcer.onDragExit(); 25604be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // This can actually be called when we aren't in a drag, e.g. when adding a new 25614be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // item to this layout via the customize drawer. 25624be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // Guard against that case. 25634be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato if (mDragging) { 25644be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato mDragging = false; 25656569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 25664be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // Fade out the drag indicators 25674be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato if (mCrosshairsAnimator != null) { 25684be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato mCrosshairsAnimator.animateOut(); 25694be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato } 25704be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato } 257108ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy 257208ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy // Invalidate the drag data 2573d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen mDragCell[0] = mDragCell[1] = -1; 257408ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy mDragOutlineAnims[mDragOutlineCurrent].animateOut(); 257508ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy mDragOutlineCurrent = (mDragOutlineCurrent + 1) % mDragOutlineAnims.length; 257619f3792523fe2d55ea791a9286398a6120920690Adam Cohen revertTempState(); 257733945b21544bc98381df17726a3537c292d8c985Michael Jurka setIsDragOverlapping(false); 25786569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy } 25796569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 25806569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy /** 2581aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * Mark a child as having been dropped. 2582de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy * At the beginning of the drag operation, the child may have been on another 2583ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy * screen, but it is re-parented before this method is called. 258431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 258531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param child The child that is being dropped 258631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 2587716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen void onDropChild(View child) { 2588d94533d04a5f8f5485f106d10af60169857ea899Romain Guy if (child != null) { 2589d94533d04a5f8f5485f106d10af60169857ea899Romain Guy LayoutParams lp = (LayoutParams) child.getLayoutParams(); 259084f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy lp.dropped = true; 2591d94533d04a5f8f5485f106d10af60169857ea899Romain Guy child.requestLayout(); 2592d94533d04a5f8f5485f106d10af60169857ea899Romain Guy } 259331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 259431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 259531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 259631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Computes a bounding rectangle for a range of cells 2597aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * 259831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param cellX X coordinate of upper left corner expressed as a cell position 259931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param cellY Y coordinate of upper left corner expressed as a cell position 2600aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * @param cellHSpan Width in cells 260131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param cellVSpan Height in cells 26026569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy * @param resultRect Rect into which to put the results 260331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 2604d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen public void cellToRect(int cellX, int cellY, int cellHSpan, int cellVSpan, Rect resultRect) { 260531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int cellWidth = mCellWidth; 260631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int cellHeight = mCellHeight; 260731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int widthGap = mWidthGap; 260831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int heightGap = mHeightGap; 2609aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 26104b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung final int hStartPadding = getPaddingLeft(); 26114b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung final int vStartPadding = getPaddingTop(); 2612aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 261331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int width = cellHSpan * cellWidth + ((cellHSpan - 1) * widthGap); 261431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int height = cellVSpan * cellHeight + ((cellVSpan - 1) * heightGap); 261531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 261631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int x = hStartPadding + cellX * (cellWidth + widthGap); 261731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int y = vStartPadding + cellY * (cellHeight + heightGap); 2618aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 26196569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy resultRect.set(x, y, x + width, y + height); 262031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 2621aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 262231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 2623aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * Computes the required horizontal and vertical cell spans to always 262431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * fit the given rectangle. 2625aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * 262631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param width Width in pixels 262731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param height Height in pixels 26288f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy * @param result An array of length 2 in which to store the result (may be null). 262931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 26308f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy public int[] rectToCell(int width, int height, int[] result) { 26319987a5c45e7d01a780d73b269bdce8d8a5309219Michael Jurka return rectToCell(getResources(), width, height, result); 26329987a5c45e7d01a780d73b269bdce8d8a5309219Michael Jurka } 26339987a5c45e7d01a780d73b269bdce8d8a5309219Michael Jurka 26349987a5c45e7d01a780d73b269bdce8d8a5309219Michael Jurka public static int[] rectToCell(Resources resources, int width, int height, int[] result) { 263531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // Always assume we're working with the smallest span to make sure we 263631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // reserve enough space in both orientations. 263779e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato int actualWidth = resources.getDimensionPixelSize(R.dimen.workspace_cell_width); 263879e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato int actualHeight = resources.getDimensionPixelSize(R.dimen.workspace_cell_height); 263931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int smallerSize = Math.min(actualWidth, actualHeight); 264079e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato 264131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // Always round up to next largest cell 264254c725cc294cd43ed0650179bfae64a622547660Winson Chung int spanX = (int) Math.ceil(width / (float) smallerSize); 264354c725cc294cd43ed0650179bfae64a622547660Winson Chung int spanY = (int) Math.ceil(height / (float) smallerSize); 264479e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato 26458f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy if (result == null) { 26468f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy return new int[] { spanX, spanY }; 26478f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy } 26488f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy result[0] = spanX; 26498f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy result[1] = spanY; 26508f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy return result; 265131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 265231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 2653f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka public int[] cellSpansToSize(int hSpans, int vSpans) { 2654f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka int[] size = new int[2]; 2655f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka size[0] = hSpans * mCellWidth + (hSpans - 1) * mWidthGap; 2656f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka size[1] = vSpans * mCellHeight + (vSpans - 1) * mHeightGap; 2657f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka return size; 2658f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka } 2659f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka 266031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 2661047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy * Calculate the grid spans needed to fit given item 2662047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy */ 2663047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy public void calculateSpans(ItemInfo info) { 2664047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy final int minWidth; 2665047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy final int minHeight; 2666047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy 2667047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy if (info instanceof LauncherAppWidgetInfo) { 2668047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy minWidth = ((LauncherAppWidgetInfo) info).minWidth; 2669047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy minHeight = ((LauncherAppWidgetInfo) info).minHeight; 2670047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy } else if (info instanceof PendingAddWidgetInfo) { 2671047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy minWidth = ((PendingAddWidgetInfo) info).minWidth; 2672047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy minHeight = ((PendingAddWidgetInfo) info).minHeight; 2673047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy } else { 2674047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy // It's not a widget, so it must be 1x1 2675047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy info.spanX = info.spanY = 1; 2676047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy return; 2677047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy } 2678047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy int[] spans = rectToCell(minWidth, minHeight, null); 2679047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy info.spanX = spans[0]; 2680047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy info.spanY = spans[1]; 2681047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy } 2682047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy 2683047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy /** 268431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Find the first vacant cell, if there is one. 268531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 268631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param vacant Holds the x and y coordinate of the vacant cell 268731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param spanX Horizontal cell span. 268831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param spanY Vertical cell span. 2689aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * 269031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @return True if a vacant cell was found 269131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 269231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public boolean getVacantCell(int[] vacant, int spanX, int spanY) { 269331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 26940280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka return findVacantCell(vacant, spanX, spanY, mCountX, mCountY, mOccupied); 269531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 269631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 269731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project static boolean findVacantCell(int[] vacant, int spanX, int spanY, 269831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int xCount, int yCount, boolean[][] occupied) { 269931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 27002801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen for (int y = 0; y < yCount; y++) { 27012801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen for (int x = 0; x < xCount; x++) { 270231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project boolean available = !occupied[x][y]; 270331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectout: for (int i = x; i < x + spanX - 1 && x < xCount; i++) { 270431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int j = y; j < y + spanY - 1 && y < yCount; j++) { 270531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project available = available && !occupied[i][j]; 270631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (!available) break out; 270731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 270831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 270931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 271031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (available) { 271131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project vacant[0] = x; 271231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project vacant[1] = y; 271331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return true; 271431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 271531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 271631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 271731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 271831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return false; 271931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 272031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 27210280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka private void clearOccupiedCells() { 27220280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka for (int x = 0; x < mCountX; x++) { 27230280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka for (int y = 0; y < mCountY; y++) { 27240280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka mOccupied[x][y] = false; 272531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 272631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 27270280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 272831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 2729d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen public void onMove(View view, int newCellX, int newCellY, int newSpanX, int newSpanY) { 27300280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka markCellsAsUnoccupiedForView(view); 2731482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsForView(newCellX, newCellY, newSpanX, newSpanY, mOccupied, true); 27320280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 273331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 2734d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen public void markCellsAsOccupiedForView(View view) { 2735482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsAsOccupiedForView(view, mOccupied); 2736482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2737482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public void markCellsAsOccupiedForView(View view, boolean[][] occupied) { 2738a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka if (view == null || view.getParent() != mShortcutsAndWidgets) return; 27390280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka LayoutParams lp = (LayoutParams) view.getLayoutParams(); 2740482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, occupied, true); 27410280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 27420280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 2743d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen public void markCellsAsUnoccupiedForView(View view) { 2744482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsAsUnoccupiedForView(view, mOccupied); 2745482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2746482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public void markCellsAsUnoccupiedForView(View view, boolean occupied[][]) { 2747a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka if (view == null || view.getParent() != mShortcutsAndWidgets) return; 27480280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka LayoutParams lp = (LayoutParams) view.getLayoutParams(); 2749482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, occupied, false); 27500280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 27510280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 2752482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private void markCellsForView(int cellX, int cellY, int spanX, int spanY, boolean[][] occupied, 2753482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean value) { 2754482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (cellX < 0 || cellY < 0) return; 27550280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka for (int x = cellX; x < cellX + spanX && x < mCountX; x++) { 27560280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka for (int y = cellY; y < cellY + spanY && y < mCountY; y++) { 2757482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen occupied[x][y] = value; 275831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 275931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 276031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 276131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 27622801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen public int getDesiredWidth() { 27634b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung return mPaddingLeft + mPaddingRight + (mCountX * mCellWidth) + 27642801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen (Math.max((mCountX - 1), 0) * mWidthGap); 27652801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen } 27662801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen 27672801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen public int getDesiredHeight() { 27684b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung return mPaddingTop + mPaddingBottom + (mCountY * mCellHeight) + 27692801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen (Math.max((mCountY - 1), 0) * mHeightGap); 27702801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen } 27712801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen 277266d72178af91d455700875635473be942bc90e54Michael Jurka public boolean isOccupied(int x, int y) { 277366d72178af91d455700875635473be942bc90e54Michael Jurka if (x < mCountX && y < mCountY) { 277466d72178af91d455700875635473be942bc90e54Michael Jurka return mOccupied[x][y]; 277566d72178af91d455700875635473be942bc90e54Michael Jurka } else { 277666d72178af91d455700875635473be942bc90e54Michael Jurka throw new RuntimeException("Position exceeds the bound of this CellLayout"); 277766d72178af91d455700875635473be942bc90e54Michael Jurka } 277866d72178af91d455700875635473be942bc90e54Michael Jurka } 277966d72178af91d455700875635473be942bc90e54Michael Jurka 278031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 278131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) { 278231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return new CellLayout.LayoutParams(getContext(), attrs); 278331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 278431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 278531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 278631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { 278731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return p instanceof CellLayout.LayoutParams; 278831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 278931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 279031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 279131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { 279231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return new CellLayout.LayoutParams(p); 279331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 279431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 2795aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung public static class CellLayoutAnimationController extends LayoutAnimationController { 2796aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung public CellLayoutAnimationController(Animation animation, float delay) { 2797aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung super(animation, delay); 2798aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung } 2799aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 2800aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung @Override 2801aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung protected long getDelayForView(View view) { 2802aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung return (int) (Math.random() * 150); 2803aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung } 2804aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung } 2805aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 280631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public static class LayoutParams extends ViewGroup.MarginLayoutParams { 280731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 280831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Horizontal location of the item in the grid. 280931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 281031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @ViewDebug.ExportedProperty 281131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public int cellX; 281231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 281331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 281431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Vertical 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 cellY; 281831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 281931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 2820482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * Temporary horizontal location of the item in the grid during reorder 2821482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen */ 2822482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public int tmpCellX; 2823482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2824482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen /** 2825482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * Temporary vertical location of the item in the grid during reorder 2826482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen */ 2827482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public int tmpCellY; 2828482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2829482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen /** 2830482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * Indicates that the temporary coordinates should be used to layout the items 2831482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen */ 2832482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public boolean useTmpCoords; 2833482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2834482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen /** 283531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Number of cells spanned horizontally by the item. 283631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 283731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @ViewDebug.ExportedProperty 283831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public int cellHSpan; 283931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 284031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 284131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Number of cells spanned vertically by the item. 284231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 284331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @ViewDebug.ExportedProperty 284431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public int cellVSpan; 2845aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 28461b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen /** 28471b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen * Indicates whether the item will set its x, y, width and height parameters freely, 28481b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen * or whether these will be computed based on cellX, cellY, cellHSpan and cellVSpan. 28491b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen */ 2850d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen public boolean isLockedToGrid = true; 2851d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen 2852482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen /** 2853482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * Indicates whether this item can be reordered. Always true except in the case of the 2854482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * the AllApps button. 2855482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen */ 2856482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public boolean canReorder = true; 2857482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 285831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // X coordinate of the view in the layout. 285931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @ViewDebug.ExportedProperty 286031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int x; 286131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // Y coordinate of the view in the layout. 286231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @ViewDebug.ExportedProperty 286331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int y; 286431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 286584f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy boolean dropped; 2866fcb9e7144e58614f5ae0e9b272fb7ce040848c67Romain Guy 286731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public LayoutParams(Context c, AttributeSet attrs) { 286831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project super(c, attrs); 286931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellHSpan = 1; 287031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellVSpan = 1; 287131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 287231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 287331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public LayoutParams(ViewGroup.LayoutParams source) { 287431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project super(source); 287531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellHSpan = 1; 287631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellVSpan = 1; 287731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 2878aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 2879aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung public LayoutParams(LayoutParams source) { 2880aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung super(source); 2881aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung this.cellX = source.cellX; 2882aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung this.cellY = source.cellY; 2883aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung this.cellHSpan = source.cellHSpan; 2884aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung this.cellVSpan = source.cellVSpan; 2885aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung } 2886aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 288731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public LayoutParams(int cellX, int cellY, int cellHSpan, int cellVSpan) { 28888f19cdd62f6e2be05e3890916eabd11317ae1bc2Romain Guy super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); 288931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this.cellX = cellX; 289031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this.cellY = cellY; 289131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this.cellHSpan = cellHSpan; 289231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this.cellVSpan = cellVSpan; 289331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 289431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 28957f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public void setup(int cellWidth, int cellHeight, int widthGap, int heightGap) { 2896d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen if (isLockedToGrid) { 2897d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen final int myCellHSpan = cellHSpan; 2898d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen final int myCellVSpan = cellVSpan; 2899482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int myCellX = useTmpCoords ? tmpCellX : cellX; 2900482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int myCellY = useTmpCoords ? tmpCellY : cellY; 29011b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen 2902d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen width = myCellHSpan * cellWidth + ((myCellHSpan - 1) * widthGap) - 2903d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen leftMargin - rightMargin; 2904d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen height = myCellVSpan * cellHeight + ((myCellVSpan - 1) * heightGap) - 2905d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen topMargin - bottomMargin; 2906eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung x = (int) (myCellX * (cellWidth + widthGap) + leftMargin); 2907eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung y = (int) (myCellY * (cellHeight + heightGap) + topMargin); 2908d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen } 2909d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen } 2910d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen 2911aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung public String toString() { 2912aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung return "(" + this.cellX + ", " + this.cellY + ")"; 2913aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung } 29147f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 29157f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public void setWidth(int width) { 29167f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen this.width = width; 29177f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 29187f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 29197f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public int getWidth() { 29207f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen return width; 29217f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 29227f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 29237f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public void setHeight(int height) { 29247f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen this.height = height; 29257f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 29267f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 29277f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public int getHeight() { 29287f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen return height; 29297f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 29307f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 29317f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public void setX(int x) { 29327f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen this.x = x; 29337f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 29347f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 29357f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public int getX() { 29367f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen return x; 29377f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 29387f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 29397f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public void setY(int y) { 29407f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen this.y = y; 29417f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 29427f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 29437f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public int getY() { 29447f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen return y; 29457f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 294631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 294731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 29480280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // This class stores info for two purposes: 29490280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // 1. When dragging items (mDragInfo in Workspace), we store the View, its cellX & cellY, 29500280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // its spanX, spanY, and the screen it is on 29510280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // 2. When long clicking on an empty cell in a CellLayout, we save information about the 29520280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // cellX and cellY coordinates and which page was clicked. We then set this as a tag on 29530280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // the CellLayout that was long clicked 2954e5fb0f27bca7afb996258a7163c76ca7390d7bffMichael Jurka static final class CellInfo { 295531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project View cell; 2956a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka int cellX = -1; 2957a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka int cellY = -1; 295831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int spanX; 295931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int spanY; 296031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int screen; 29613d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung long container; 296231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 296331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 296431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public String toString() { 2965aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung return "Cell[view=" + (cell == null ? "null" : cell.getClass()) 2966aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung + ", x=" + cellX + ", y=" + cellY + "]"; 296731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 296831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 2969d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka 2970d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka public boolean lastDownOnOccupiedCell() { 2971d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka return mLastDownOnOccupiedCell; 2972d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka } 297331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project} 2974