CellLayout.java revision 1462de39f01cec0ba785386532719cb0207dd827
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; 201462de39f01cec0ba785386532719cb0207dd827Adam Cohenimport android.animation.AnimatorListenerAdapter; 2150e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keelyimport android.animation.AnimatorSet; 2250e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keelyimport android.animation.ObjectAnimator; 2300397b1d9233409d9d6b233b077ae12d09768ce8Chet Haaseimport android.animation.TimeInterpolator; 24de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroyimport android.animation.ValueAnimator; 25de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroyimport android.animation.ValueAnimator.AnimatorUpdateListener; 2631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.content.Context; 2779e56263dbcbe85dc434df372bc6e6730aa13477Joe Onoratoimport android.content.res.Resources; 28aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chungimport android.content.res.TypedArray; 294be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onoratoimport android.graphics.Bitmap; 30aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chungimport android.graphics.Canvas; 310dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynnimport android.graphics.Color; 324be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onoratoimport android.graphics.Paint; 33de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroyimport android.graphics.Point; 34b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohenimport android.graphics.PorterDuff; 35b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohenimport android.graphics.PorterDuffXfermode; 3631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.graphics.Rect; 37482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohenimport android.graphics.drawable.ColorDrawable; 386569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroyimport android.graphics.drawable.Drawable; 39b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohenimport android.graphics.drawable.NinePatchDrawable; 401462de39f01cec0ba785386532719cb0207dd827Adam Cohenimport android.os.Parcelable; 4131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.util.AttributeSet; 424be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onoratoimport android.util.Log; 431462de39f01cec0ba785386532719cb0207dd827Adam Cohenimport android.util.SparseArray; 4431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.MotionEvent; 4531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.View; 4631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.ViewDebug; 4731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.ViewGroup; 48aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chungimport android.view.animation.Animation; 49150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chungimport android.view.animation.DecelerateInterpolator; 50aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chungimport android.view.animation.LayoutAnimationController; 5131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 526639687cd67bab1aeef2a75e5c6bc458b20dc082Adam Cohenimport com.android.launcher.R; 5369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohenimport com.android.launcher2.FolderIcon.FolderRingAnimator; 548e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy 5569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohenimport java.util.ArrayList; 56c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohenimport java.util.Arrays; 57bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohenimport java.util.HashMap; 58d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohenimport java.util.Stack; 59c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen 60bdb5c5342adc550559fd723af461e53248f2fba8Michael Jurkapublic class CellLayout extends ViewGroup { 61aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung static final String TAG = "CellLayout"; 62aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 632acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen private Launcher mLauncher; 6431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private int mCellWidth; 6531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private int mCellHeight; 66aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 67d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen private int mCountX; 68d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen private int mCountY; 6931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 70234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen private int mOriginalWidthGap; 71234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen private int mOriginalHeightGap; 7231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private int mWidthGap; 7331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private int mHeightGap; 744b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung private int mMaxGap; 75ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen private boolean mScrollingTransformsDirty = false; 7631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 7731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private final Rect mRect = new Rect(); 7831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private final CellInfo mCellInfo = new CellInfo(); 79aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 80de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy // These are temporary variables to prevent having to allocate a new object just to 81de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy // return an (x, y) value from helper functions. Do NOT use them to maintain other state. 820be025d64c1f84138fe430a58875886e66aae767Winson Chung private final int[] mTmpXY = new int[2]; 83de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy private final int[] mTmpPoint = new int[2]; 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 125482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private HashMap<CellLayout.LayoutParams, Animator> mReorderAnimators = new 126482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen HashMap<CellLayout.LayoutParams, Animator>(); 12719f3792523fe2d55ea791a9286398a6120920690Adam Cohen private HashMap<View, ReorderHintAnimation> 12819f3792523fe2d55ea791a9286398a6120920690Adam Cohen mShakeAnimators = new HashMap<View, ReorderHintAnimation>(); 12919f3792523fe2d55ea791a9286398a6120920690Adam Cohen 13019f3792523fe2d55ea791a9286398a6120920690Adam Cohen private boolean mItemPlacementDirty = false; 131bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen 1326569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy // When a drag operation is in progress, holds the nearest cell to the touch point 1336569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy private final int[] mDragCell = new int[2]; 13431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 1354be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato private boolean mDragging = false; 1364be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato 137ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy private TimeInterpolator mEaseOutInterpolator; 138a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka private ShortcutAndWidgetContainer mShortcutsAndWidgets; 139ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy 1400dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn private boolean mIsHotseat = false; 1410dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn 142482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public static final int MODE_DRAG_OVER = 0; 143482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public static final int MODE_ON_DROP = 1; 144482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public static final int MODE_ON_DROP_EXTERNAL = 2; 145482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public static final int MODE_ACCEPT_DROP = 3; 14619f3792523fe2d55ea791a9286398a6120920690Adam Cohen private static final boolean DESTRUCTIVE_REORDER = false; 147482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private static final boolean DEBUG_VISUALIZE_OCCUPIED = false; 148482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 149a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen static final int LANDSCAPE = 0; 150a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen static final int PORTRAIT = 1; 151a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen 1527bdfc9700b1cad043c04c757f134db1bf3df00daAdam Cohen private static final float REORDER_HINT_MAGNITUDE = 0.12f; 15319f3792523fe2d55ea791a9286398a6120920690Adam Cohen private static final int REORDER_ANIMATION_DURATION = 150; 15419f3792523fe2d55ea791a9286398a6120920690Adam Cohen private float mReorderHintAnimationMagnitude; 15519f3792523fe2d55ea791a9286398a6120920690Adam Cohen 156482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private ArrayList<View> mIntersectingViews = new ArrayList<View>(); 157482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private Rect mOccupiedRect = new Rect(); 158482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private int[] mDirectionVector = new int[2]; 15919f3792523fe2d55ea791a9286398a6120920690Adam Cohen int[] mPreviousReorderDirection = new int[2]; 160b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen private static final int INVALID_DIRECTION = -100; 161c6cc61d45836e4081920883cc4d448ccb0bb8417Adam Cohen private DropTarget.DragEnforcer mDragEnforcer; 162482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1638a0bff5e35f63321178bbf777ec24d42544866b3Romain Guy private final static PorterDuffXfermode sAddBlendMode = 1648a0bff5e35f63321178bbf777ec24d42544866b3Romain Guy new PorterDuffXfermode(PorterDuff.Mode.ADD); 1658a0bff5e35f63321178bbf777ec24d42544866b3Romain Guy 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); 1768b805b17158886035b38261eb611d8641701ae43Michael Jurka mDragEnforcer = new DropTarget.DragEnforcer(context); 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 185f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen mCellWidth = a.getDimensionPixelSize(R.styleable.CellLayout_cellWidth, 10); 186f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen mCellHeight = a.getDimensionPixelSize(R.styleable.CellLayout_cellHeight, 10); 187234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen mWidthGap = mOriginalWidthGap = a.getDimensionPixelSize(R.styleable.CellLayout_widthGap, 0); 188234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen mHeightGap = mOriginalHeightGap = a.getDimensionPixelSize(R.styleable.CellLayout_heightGap, 0); 1894b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung mMaxGap = a.getDimensionPixelSize(R.styleable.CellLayout_maxGap, 0); 190d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen mCountX = LauncherModel.getCellCountX(); 191d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen mCountY = LauncherModel.getCellCountY(); 1920280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka mOccupied = new boolean[mCountX][mCountY]; 193482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mTmpOccupied = new boolean[mCountX][mCountY]; 1945b53f29f809a0dad4a1e0717ba610ce737ee0f43Adam Cohen mPreviousReorderDirection[0] = INVALID_DIRECTION; 1955b53f29f809a0dad4a1e0717ba610ce737ee0f43Adam Cohen mPreviousReorderDirection[1] = INVALID_DIRECTION; 19631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 19731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project a.recycle(); 19831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 19931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project setAlwaysDrawnWithCacheEnabled(false); 20031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 201046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy final Resources res = getResources(); 202de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy 203967289b6d5fec77f5c381d11ffb2319f3bb5e737Winson Chung mNormalBackground = res.getDrawable(R.drawable.homescreen_blue_normal_holo); 204dea74b7d12b0fcd50bfdb4274f9867ba76d75238Winson Chung mActiveGlowBackground = res.getDrawable(R.drawable.homescreen_blue_strong_holo); 205b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung 206b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mOverScrollLeft = res.getDrawable(R.drawable.overscroll_glow_left); 207b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mOverScrollRight = res.getDrawable(R.drawable.overscroll_glow_right); 208b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mForegroundPadding = 209b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen res.getDimensionPixelSize(R.dimen.workspace_overscroll_drawable_padding); 210b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung 21119f3792523fe2d55ea791a9286398a6120920690Adam Cohen mReorderHintAnimationMagnitude = (REORDER_HINT_MAGNITUDE * 21219f3792523fe2d55ea791a9286398a6120920690Adam Cohen res.getDimensionPixelSize(R.dimen.app_icon_size)); 21319f3792523fe2d55ea791a9286398a6120920690Adam Cohen 214b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung mNormalBackground.setFilterBitmap(true); 215b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung mActiveGlowBackground.setFilterBitmap(true); 216de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy 217046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy // Initialize the data structures used for the drag visualization. 218150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung 219ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy mEaseOutInterpolator = new DecelerateInterpolator(2.5f); // Quint ease out 220de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy 221046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy 222b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung mDragCell[0] = mDragCell[1] = -1; 2234be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato for (int i = 0; i < mDragOutlines.length; i++) { 224d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen mDragOutlines[i] = new Rect(-1, -1, -1, -1); 225046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy } 226046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy 227046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy // When dragging things around the home screens, we show a green outline of 228046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy // where the item will land. The outlines gradually fade out, leaving a trail 229046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy // behind the drag path. 230046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy // Set up all the animations that are used to implement this fading. 231046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy final int duration = res.getInteger(R.integer.config_dragOutlineFadeTime); 232472b281d5cb4f5660df981a6c912266b9f5703feChet Haase final float fromAlphaValue = 0; 233472b281d5cb4f5660df981a6c912266b9f5703feChet Haase final float toAlphaValue = (float)res.getInteger(R.integer.config_dragOutlineMaxAlpha); 2344be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato 2358e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy Arrays.fill(mDragOutlineAlphas, fromAlphaValue); 2364be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato 2374be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato for (int i = 0; i < mDragOutlineAnims.length; i++) { 238046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy final InterruptibleInOutAnimator anim = 239046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy new InterruptibleInOutAnimator(duration, fromAlphaValue, toAlphaValue); 240ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy anim.getAnimator().setInterpolator(mEaseOutInterpolator); 241046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy final int thisIndex = i; 242472b281d5cb4f5660df981a6c912266b9f5703feChet Haase anim.getAnimator().addUpdateListener(new AnimatorUpdateListener() { 243de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy public void onAnimationUpdate(ValueAnimator animation) { 2444be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato final Bitmap outline = (Bitmap)anim.getTag(); 2454be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato 2464be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // If an animation is started and then stopped very quickly, we can still 2474be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // get spurious updates we've cleared the tag. Guard against this. 2484be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato if (outline == null) { 2493a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka @SuppressWarnings("all") // suppress dead code warning 2503a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka final boolean debug = false; 2513a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka if (debug) { 252fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy Object val = animation.getAnimatedValue(); 253fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy Log.d(TAG, "anim " + thisIndex + " update: " + val + 254fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy ", isStopped " + anim.isStopped()); 255fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy } 2564be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // Try to prevent it from continuing to run 2574be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato animation.cancel(); 2584be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato } else { 259472b281d5cb4f5660df981a6c912266b9f5703feChet Haase mDragOutlineAlphas[thisIndex] = (Float) animation.getAnimatedValue(); 260d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen CellLayout.this.invalidate(mDragOutlines[thisIndex]); 2614be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato } 262de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy } 263de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy }); 2644be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // The animation holds a reference to the drag outline bitmap as long is it's 2654be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // running. This way the bitmap can be GCed when the animations are complete. 266472b281d5cb4f5660df981a6c912266b9f5703feChet Haase anim.getAnimator().addListener(new AnimatorListenerAdapter() { 2673c4c20fbe682cb4b3ef94f09afe0af09171583f3Michael Jurka @Override 2684be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato public void onAnimationEnd(Animator animation) { 269472b281d5cb4f5660df981a6c912266b9f5703feChet Haase if ((Float) ((ValueAnimator) animation).getAnimatedValue() == 0f) { 2704be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato anim.setTag(null); 2714be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato } 2724be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato } 2734be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato }); 2744be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato mDragOutlineAnims[i] = anim; 275de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy } 276ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy 27718014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka mBackgroundRect = new Rect(); 278b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mForegroundRect = new Rect(); 279bea15195346bab3c52b0156e92f2b71f0811b210Michael Jurka 280a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets = new ShortcutAndWidgetContainer(context); 281a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.setCellDimensions(mCellWidth, mCellHeight, mWidthGap, mHeightGap); 282a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka addView(mShortcutsAndWidgets); 28318014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka } 28418014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka 285f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka static int widthInPortrait(Resources r, int numCells) { 286f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka // We use this method from Workspace to figure out how many rows/columns Launcher should 287f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka // have. We ignore the left/right padding on CellLayout because it turns out in our design 288f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka // the padding extends outside the visible screen size, but it looked fine anyway. 289f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka int cellWidth = r.getDimensionPixelSize(R.dimen.workspace_cell_width); 2904b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung int minGap = Math.min(r.getDimensionPixelSize(R.dimen.workspace_width_gap), 2914b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung r.getDimensionPixelSize(R.dimen.workspace_height_gap)); 292f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka 2934b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung return minGap * (numCells - 1) + cellWidth * numCells; 294f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka } 295f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka 296f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka static int heightInLandscape(Resources r, int numCells) { 297f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka // We use this method from Workspace to figure out how many rows/columns Launcher should 298f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka // have. We ignore the left/right padding on CellLayout because it turns out in our design 299f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka // the padding extends outside the visible screen size, but it looked fine anyway. 300f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka int cellHeight = r.getDimensionPixelSize(R.dimen.workspace_cell_height); 3014b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung int minGap = Math.min(r.getDimensionPixelSize(R.dimen.workspace_width_gap), 3024b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung r.getDimensionPixelSize(R.dimen.workspace_height_gap)); 303f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka 3044b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung return minGap * (numCells - 1) + cellHeight * numCells; 305f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka } 306f6440da9d02f3ee1553db4bd431a202eb1d1a9ddMichael Jurka 3072801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen public void enableHardwareLayers() { 308a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.enableHardwareLayers(); 3092801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen } 3102801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen 3112801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen public void setGridSize(int x, int y) { 3122801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen mCountX = x; 3132801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen mCountY = y; 3142801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen mOccupied = new boolean[mCountX][mCountY]; 315482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mTmpOccupied = new boolean[mCountX][mCountY]; 3167fbec10b36818f100b631f3d73fe1ad5360975aaAdam Cohen mTempRectStack.clear(); 31776fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen requestLayout(); 3182801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen } 3192801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen 32096864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy private void invalidateBubbleTextView(BubbleTextView icon) { 32196864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy final int padding = icon.getPressedOrFocusedBackgroundPadding(); 3224b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung invalidate(icon.getLeft() + getPaddingLeft() - padding, 3234b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung icon.getTop() + getPaddingTop() - padding, 3244b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung icon.getRight() + getPaddingLeft() + padding, 3254b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung icon.getBottom() + getPaddingTop() + padding); 32696864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy } 32796864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy 328b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen void setOverScrollAmount(float r, boolean left) { 329b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen if (left && mOverScrollForegroundDrawable != mOverScrollLeft) { 330b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mOverScrollForegroundDrawable = mOverScrollLeft; 331b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen } else if (!left && mOverScrollForegroundDrawable != mOverScrollRight) { 332b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mOverScrollForegroundDrawable = mOverScrollRight; 333b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen } 334b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen 335b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mForegroundAlpha = (int) Math.round((r * 255)); 336b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mOverScrollForegroundDrawable.setAlpha(mForegroundAlpha); 337b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen invalidate(); 338b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen } 339b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen 34096864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy void setPressedOrFocusedIcon(BubbleTextView icon) { 34196864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy // We draw the pressed or focused BubbleTextView's background in CellLayout because it 34296864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy // requires an expanded clip rect (due to the glow's blur radius) 34396864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy BubbleTextView oldIcon = mPressedOrFocusedIcon; 34496864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy mPressedOrFocusedIcon = icon; 34596864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy if (oldIcon != null) { 34696864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy invalidateBubbleTextView(oldIcon); 34796864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy } 34896864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy if (mPressedOrFocusedIcon != null) { 34996864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy invalidateBubbleTextView(mPressedOrFocusedIcon); 35096864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy } 35196864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy } 35296864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy 35333945b21544bc98381df17726a3537c292d8c985Michael Jurka void setIsDragOverlapping(boolean isDragOverlapping) { 35433945b21544bc98381df17726a3537c292d8c985Michael Jurka if (mIsDragOverlapping != isDragOverlapping) { 35533945b21544bc98381df17726a3537c292d8c985Michael Jurka mIsDragOverlapping = isDragOverlapping; 35633945b21544bc98381df17726a3537c292d8c985Michael Jurka invalidate(); 35733945b21544bc98381df17726a3537c292d8c985Michael Jurka } 35833945b21544bc98381df17726a3537c292d8c985Michael Jurka } 35933945b21544bc98381df17726a3537c292d8c985Michael Jurka 36033945b21544bc98381df17726a3537c292d8c985Michael Jurka boolean getIsDragOverlapping() { 36133945b21544bc98381df17726a3537c292d8c985Michael Jurka return mIsDragOverlapping; 36233945b21544bc98381df17726a3537c292d8c985Michael Jurka } 36333945b21544bc98381df17726a3537c292d8c985Michael Jurka 364ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen protected void setOverscrollTransformsDirty(boolean dirty) { 365ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen mScrollingTransformsDirty = dirty; 366ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen } 367ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen 368ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen protected void resetOverscrollTransforms() { 369ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen if (mScrollingTransformsDirty) { 370ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen setOverscrollTransformsDirty(false); 371ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen setTranslationX(0); 372ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen setRotationY(0); 373ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen // It doesn't matter if we pass true or false here, the important thing is that we 374ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen // pass 0, which results in the overscroll drawable not being drawn any more. 375ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen setOverScrollAmount(0, false); 376ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen setPivotX(getMeasuredWidth() / 2); 377ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen setPivotY(getMeasuredHeight() / 2); 378ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen } 379ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen } 380ebea84d1c95f4c38ba8cee46cd586fd757b4fce2Adam Cohen 381a6abce8464b57ce91e8f083951ad263370fc2da8Romain Guy @Override 3821262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy protected void onDraw(Canvas canvas) { 3833e7c7634531302271270c8cf418abc959d621cbcMichael Jurka // When we're large, we are either drawn in a "hover" state (ie when dragging an item to 3843e7c7634531302271270c8cf418abc959d621cbcMichael Jurka // a neighboring page) or with just a normal background (if backgroundAlpha > 0.0f) 3853e7c7634531302271270c8cf418abc959d621cbcMichael Jurka // When we're small, we are either drawn normally or in the "accepts drops" state (during 3863e7c7634531302271270c8cf418abc959d621cbcMichael Jurka // a drag). However, we also drag the mini hover background *over* one of those two 3873e7c7634531302271270c8cf418abc959d621cbcMichael Jurka // backgrounds 388b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung if (mBackgroundAlpha > 0.0f) { 389f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen Drawable bg; 39033945b21544bc98381df17726a3537c292d8c985Michael Jurka 39133945b21544bc98381df17726a3537c292d8c985Michael Jurka if (mIsDragOverlapping) { 39233945b21544bc98381df17726a3537c292d8c985Michael Jurka // In the mini case, we draw the active_glow bg *over* the active background 393bdf78559f223ac11e01e3311edd5a48a80383e1eMichael Jurka bg = mActiveGlowBackground; 394f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen } else { 395bdf78559f223ac11e01e3311edd5a48a80383e1eMichael Jurka bg = mNormalBackground; 396f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen } 39733945b21544bc98381df17726a3537c292d8c985Michael Jurka 39833945b21544bc98381df17726a3537c292d8c985Michael Jurka bg.setAlpha((int) (mBackgroundAlpha * mBackgroundAlphaMultiplier * 255)); 39933945b21544bc98381df17726a3537c292d8c985Michael Jurka bg.setBounds(mBackgroundRect); 40033945b21544bc98381df17726a3537c292d8c985Michael Jurka bg.draw(canvas); 401a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka } 40231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 4038e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy final Paint paint = mDragOutlinePaint; 4044be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato for (int i = 0; i < mDragOutlines.length; i++) { 405472b281d5cb4f5660df981a6c912266b9f5703feChet Haase final float alpha = mDragOutlineAlphas[i]; 4064be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato if (alpha > 0) { 407d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen final Rect r = mDragOutlines[i]; 4084be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato final Bitmap b = (Bitmap) mDragOutlineAnims[i].getTag(); 409472b281d5cb4f5660df981a6c912266b9f5703feChet Haase paint.setAlpha((int)(alpha + .5f)); 410d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen canvas.drawBitmap(b, null, r, paint); 411150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung } 4126569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy } 41396864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy 41496864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy // We draw the pressed or focused BubbleTextView's background in CellLayout because it 41596864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy // requires an expanded clip rect (due to the glow's blur radius) 41696864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy if (mPressedOrFocusedIcon != null) { 41796864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy final int padding = mPressedOrFocusedIcon.getPressedOrFocusedBackgroundPadding(); 41896864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy final Bitmap b = mPressedOrFocusedIcon.getPressedOrFocusedBackground(); 41996864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy if (b != null) { 42096864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy canvas.drawBitmap(b, 4214b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung mPressedOrFocusedIcon.getLeft() + getPaddingLeft() - padding, 4224b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung mPressedOrFocusedIcon.getTop() + getPaddingTop() - padding, 42396864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy null); 42496864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy } 42596864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy } 42669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 427482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (DEBUG_VISUALIZE_OCCUPIED) { 428482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int[] pt = new int[2]; 429482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen ColorDrawable cd = new ColorDrawable(Color.RED); 430e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen cd.setBounds(0, 0, mCellWidth, mCellHeight); 431482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < mCountX; i++) { 432482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int j = 0; j < mCountY; j++) { 433482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (mOccupied[i][j]) { 434482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen cellToPoint(i, j, pt); 435482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen canvas.save(); 436482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen canvas.translate(pt[0], pt[1]); 437482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen cd.draw(canvas); 438482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen canvas.restore(); 439482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 440482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 441482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 442482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 443482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 444850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn int previewOffset = FolderRingAnimator.sPreviewSize; 445850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn 44669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen // The folder outer / inner ring image(s) 44769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen for (int i = 0; i < mFolderOuterRings.size(); i++) { 44869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen FolderRingAnimator fra = mFolderOuterRings.get(i); 44969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 45069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen // Draw outer ring 45169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen Drawable d = FolderRingAnimator.sSharedOuterRingDrawable; 45269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen int width = (int) fra.getOuterRingSize(); 45369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen int height = width; 45469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen cellToPoint(fra.mCellX, fra.mCellY, mTempLocation); 45569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 45669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen int centerX = mTempLocation[0] + mCellWidth / 2; 457850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn int centerY = mTempLocation[1] + previewOffset / 2; 45869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 45969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen canvas.save(); 46069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen canvas.translate(centerX - width / 2, centerY - height / 2); 46169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen d.setBounds(0, 0, width, height); 46269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen d.draw(canvas); 46369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen canvas.restore(); 46469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 46569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen // Draw inner ring 46669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen d = FolderRingAnimator.sSharedInnerRingDrawable; 46769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen width = (int) fra.getInnerRingSize(); 46869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen height = width; 46969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen cellToPoint(fra.mCellX, fra.mCellY, mTempLocation); 47069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 47169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen centerX = mTempLocation[0] + mCellWidth / 2; 472850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn centerY = mTempLocation[1] + previewOffset / 2; 47369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen canvas.save(); 47469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen canvas.translate(centerX - width / 2, centerY - width / 2); 47569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen d.setBounds(0, 0, width, height); 47669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen d.draw(canvas); 47769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen canvas.restore(); 47869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen } 479c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen 480c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen if (mFolderLeaveBehindCell[0] >= 0 && mFolderLeaveBehindCell[1] >= 0) { 481c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen Drawable d = FolderIcon.sSharedFolderLeaveBehind; 482c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen int width = d.getIntrinsicWidth(); 483c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen int height = d.getIntrinsicHeight(); 484c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen 485c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen cellToPoint(mFolderLeaveBehindCell[0], mFolderLeaveBehindCell[1], mTempLocation); 486c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen int centerX = mTempLocation[0] + mCellWidth / 2; 487850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn int centerY = mTempLocation[1] + previewOffset / 2; 488c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen 489c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen canvas.save(); 490c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen canvas.translate(centerX - width / 2, centerY - width / 2); 491c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen d.setBounds(0, 0, width, height); 492c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen d.draw(canvas); 493c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen canvas.restore(); 494c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen } 49569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen } 49669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 497b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen @Override 498b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen protected void dispatchDraw(Canvas canvas) { 499b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen super.dispatchDraw(canvas); 500b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen if (mForegroundAlpha > 0) { 501b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mOverScrollForegroundDrawable.setBounds(mForegroundRect); 502b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen Paint p = ((NinePatchDrawable) mOverScrollForegroundDrawable).getPaint(); 5038a0bff5e35f63321178bbf777ec24d42544866b3Romain Guy p.setXfermode(sAddBlendMode); 504b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mOverScrollForegroundDrawable.draw(canvas); 505b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen p.setXfermode(null); 506b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen } 507b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen } 508b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen 50969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen public void showFolderAccept(FolderRingAnimator fra) { 51069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen mFolderOuterRings.add(fra); 51169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen } 51269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 51369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen public void hideFolderAccept(FolderRingAnimator fra) { 51469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen if (mFolderOuterRings.contains(fra)) { 51569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen mFolderOuterRings.remove(fra); 51669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen } 51769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen invalidate(); 5186569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy } 5196569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 520c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen public void setFolderLeaveBehindCell(int x, int y) { 521c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen mFolderLeaveBehindCell[0] = x; 522c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen mFolderLeaveBehindCell[1] = y; 523c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen invalidate(); 524c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen } 525c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen 526c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen public void clearFolderLeaveBehind() { 527c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen mFolderLeaveBehindCell[0] = -1; 528c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen mFolderLeaveBehindCell[1] = -1; 529c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen invalidate(); 530c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen } 531c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen 5326569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy @Override 533e6235dd225404239b55c459245543f3302326112Michael Jurka public boolean shouldDelayChildPressedState() { 534e6235dd225404239b55c459245543f3302326112Michael Jurka return false; 535e6235dd225404239b55c459245543f3302326112Michael Jurka } 536e6235dd225404239b55c459245543f3302326112Michael Jurka 5371462de39f01cec0ba785386532719cb0207dd827Adam Cohen public void restoreInstanceState(SparseArray<Parcelable> states) { 5381462de39f01cec0ba785386532719cb0207dd827Adam Cohen dispatchRestoreInstanceState(states); 5391462de39f01cec0ba785386532719cb0207dd827Adam Cohen } 5401462de39f01cec0ba785386532719cb0207dd827Adam Cohen 541e6235dd225404239b55c459245543f3302326112Michael Jurka @Override 54283f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey public void cancelLongPress() { 54383f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey super.cancelLongPress(); 54483f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey 54583f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey // Cancel long press for all children 54683f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey final int count = getChildCount(); 54783f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey for (int i = 0; i < count; i++) { 54883f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey final View child = getChildAt(i); 54983f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey child.cancelLongPress(); 55083f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey } 55183f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey } 55283f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey 553dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka public void setOnInterceptTouchListener(View.OnTouchListener listener) { 554dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka mInterceptTouchListener = listener; 555dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } 556dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka 55731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int getCountX() { 558d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen return mCountX; 55931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 56031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 56131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int getCountY() { 562d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen return mCountY; 56331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 56431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 5650dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn public void setIsHotseat(boolean isHotseat) { 5660dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn mIsHotseat = isHotseat; 5670dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn } 5680dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn 5690dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn public boolean addViewToCellLayout(View child, int index, int childId, LayoutParams params, 570850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn boolean markCells) { 571aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung final LayoutParams lp = params; 572aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 573de38e42fe89fd7490221427908cd97c51da21b44Andrew Flynn // Hotseat icons - remove text 5740dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn if (child instanceof BubbleTextView) { 5750dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn BubbleTextView bubbleChild = (BubbleTextView) child; 5760dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn 577de38e42fe89fd7490221427908cd97c51da21b44Andrew Flynn Resources res = getResources(); 578de38e42fe89fd7490221427908cd97c51da21b44Andrew Flynn if (mIsHotseat) { 579de38e42fe89fd7490221427908cd97c51da21b44Andrew Flynn bubbleChild.setTextColor(res.getColor(android.R.color.transparent)); 580de38e42fe89fd7490221427908cd97c51da21b44Andrew Flynn } else { 581de38e42fe89fd7490221427908cd97c51da21b44Andrew Flynn bubbleChild.setTextColor(res.getColor(R.color.workspace_icon_text_color)); 5820dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn } 5830dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn } 5840dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn 58531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // Generate an id for each view, this assumes we have at most 256x256 cells 58631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // per workspace screen 587d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen if (lp.cellX >= 0 && lp.cellX <= mCountX - 1 && lp.cellY >= 0 && lp.cellY <= mCountY - 1) { 588aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung // If the horizontal or vertical span is set to -1, it is taken to 589aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung // mean that it spans the extent of the CellLayout 590d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen if (lp.cellHSpan < 0) lp.cellHSpan = mCountX; 591d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen if (lp.cellVSpan < 0) lp.cellVSpan = mCountY; 592aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 593aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung child.setId(childId); 59431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 595a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.addView(child, index, lp); 596dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka 597f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka if (markCells) markCellsAsOccupiedForView(child); 5980280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 599aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung return true; 600aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung } 601aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung return false; 60231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 6033e7c7634531302271270c8cf418abc959d621cbcMichael Jurka 60431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 6050280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka public void removeAllViews() { 6060280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka clearOccupiedCells(); 607a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.removeAllViews(); 6080280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 6090280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 6100280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka @Override 6110280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka public void removeAllViewsInLayout() { 612a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka if (mShortcutsAndWidgets.getChildCount() > 0) { 6137cfc2825c3a1029f962d2fc387ae2eaa85b51798Michael Jurka clearOccupiedCells(); 614a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.removeAllViewsInLayout(); 6157cfc2825c3a1029f962d2fc387ae2eaa85b51798Michael Jurka } 6160280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 6170280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 618f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka public void removeViewWithoutMarkingCells(View view) { 619a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.removeView(view); 620f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka } 621f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka 6220280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka @Override 6230280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka public void removeView(View view) { 6240280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka markCellsAsUnoccupiedForView(view); 625a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.removeView(view); 6260280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 6270280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 6280280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka @Override 6290280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka public void removeViewAt(int index) { 630a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka markCellsAsUnoccupiedForView(mShortcutsAndWidgets.getChildAt(index)); 631a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.removeViewAt(index); 6320280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 6330280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 6340280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka @Override 6350280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka public void removeViewInLayout(View view) { 6360280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka markCellsAsUnoccupiedForView(view); 637a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.removeViewInLayout(view); 6380280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 6390280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 6400280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka @Override 6410280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka public void removeViews(int start, int count) { 6420280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka for (int i = start; i < start + count; i++) { 643a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka markCellsAsUnoccupiedForView(mShortcutsAndWidgets.getChildAt(i)); 6440280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 645a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.removeViews(start, count); 6460280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 6470280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 6480280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka @Override 6490280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka public void removeViewsInLayout(int start, int count) { 6500280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka for (int i = start; i < start + count; i++) { 651a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka markCellsAsUnoccupiedForView(mShortcutsAndWidgets.getChildAt(i)); 6520280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 653a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.removeViewsInLayout(start, count); 654abded66084680bb31cc7ea403c88f44f79a3c884Michael Jurka } 655abded66084680bb31cc7ea403c88f44f79a3c884Michael Jurka 65631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 65731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected void onAttachedToWindow() { 65831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project super.onAttachedToWindow(); 65931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mCellInfo.screen = ((ViewGroup) getParent()).indexOfChild(this); 66031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 66131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 662af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka public void setTagToCellInfoForPoint(int touchX, int touchY) { 66331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final CellInfo cellInfo = mCellInfo; 664eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung Rect frame = mRect; 6658b805b17158886035b38261eb611d8641701ae43Michael Jurka final int x = touchX + getScrollX(); 6668b805b17158886035b38261eb611d8641701ae43Michael Jurka final int y = touchY + getScrollY(); 667a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka final int count = mShortcutsAndWidgets.getChildCount(); 66831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 669af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka boolean found = false; 670af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka for (int i = count - 1; i >= 0; i--) { 671a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka final View child = mShortcutsAndWidgets.getChildAt(i); 672d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 673af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka 6741b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen if ((child.getVisibility() == VISIBLE || child.getAnimation() != null) && 6751b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen lp.isLockedToGrid) { 676af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka child.getHitRect(frame); 6770be025d64c1f84138fe430a58875886e66aae767Winson Chung 678eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung float scale = child.getScaleX(); 679eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung frame = new Rect(child.getLeft(), child.getTop(), child.getRight(), 680eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung child.getBottom()); 6810be025d64c1f84138fe430a58875886e66aae767Winson Chung // The child hit rect is relative to the CellLayoutChildren parent, so we need to 6820be025d64c1f84138fe430a58875886e66aae767Winson Chung // offset that by this CellLayout's padding to test an (x,y) point that is relative 6830be025d64c1f84138fe430a58875886e66aae767Winson Chung // to this view. 6848b805b17158886035b38261eb611d8641701ae43Michael Jurka frame.offset(getPaddingLeft(), getPaddingTop()); 685eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung frame.inset((int) (frame.width() * (1f - scale) / 2), 686eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung (int) (frame.height() * (1f - scale) / 2)); 6870be025d64c1f84138fe430a58875886e66aae767Winson Chung 688af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka if (frame.contains(x, y)) { 689af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.cell = child; 690af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.cellX = lp.cellX; 691af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.cellY = lp.cellY; 692af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.spanX = lp.cellHSpan; 693af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.spanY = lp.cellVSpan; 694af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka found = true; 695af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka break; 69631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 69731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 698af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka } 699aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 700d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka mLastDownOnOccupiedCell = found; 701d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka 702af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka if (!found) { 7030be025d64c1f84138fe430a58875886e66aae767Winson Chung final int cellXY[] = mTmpXY; 704af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka pointToCellExact(x, y, cellXY); 70531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 706af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.cell = null; 707af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.cellX = cellXY[0]; 708af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.cellY = cellXY[1]; 709af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.spanX = 1; 710af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka cellInfo.spanY = 1; 711af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka } 712af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka setTag(cellInfo); 713af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka } 71431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 715af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka @Override 716af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka public boolean onInterceptTouchEvent(MotionEvent ev) { 717c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen // First we clear the tag to ensure that on every touch down we start with a fresh slate, 718c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen // even in the case where we return early. Not clearing here was causing bugs whereby on 719c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen // long-press we'd end up picking up an item from a previous drag operation. 720c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen final int action = ev.getAction(); 721c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen 722c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen if (action == MotionEvent.ACTION_DOWN) { 723c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen clearTagCellInfo(); 724c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen } 725c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen 726dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka if (mInterceptTouchListener != null && mInterceptTouchListener.onTouch(this, ev)) { 727dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka return true; 728dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } 72931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 730af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka if (action == MotionEvent.ACTION_DOWN) { 731af44209bfa60da3c7ab49b7f508f9effd316ee41Michael Jurka setTagToCellInfoForPoint((int) ev.getX(), (int) ev.getY()); 73231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 733eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung 73431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return false; 73531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 73631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 737c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen private void clearTagCellInfo() { 738c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen final CellInfo cellInfo = mCellInfo; 739c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen cellInfo.cell = null; 740c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen cellInfo.cellX = -1; 741c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen cellInfo.cellY = -1; 742c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen cellInfo.spanX = 0; 743c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen cellInfo.spanY = 0; 744c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen setTag(cellInfo); 745c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen } 746c1997fd6debbc69b53be71b7d871657fd5843c7aAdam Cohen 74731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public CellInfo getTag() { 7480280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka return (CellInfo) super.getTag(); 74931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 75031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 7516569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy /** 752aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * Given a point, return the cell that strictly encloses that point 75331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param x X coordinate of the point 75431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param y Y coordinate of the point 75531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param result Array of 2 ints to hold the x and y coordinate of the cell 75631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 75731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project void pointToCellExact(int x, int y, int[] result) { 7584b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung final int hStartPadding = getPaddingLeft(); 7594b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung final int vStartPadding = getPaddingTop(); 76031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 76131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project result[0] = (x - hStartPadding) / (mCellWidth + mWidthGap); 76231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project result[1] = (y - vStartPadding) / (mCellHeight + mHeightGap); 76331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 764d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen final int xAxis = mCountX; 765d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen final int yAxis = mCountY; 76631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 76731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (result[0] < 0) result[0] = 0; 76831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (result[0] >= xAxis) result[0] = xAxis - 1; 76931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (result[1] < 0) result[1] = 0; 77031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (result[1] >= yAxis) result[1] = yAxis - 1; 77131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 772aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 77331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 77431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Given a point, return the cell that most closely encloses that point 77531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param x X coordinate of the point 77631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param y Y coordinate of the point 77731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param result Array of 2 ints to hold the x and y coordinate of the cell 77831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 77931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project void pointToCellRounded(int x, int y, int[] result) { 78031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project pointToCellExact(x + (mCellWidth / 2), y + (mCellHeight / 2), result); 78131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 78231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 78331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 78431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Given a cell coordinate, return the point that represents the upper left corner of that cell 785aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * 786aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * @param cellX X coordinate of the cell 78731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param cellY Y coordinate of the cell 788aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * 78931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param result Array of 2 ints to hold the x and y coordinate of the point 79031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 79131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project void cellToPoint(int cellX, int cellY, int[] result) { 7924b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung final int hStartPadding = getPaddingLeft(); 7934b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung final int vStartPadding = getPaddingTop(); 79431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 79531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project result[0] = hStartPadding + cellX * (mCellWidth + mWidthGap); 79631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project result[1] = vStartPadding + cellY * (mCellHeight + mHeightGap); 79731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 79831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 799e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen /** 800482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * Given a cell coordinate, return the point that represents the center of the cell 801e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen * 802e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen * @param cellX X coordinate of the cell 803e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen * @param cellY Y coordinate of the cell 804e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen * 805e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen * @param result Array of 2 ints to hold the x and y coordinate of the point 806e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen */ 807e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen void cellToCenterPoint(int cellX, int cellY, int[] result) { 80847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen regionToCenterPoint(cellX, cellY, 1, 1, result); 80947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 81047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 81147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen /** 81247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * Given a cell coordinate and span return the point that represents the center of the regio 81347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * 81447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param cellX X coordinate of the cell 81547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param cellY Y coordinate of the cell 81647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * 81747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param result Array of 2 ints to hold the x and y coordinate of the point 81847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen */ 81947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen void regionToCenterPoint(int cellX, int cellY, int spanX, int spanY, int[] result) { 8204b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung final int hStartPadding = getPaddingLeft(); 8214b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung final int vStartPadding = getPaddingTop(); 82247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen result[0] = hStartPadding + cellX * (mCellWidth + mWidthGap) + 82347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen (spanX * mCellWidth + (spanX - 1) * mWidthGap) / 2; 82447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen result[1] = vStartPadding + cellY * (mCellHeight + mHeightGap) + 82547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen (spanY * mCellHeight + (spanY - 1) * mHeightGap) / 2; 826e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen } 827e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen 82819f3792523fe2d55ea791a9286398a6120920690Adam Cohen /** 82919f3792523fe2d55ea791a9286398a6120920690Adam Cohen * Given a cell coordinate and span fills out a corresponding pixel rect 83019f3792523fe2d55ea791a9286398a6120920690Adam Cohen * 83119f3792523fe2d55ea791a9286398a6120920690Adam Cohen * @param cellX X coordinate of the cell 83219f3792523fe2d55ea791a9286398a6120920690Adam Cohen * @param cellY Y coordinate of the cell 83319f3792523fe2d55ea791a9286398a6120920690Adam Cohen * @param result Rect in which to write the result 83419f3792523fe2d55ea791a9286398a6120920690Adam Cohen */ 83519f3792523fe2d55ea791a9286398a6120920690Adam Cohen void regionToRect(int cellX, int cellY, int spanX, int spanY, Rect result) { 83619f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int hStartPadding = getPaddingLeft(); 83719f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int vStartPadding = getPaddingTop(); 83819f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int left = hStartPadding + cellX * (mCellWidth + mWidthGap); 83919f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int top = vStartPadding + cellY * (mCellHeight + mHeightGap); 84019f3792523fe2d55ea791a9286398a6120920690Adam Cohen result.set(left, top, left + (spanX * mCellWidth + (spanX - 1) * mWidthGap), 84119f3792523fe2d55ea791a9286398a6120920690Adam Cohen top + (spanY * mCellHeight + (spanY - 1) * mHeightGap)); 84219f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 84319f3792523fe2d55ea791a9286398a6120920690Adam Cohen 844482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public float getDistanceFromCell(float x, float y, int[] cell) { 845482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen cellToCenterPoint(cell[0], cell[1], mTmpPoint); 846482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen float distance = (float) Math.sqrt( Math.pow(x - mTmpPoint[0], 2) + 847482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen Math.pow(y - mTmpPoint[1], 2)); 848482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return distance; 849482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 850482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 85184f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy int getCellWidth() { 85284f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy return mCellWidth; 85384f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy } 85484f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy 85584f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy int getCellHeight() { 85684f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy return mCellHeight; 85784f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy } 85884f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy 859d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen int getWidthGap() { 860d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen return mWidthGap; 861d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen } 862d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen 863d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen int getHeightGap() { 864d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen return mHeightGap; 865d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen } 866d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen 8677f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen Rect getContentRect(Rect r) { 8687f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen if (r == null) { 8697f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen r = new Rect(); 8707f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 8717f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen int left = getPaddingLeft(); 8727f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen int top = getPaddingTop(); 8738b805b17158886035b38261eb611d8641701ae43Michael Jurka int right = left + getWidth() - getPaddingLeft() - getPaddingRight(); 8748b805b17158886035b38261eb611d8641701ae43Michael Jurka int bottom = top + getHeight() - getPaddingTop() - getPaddingBottom(); 8757f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen r.set(left, top, right, bottom); 8767f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen return r; 8777f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 8787f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 879a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen static void getMetrics(Rect metrics, Resources res, int measureWidth, int measureHeight, 880a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen int countX, int countY, int orientation) { 881a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen int numWidthGaps = countX - 1; 882a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen int numHeightGaps = countY - 1; 883f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen 884f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen int widthGap; 885f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen int heightGap; 886f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen int cellWidth; 887f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen int cellHeight; 888f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen int paddingLeft; 889f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen int paddingRight; 890f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen int paddingTop; 891f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen int paddingBottom; 892f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen 893a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen int maxGap = res.getDimensionPixelSize(R.dimen.workspace_max_gap); 894f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen if (orientation == LANDSCAPE) { 895f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen cellWidth = res.getDimensionPixelSize(R.dimen.workspace_cell_width_land); 896f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen cellHeight = res.getDimensionPixelSize(R.dimen.workspace_cell_height_land); 897f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen widthGap = res.getDimensionPixelSize(R.dimen.workspace_width_gap_land); 898f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen heightGap = res.getDimensionPixelSize(R.dimen.workspace_height_gap_land); 899f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen paddingLeft = res.getDimensionPixelSize(R.dimen.cell_layout_left_padding_land); 900f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen paddingRight = res.getDimensionPixelSize(R.dimen.cell_layout_right_padding_land); 901f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen paddingTop = res.getDimensionPixelSize(R.dimen.cell_layout_top_padding_land); 902f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen paddingBottom = res.getDimensionPixelSize(R.dimen.cell_layout_bottom_padding_land); 903f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen } else { 904f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen // PORTRAIT 905f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen cellWidth = res.getDimensionPixelSize(R.dimen.workspace_cell_width_port); 906f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen cellHeight = res.getDimensionPixelSize(R.dimen.workspace_cell_height_port); 907f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen widthGap = res.getDimensionPixelSize(R.dimen.workspace_width_gap_port); 908f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen heightGap = res.getDimensionPixelSize(R.dimen.workspace_height_gap_port); 909f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen paddingLeft = res.getDimensionPixelSize(R.dimen.cell_layout_left_padding_port); 910f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen paddingRight = res.getDimensionPixelSize(R.dimen.cell_layout_right_padding_port); 911f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen paddingTop = res.getDimensionPixelSize(R.dimen.cell_layout_top_padding_port); 912f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen paddingBottom = res.getDimensionPixelSize(R.dimen.cell_layout_bottom_padding_port); 913f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen } 914f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen 915f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen if (widthGap < 0 || heightGap < 0) { 916f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen int hSpace = measureWidth - paddingLeft - paddingRight; 917f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen int vSpace = measureHeight - paddingTop - paddingBottom; 918a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen int hFreeSpace = hSpace - (countX * cellWidth); 919a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen int vFreeSpace = vSpace - (countY * cellHeight); 920a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen widthGap = Math.min(maxGap, numWidthGaps > 0 ? (hFreeSpace / numWidthGaps) : 0); 921a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen heightGap = Math.min(maxGap, numHeightGaps > 0 ? (vFreeSpace / numHeightGaps) : 0); 922f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen } 923f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen metrics.set(cellWidth, cellHeight, widthGap, heightGap); 924f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen } 925f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen 92631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 92731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 92831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec); 929aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec); 930aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 93131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec); 93231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec); 933aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 93431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (widthSpecMode == MeasureSpec.UNSPECIFIED || heightSpecMode == MeasureSpec.UNSPECIFIED) { 93531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project throw new RuntimeException("CellLayout cannot have UNSPECIFIED dimensions"); 93631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 93731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 938d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen int numWidthGaps = mCountX - 1; 939d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen int numHeightGaps = mCountY - 1; 940d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen 941234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen if (mOriginalWidthGap < 0 || mOriginalHeightGap < 0) { 942dd13e3d0f9925b7bb80c37e21d039aab4fa7e7a1Michael Jurka int hSpace = widthSpecSize - getPaddingLeft() - getPaddingRight(); 943dd13e3d0f9925b7bb80c37e21d039aab4fa7e7a1Michael Jurka int vSpace = heightSpecSize - getPaddingTop() - getPaddingBottom(); 944f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen int hFreeSpace = hSpace - (mCountX * mCellWidth); 945f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen int vFreeSpace = vSpace - (mCountY * mCellHeight); 9464b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung mWidthGap = Math.min(mMaxGap, numWidthGaps > 0 ? (hFreeSpace / numWidthGaps) : 0); 9474b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung mHeightGap = Math.min(mMaxGap,numHeightGaps > 0 ? (vFreeSpace / numHeightGaps) : 0); 948a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.setCellDimensions(mCellWidth, mCellHeight, mWidthGap, mHeightGap); 949234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen } else { 950234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen mWidthGap = mOriginalWidthGap; 951234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen mHeightGap = mOriginalHeightGap; 952ece7f5b3b55cab646941123e03589241a61678e2Winson Chung } 9535f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka 9548c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka // Initial values correspond to widthSpecMode == MeasureSpec.EXACTLY 9558c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka int newWidth = widthSpecSize; 9568c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka int newHeight = heightSpecSize; 9578c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka if (widthSpecMode == MeasureSpec.AT_MOST) { 9588b805b17158886035b38261eb611d8641701ae43Michael Jurka newWidth = getPaddingLeft() + getPaddingRight() + (mCountX * mCellWidth) + 9598c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka ((mCountX - 1) * mWidthGap); 9608b805b17158886035b38261eb611d8641701ae43Michael Jurka newHeight = getPaddingTop() + getPaddingBottom() + (mCountY * mCellHeight) + 9618c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka ((mCountY - 1) * mHeightGap); 9628c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka setMeasuredDimension(newWidth, newHeight); 9638c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka } 96431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 9658c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka int count = getChildCount(); 96631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int i = 0; i < count; i++) { 96731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project View child = getChildAt(i); 9688b805b17158886035b38261eb611d8641701ae43Michael Jurka int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(newWidth - getPaddingLeft() - 9698b805b17158886035b38261eb611d8641701ae43Michael Jurka getPaddingRight(), MeasureSpec.EXACTLY); 9708b805b17158886035b38261eb611d8641701ae43Michael Jurka int childheightMeasureSpec = MeasureSpec.makeMeasureSpec(newHeight - getPaddingTop() - 9718b805b17158886035b38261eb611d8641701ae43Michael Jurka getPaddingBottom(), MeasureSpec.EXACTLY); 97231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project child.measure(childWidthMeasureSpec, childheightMeasureSpec); 97331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 9748c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka setMeasuredDimension(newWidth, newHeight); 97531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 97631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 97731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 97828750fba6a2d141eb9a1e566718c17236030b815Michael Jurka protected void onLayout(boolean changed, int l, int t, int r, int b) { 97931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int count = getChildCount(); 98031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int i = 0; i < count; i++) { 9818c920dd3683d752aa4c43e964831ce53f9b72887Michael Jurka View child = getChildAt(i); 9828b805b17158886035b38261eb611d8641701ae43Michael Jurka child.layout(getPaddingLeft(), getPaddingTop(), 9838b805b17158886035b38261eb611d8641701ae43Michael Jurka r - l - getPaddingRight(), b - t - getPaddingBottom()); 98431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 98531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 98631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 98731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 988dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka protected void onSizeChanged(int w, int h, int oldw, int oldh) { 989dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka super.onSizeChanged(w, h, oldw, oldh); 99018014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka mBackgroundRect.set(0, 0, w, h); 991b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen mForegroundRect.set(mForegroundPadding, mForegroundPadding, 992b5ba097015c4794fa822f30b38a60a7070a00097Adam Cohen w - 2 * mForegroundPadding, h - 2 * mForegroundPadding); 993dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } 994dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka 995dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka @Override 99631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected void setChildrenDrawingCacheEnabled(boolean enabled) { 997a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.setChildrenDrawingCacheEnabled(enabled); 99831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 99931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 100031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 100131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected void setChildrenDrawnWithCacheEnabled(boolean enabled) { 1002a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.setChildrenDrawnWithCacheEnabled(enabled); 100331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 100431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 10055f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka public float getBackgroundAlpha() { 10065f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka return mBackgroundAlpha; 1007dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } 1008dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka 10091b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen public void setBackgroundAlphaMultiplier(float multiplier) { 1010a3d30adbfd4f013260f1f5ba3a56bc9bb4a11717Michael Jurka if (mBackgroundAlphaMultiplier != multiplier) { 1011a3d30adbfd4f013260f1f5ba3a56bc9bb4a11717Michael Jurka mBackgroundAlphaMultiplier = multiplier; 1012a3d30adbfd4f013260f1f5ba3a56bc9bb4a11717Michael Jurka invalidate(); 1013a3d30adbfd4f013260f1f5ba3a56bc9bb4a11717Michael Jurka } 10141b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen } 10151b0aaac0b3abd777ed319341f95a8dfff23c79f4Adam Cohen 1016ddb821981e0919bbd3b4c9a2b6aa1811d6c86bb6Adam Cohen public float getBackgroundAlphaMultiplier() { 1017ddb821981e0919bbd3b4c9a2b6aa1811d6c86bb6Adam Cohen return mBackgroundAlphaMultiplier; 1018ddb821981e0919bbd3b4c9a2b6aa1811d6c86bb6Adam Cohen } 1019ddb821981e0919bbd3b4c9a2b6aa1811d6c86bb6Adam Cohen 10205f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka public void setBackgroundAlpha(float alpha) { 1021afaa05014e0bf3ed1192f9ddec2af4283bc50248Michael Jurka if (mBackgroundAlpha != alpha) { 1022afaa05014e0bf3ed1192f9ddec2af4283bc50248Michael Jurka mBackgroundAlpha = alpha; 1023afaa05014e0bf3ed1192f9ddec2af4283bc50248Michael Jurka invalidate(); 1024afaa05014e0bf3ed1192f9ddec2af4283bc50248Michael Jurka } 1025dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } 1026dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka 1027a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka public void setShortcutAndWidgetAlpha(float alpha) { 10280142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka final int childCount = getChildCount(); 10290142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka for (int i = 0; i < childCount; i++) { 1030dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka getChildAt(i).setAlpha(alpha); 1031dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } 1032dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } 1033dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka 1034a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka public ShortcutAndWidgetContainer getShortcutsAndWidgets() { 1035a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka if (getChildCount() > 0) { 1036a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka return (ShortcutAndWidgetContainer) getChildAt(0); 1037a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka } 1038a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka return null; 1039a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka } 1040a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka 1041440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy public View getChildAt(int x, int y) { 1042a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka return mShortcutsAndWidgets.getChildAt(x, y); 1043440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy } 1044440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy 104576fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen public boolean animateChildToPosition(final View child, int cellX, int cellY, int duration, 1046482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int delay, boolean permanent, boolean adjustOccupied) { 1047a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka ShortcutAndWidgetContainer clc = getShortcutsAndWidgets(); 1048482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean[][] occupied = mOccupied; 1049482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (!permanent) { 1050482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen occupied = mTmpOccupied; 1051482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1052482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 105319f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (clc.indexOfChild(child) != -1) { 1054bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 1055bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen final ItemInfo info = (ItemInfo) child.getTag(); 1056bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen 1057bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen // We cancel any existing animations 1058bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen if (mReorderAnimators.containsKey(lp)) { 1059bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen mReorderAnimators.get(lp).cancel(); 1060bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen mReorderAnimators.remove(lp); 1061bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 1062bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen 1063482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int oldX = lp.x; 1064482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int oldY = lp.y; 1065482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (adjustOccupied) { 1066482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen occupied[lp.cellX][lp.cellY] = false; 1067482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen occupied[cellX][cellY] = true; 1068482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1069bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen lp.isLockedToGrid = true; 1070482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (permanent) { 1071482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen lp.cellX = info.cellX = cellX; 1072482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen lp.cellY = info.cellY = cellY; 1073482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } else { 1074482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen lp.tmpCellX = cellX; 1075482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen lp.tmpCellY = cellY; 1076482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1077bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen clc.setupLp(lp); 1078bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen lp.isLockedToGrid = false; 1079482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int newX = lp.x; 1080482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int newY = lp.y; 1081bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen 108276fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen lp.x = oldX; 108376fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen lp.y = oldY; 108476fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen 1085482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // Exit early if we're not actually moving the view 1086482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (oldX == newX && oldY == newY) { 1087482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen lp.isLockedToGrid = true; 1088482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return true; 1089482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1090482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1091482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen ValueAnimator va = ValueAnimator.ofFloat(0f, 1f); 1092482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen va.setDuration(duration); 1093482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mReorderAnimators.put(lp, va); 1094482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1095482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen va.addUpdateListener(new AnimatorUpdateListener() { 1096482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen @Override 1097bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen public void onAnimationUpdate(ValueAnimator animation) { 1098482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen float r = ((Float) animation.getAnimatedValue()).floatValue(); 109919f3792523fe2d55ea791a9286398a6120920690Adam Cohen lp.x = (int) ((1 - r) * oldX + r * newX); 110019f3792523fe2d55ea791a9286398a6120920690Adam Cohen lp.y = (int) ((1 - r) * oldY + r * newY); 11016b8a02d63a5d9cab8209381993e37db6a6afb753Adam Cohen child.requestLayout(); 1102bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 1103bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen }); 1104482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen va.addListener(new AnimatorListenerAdapter() { 1105bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen boolean cancelled = false; 1106bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen public void onAnimationEnd(Animator animation) { 1107bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen // If the animation was cancelled, it means that another animation 1108bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen // has interrupted this one, and we don't want to lock the item into 1109bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen // place just yet. 1110bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen if (!cancelled) { 1111bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen lp.isLockedToGrid = true; 1112482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen child.requestLayout(); 1113bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 1114bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen if (mReorderAnimators.containsKey(lp)) { 1115bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen mReorderAnimators.remove(lp); 1116bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 1117bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 1118bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen public void onAnimationCancel(Animator animation) { 1119bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen cancelled = true; 1120bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 1121bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen }); 1122482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen va.setStartDelay(delay); 1123482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen va.start(); 1124bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen return true; 1125bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 1126bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen return false; 1127bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 1128bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen 11296569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy /** 11306569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy * Estimate where the top left cell of the dragged item will land if it is dropped. 11316569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy * 11326569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy * @param originX The X value of the top left corner of the item 11336569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy * @param originY The Y value of the top left corner of the item 11346569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy * @param spanX The number of horizontal cells that the item spans 11356569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy * @param spanY The number of vertical cells that the item spans 11366569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy * @param result The estimated drop cell X and Y. 11376569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy */ 11386569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy void estimateDropCell(int originX, int originY, int spanX, int spanY, int[] result) { 1139d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen final int countX = mCountX; 1140d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen final int countY = mCountY; 11416569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 1142a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka // pointToCellRounded takes the top left of a cell but will pad that with 1143a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka // cellWidth/2 and cellHeight/2 when finding the matching cell 1144a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka pointToCellRounded(originX, originY, result); 11456569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 11466569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy // If the item isn't fully on this screen, snap to the edges 11476569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy int rightOverhang = result[0] + spanX - countX; 11486569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy if (rightOverhang > 0) { 11496569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy result[0] -= rightOverhang; // Snap to right 11506569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy } 11516569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy result[0] = Math.max(0, result[0]); // Snap to left 11526569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy int bottomOverhang = result[1] + spanY - countY; 11536569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy if (bottomOverhang > 0) { 11546569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy result[1] -= bottomOverhang; // Snap to bottom 11556569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy } 11566569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy result[1] = Math.max(0, result[1]); // Snap to top 11576569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy } 11586569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 1159482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen void visualizeDropLocation(View v, Bitmap dragOutline, int originX, int originY, int cellX, 1160482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int cellY, int spanX, int spanY, boolean resize, Point dragOffset, Rect dragRegion) { 116108ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy final int oldDragCellX = mDragCell[0]; 116208ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy final int oldDragCellY = mDragCell[1]; 1163482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1164b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung if (v != null && dragOffset == null) { 1165a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung mDragCenter.set(originX + (v.getWidth() / 2), originY + (v.getHeight() / 2)); 1166a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung } else { 1167a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung mDragCenter.set(originX, originY); 1168a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung } 11696569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 11702801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen if (dragOutline == null && v == null) { 11712801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen return; 11722801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen } 11732801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen 1174482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (cellX != oldDragCellX || cellY != oldDragCellY) { 1175482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mDragCell[0] = cellX; 1176482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mDragCell[1] = cellY; 11776569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy // Find the top left corner of the rect the object will occupy 1178de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy final int[] topLeft = mTmpPoint; 1179482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen cellToPoint(cellX, cellY, topLeft); 1180de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy 11814be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato int left = topLeft[0]; 11824be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato int top = topLeft[1]; 11836569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 1184b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung if (v != null && dragOffset == null) { 118599e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen // When drawing the drag outline, it did not account for margin offsets 118699e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen // added by the view's parent. 118799e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen MarginLayoutParams lp = (MarginLayoutParams) v.getLayoutParams(); 118899e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen left += lp.leftMargin; 118999e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen top += lp.topMargin; 119099e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen 119199e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen // Offsets due to the size difference between the View and the dragOutline. 119299e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen // There is a size difference to account for the outer blur, which may lie 119399e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen // outside the bounds of the view. 1194a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung top += (v.getHeight() - dragOutline.getHeight()) / 2; 1195ae915cecd36af4973061a1cb0b58c5be1be699a0Adam Cohen // We center about the x axis 1196ae915cecd36af4973061a1cb0b58c5be1be699a0Adam Cohen left += ((mCellWidth * spanX) + ((spanX - 1) * mWidthGap) 1197ae915cecd36af4973061a1cb0b58c5be1be699a0Adam Cohen - dragOutline.getWidth()) / 2; 11986639687cd67bab1aeef2a75e5c6bc458b20dc082Adam Cohen } else { 1199b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung if (dragOffset != null && dragRegion != null) { 1200b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung // Center the drag region *horizontally* in the cell and apply a drag 1201b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung // outline offset 1202b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung left += dragOffset.x + ((mCellWidth * spanX) + ((spanX - 1) * mWidthGap) 1203b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung - dragRegion.width()) / 2; 1204b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung top += dragOffset.y; 1205b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung } else { 1206b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung // Center the drag outline in the cell 1207b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung left += ((mCellWidth * spanX) + ((spanX - 1) * mWidthGap) 1208b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung - dragOutline.getWidth()) / 2; 1209b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung top += ((mCellHeight * spanY) + ((spanY - 1) * mHeightGap) 1210b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung - dragOutline.getHeight()) / 2; 1211b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung } 1212a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung } 12134be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato final int oldIndex = mDragOutlineCurrent; 121408ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy mDragOutlineAnims[oldIndex].animateOut(); 121508ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy mDragOutlineCurrent = (oldIndex + 1) % mDragOutlines.length; 1216d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen Rect r = mDragOutlines[mDragOutlineCurrent]; 1217d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen r.set(left, top, left + dragOutline.getWidth(), top + dragOutline.getHeight()); 1218d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (resize) { 1219482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen cellToRect(cellX, cellY, spanX, spanY, r); 1220d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1221150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung 122208ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy mDragOutlineAnims[mDragOutlineCurrent].setTag(dragOutline); 122308ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy mDragOutlineAnims[mDragOutlineCurrent].animateIn(); 12246569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy } 12256569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy } 12266569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 1227e0310965022e7a1adb7ad489505d404186608689Adam Cohen public void clearDragOutlines() { 1228e0310965022e7a1adb7ad489505d404186608689Adam Cohen final int oldIndex = mDragOutlineCurrent; 1229e0310965022e7a1adb7ad489505d404186608689Adam Cohen mDragOutlineAnims[oldIndex].animateOut(); 1230d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen mDragCell[0] = mDragCell[1] = -1; 1231e0310965022e7a1adb7ad489505d404186608689Adam Cohen } 1232e0310965022e7a1adb7ad489505d404186608689Adam Cohen 123331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 123470864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * Find a vacant area that will fit the given bounds nearest the requested 123570864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * cell location. Uses Euclidean distance to score multiple vacant areas. 1236aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * 123751afc022fa76c79f0d1ece470ddc126c08fea8a4Romain Guy * @param pixelX The X location at which you want to search for a vacant area. 123851afc022fa76c79f0d1ece470ddc126c08fea8a4Romain Guy * @param pixelY The Y location at which you want to search for a vacant area. 123970864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * @param spanX Horizontal span of the object. 124070864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * @param spanY Vertical span of the object. 1241de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy * @param result Array in which to place the result, or null (in which case a new array will 1242de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy * be allocated) 124370864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * @return The X, Y cell of a vacant area that can contain this object, 124470864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * nearest the requested location. 124531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 1246d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int[] findNearestVacantArea(int pixelX, int pixelY, int spanX, int spanY, 1247d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int[] result) { 1248de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy return findNearestVacantArea(pixelX, pixelY, spanX, spanY, null, result); 12496a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka } 1250aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 12516a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka /** 12526a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * Find a vacant area that will fit the given bounds nearest the requested 12536a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * cell location. Uses Euclidean distance to score multiple vacant areas. 12546a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * 12556a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * @param pixelX The X location at which you want to search for a vacant area. 12566a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * @param pixelY The Y location at which you want to search for a vacant area. 1257d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param minSpanX The minimum horizontal span required 1258d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param minSpanY The minimum vertical span required 1259d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param spanX Horizontal span of the object. 1260d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param spanY Vertical span of the object. 1261d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param result Array in which to place the result, or null (in which case a new array will 1262d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * be allocated) 1263d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @return The X, Y cell of a vacant area that can contain this object, 1264d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * nearest the requested location. 1265d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen */ 1266d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int[] findNearestVacantArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, 1267d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int spanY, int[] result, int[] resultSpan) { 1268d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen return findNearestVacantArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, null, 1269d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen result, resultSpan); 1270d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1271d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen 1272d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen /** 1273d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * Find a vacant area that will fit the given bounds nearest the requested 1274d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * cell location. Uses Euclidean distance to score multiple vacant areas. 1275d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * 1276d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param pixelX The X location at which you want to search for a vacant area. 1277d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param pixelY The Y location at which you want to search for a vacant area. 12786a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * @param spanX Horizontal span of the object. 12796a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * @param spanY Vertical span of the object. 1280df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param ignoreOccupied If true, the result can be an occupied cell 1281df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param result Array in which to place the result, or null (in which case a new array will 1282df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * be allocated) 12836a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * @return The X, Y cell of a vacant area that can contain this object, 12846a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * nearest the requested location. 12856a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka */ 1286df0353815c629fc678824b07a234b89a1ff94208Adam Cohen int[] findNearestArea(int pixelX, int pixelY, int spanX, int spanY, View ignoreView, 1287df0353815c629fc678824b07a234b89a1ff94208Adam Cohen boolean ignoreOccupied, int[] result) { 1288d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen return findNearestArea(pixelX, pixelY, spanX, spanY, 1289482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen spanX, spanY, ignoreView, ignoreOccupied, result, null, mOccupied); 1290d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1291d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen 1292d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen private final Stack<Rect> mTempRectStack = new Stack<Rect>(); 1293d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen private void lazyInitTempRectStack() { 1294d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (mTempRectStack.isEmpty()) { 1295d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen for (int i = 0; i < mCountX * mCountY; i++) { 1296d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen mTempRectStack.push(new Rect()); 1297d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1298d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1299d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1300482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1301d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen private void recycleTempRects(Stack<Rect> used) { 1302d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen while (!used.isEmpty()) { 1303d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen mTempRectStack.push(used.pop()); 1304d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1305d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1306d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen 1307d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen /** 1308d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * Find a vacant area that will fit the given bounds nearest the requested 1309d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * cell location. Uses Euclidean distance to score multiple vacant areas. 1310d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * 1311d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param pixelX The X location at which you want to search for a vacant area. 1312d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param pixelY The Y location at which you want to search for a vacant area. 1313d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param minSpanX The minimum horizontal span required 1314d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param minSpanY The minimum vertical span required 1315d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param spanX Horizontal span of the object. 1316d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param spanY Vertical span of the object. 1317d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param ignoreOccupied If true, the result can be an occupied cell 1318d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param result Array in which to place the result, or null (in which case a new array will 1319d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * be allocated) 1320d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @return The X, Y cell of a vacant area that can contain this object, 1321d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * nearest the requested location. 1322d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen */ 1323d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int[] findNearestArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, int spanY, 1324482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen View ignoreView, boolean ignoreOccupied, int[] result, int[] resultSpan, 1325482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean[][] occupied) { 1326d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen lazyInitTempRectStack(); 1327c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka // mark space take by ignoreView as available (method checks if ignoreView is null) 1328482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsAsUnoccupiedForView(ignoreView, occupied); 1329c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka 1330e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen // For items with a spanX / spanY > 1, the passed in point (pixelX, pixelY) corresponds 1331e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen // to the center of the item, but we are searching based on the top-left cell, so 1332e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen // we translate the point over to correspond to the top-left. 1333e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen pixelX -= (mCellWidth + mWidthGap) * (spanX - 1) / 2f; 1334e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen pixelY -= (mCellHeight + mHeightGap) * (spanY - 1) / 2f; 1335e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen 133670864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey // Keep track of best-scoring drop area 1337de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy final int[] bestXY = result != null ? result : new int[2]; 133870864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey double bestDistance = Double.MAX_VALUE; 1339d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen final Rect bestRect = new Rect(-1, -1, -1, -1); 1340d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen final Stack<Rect> validRegions = new Stack<Rect>(); 1341aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 1342de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy final int countX = mCountX; 1343de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy final int countY = mCountY; 1344de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy 1345d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (minSpanX <= 0 || minSpanY <= 0 || spanX <= 0 || spanY <= 0 || 1346d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen spanX < minSpanX || spanY < minSpanY) { 1347d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen return bestXY; 1348d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1349d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen 1350d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen for (int y = 0; y < countY - (minSpanY - 1); y++) { 1351c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka inner: 1352d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen for (int x = 0; x < countX - (minSpanX - 1); x++) { 1353d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int ySize = -1; 1354d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int xSize = -1; 1355df0353815c629fc678824b07a234b89a1ff94208Adam Cohen if (ignoreOccupied) { 1356d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // First, let's see if this thing fits anywhere 1357d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen for (int i = 0; i < minSpanX; i++) { 1358d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen for (int j = 0; j < minSpanY; j++) { 1359df0353815c629fc678824b07a234b89a1ff94208Adam Cohen if (occupied[x + i][y + j]) { 1360df0353815c629fc678824b07a234b89a1ff94208Adam Cohen continue inner; 1361df0353815c629fc678824b07a234b89a1ff94208Adam Cohen } 1362c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka } 1363c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka } 1364d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen xSize = minSpanX; 1365d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen ySize = minSpanY; 1366d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen 1367d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // We know that the item will fit at _some_ acceptable size, now let's see 1368d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // how big we can make it. We'll alternate between incrementing x and y spans 1369d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // until we hit a limit. 1370d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen boolean incX = true; 1371d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen boolean hitMaxX = xSize >= spanX; 1372d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen boolean hitMaxY = ySize >= spanY; 1373d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen while (!(hitMaxX && hitMaxY)) { 1374d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (incX && !hitMaxX) { 1375d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen for (int j = 0; j < ySize; j++) { 1376d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (x + xSize > countX -1 || occupied[x + xSize][y + j]) { 1377d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // We can't move out horizontally 1378d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen hitMaxX = true; 1379d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1380d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1381d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (!hitMaxX) { 1382d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen xSize++; 1383d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1384d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } else if (!hitMaxY) { 1385d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen for (int i = 0; i < xSize; i++) { 1386d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (y + ySize > countY - 1 || occupied[x + i][y + ySize]) { 1387d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // We can't move out vertically 1388d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen hitMaxY = true; 1389d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1390d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1391d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (!hitMaxY) { 1392d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen ySize++; 1393d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1394d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1395d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen hitMaxX |= xSize >= spanX; 1396d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen hitMaxY |= ySize >= spanY; 1397d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen incX = !incX; 1398d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1399d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen incX = true; 1400d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen hitMaxX = xSize >= spanX; 1401d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen hitMaxY = ySize >= spanY; 1402c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka } 14030be025d64c1f84138fe430a58875886e66aae767Winson Chung final int[] cellXY = mTmpXY; 1404e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen cellToCenterPoint(x, y, cellXY); 1405c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka 1406d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // We verify that the current rect is not a sub-rect of any of our previous 1407d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // candidates. In this case, the current rect is disqualified in favour of the 1408d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // containing rect. 1409d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen Rect currentRect = mTempRectStack.pop(); 1410d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen currentRect.set(x, y, x + xSize, y + ySize); 1411d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen boolean contained = false; 1412d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen for (Rect r : validRegions) { 1413d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (r.contains(currentRect)) { 1414d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen contained = true; 1415d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen break; 1416d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1417d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1418d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen validRegions.push(currentRect); 1419c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka double distance = Math.sqrt(Math.pow(cellXY[0] - pixelX, 2) 1420c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka + Math.pow(cellXY[1] - pixelY, 2)); 1421482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1422d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if ((distance <= bestDistance && !contained) || 1423d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen currentRect.contains(bestRect)) { 1424c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka bestDistance = distance; 1425c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka bestXY[0] = x; 1426c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka bestXY[1] = y; 1427d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (resultSpan != null) { 1428d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen resultSpan[0] = xSize; 1429d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen resultSpan[1] = ySize; 1430d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1431d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen bestRect.set(currentRect); 1432c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka } 143331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 143431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 1435c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka // re-mark space taken by ignoreView as occupied 1436482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsAsOccupiedForView(ignoreView, occupied); 143731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 1438c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen // Return -1, -1 if no suitable location found 1439c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen if (bestDistance == Double.MAX_VALUE) { 1440c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen bestXY[0] = -1; 1441c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen bestXY[1] = -1; 144270864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey } 1443d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen recycleTempRects(validRegions); 1444c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen return bestXY; 144531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 1446aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 1447482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen /** 1448482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * Find a vacant area that will fit the given bounds nearest the requested 1449482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * cell location, and will also weigh in a suggested direction vector of the 1450482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * desired location. This method computers distance based on unit grid distances, 1451482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * not pixel distances. 1452482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * 145347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param cellX The X cell nearest to which you want to search for a vacant area. 145447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param cellY The Y cell nearest which you want to search for a vacant area. 1455482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * @param spanX Horizontal span of the object. 1456482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * @param spanY Vertical span of the object. 145747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param direction The favored direction in which the views should move from x, y 145847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param exactDirectionOnly If this parameter is true, then only solutions where the direction 145947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * matches exactly. Otherwise we find the best matching direction. 146047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param occoupied The array which represents which cells in the CellLayout are occupied 146147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param blockOccupied The array which represents which cells in the specified block (cellX, 146247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * cellY, spanX, spanY) are occupied. This is used when try to move a group of views. 1463482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * @param result Array in which to place the result, or null (in which case a new array will 1464482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * be allocated) 1465482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * @return The X, Y cell of a vacant area that can contain this object, 1466482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * nearest the requested location. 1467482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen */ 1468482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private int[] findNearestArea(int cellX, int cellY, int spanX, int spanY, int[] direction, 146947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean[][] occupied, boolean blockOccupied[][], int[] result) { 1470482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // Keep track of best-scoring drop area 1471482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int[] bestXY = result != null ? result : new int[2]; 1472482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen float bestDistance = Float.MAX_VALUE; 1473482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int bestDirectionScore = Integer.MIN_VALUE; 1474482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1475482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int countX = mCountX; 1476482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int countY = mCountY; 1477482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1478482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int y = 0; y < countY - (spanY - 1); y++) { 1479482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen inner: 1480482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int x = 0; x < countX - (spanX - 1); x++) { 1481482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // First, let's see if this thing fits anywhere 1482482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < spanX; i++) { 1483482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int j = 0; j < spanY; j++) { 148447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (occupied[x + i][y + j] && (blockOccupied == null || blockOccupied[i][j])) { 1485482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen continue inner; 1486482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1487482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1488482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1489482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1490482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen float distance = (float) 1491482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen Math.sqrt((x - cellX) * (x - cellX) + (y - cellY) * (y - cellY)); 1492482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int[] curDirection = mTmpPoint; 149347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen computeDirectionVector(x - cellX, y - cellY, curDirection); 149447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen // The direction score is just the dot product of the two candidate direction 149547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen // and that passed in. 1496482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int curDirectionScore = direction[0] * curDirection[0] + 1497482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen direction[1] * curDirection[1]; 149847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean exactDirectionOnly = false; 149947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean directionMatches = direction[0] == curDirection[0] && 150047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen direction[0] == curDirection[0]; 150147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if ((directionMatches || !exactDirectionOnly) && 150247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen Float.compare(distance, bestDistance) < 0 || (Float.compare(distance, 1503482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen bestDistance) == 0 && curDirectionScore > bestDirectionScore)) { 1504482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen bestDistance = distance; 1505482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen bestDirectionScore = curDirectionScore; 1506482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen bestXY[0] = x; 1507482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen bestXY[1] = y; 1508482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1509482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1510482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1511482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1512482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // Return -1, -1 if no suitable location found 1513482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (bestDistance == Float.MAX_VALUE) { 1514482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen bestXY[0] = -1; 1515482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen bestXY[1] = -1; 1516482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1517482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return bestXY; 1518482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1519482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 152047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen private int[] findNearestAreaInDirection(int cellX, int cellY, int spanX, int spanY, 152147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen int[] direction,boolean[][] occupied, 152247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean blockOccupied[][], int[] result) { 152347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen // Keep track of best-scoring drop area 152447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen final int[] bestXY = result != null ? result : new int[2]; 152547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen bestXY[0] = -1; 152647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen bestXY[1] = -1; 152747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen float bestDistance = Float.MAX_VALUE; 152847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 152947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen // We use this to march in a single direction 15305b53f29f809a0dad4a1e0717ba610ce737ee0f43Adam Cohen if ((direction[0] != 0 && direction[1] != 0) || 15315b53f29f809a0dad4a1e0717ba610ce737ee0f43Adam Cohen (direction[0] == 0 && direction[1] == 0)) { 153247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen return bestXY; 153347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 153447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 153547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen // This will only incrememnet one of x or y based on the assertion above 153647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen int x = cellX + direction[0]; 153747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen int y = cellY + direction[1]; 153847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen while (x >= 0 && x + spanX <= mCountX && y >= 0 && y + spanY <= mCountY) { 153947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 154047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean fail = false; 154147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen for (int i = 0; i < spanX; i++) { 154247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen for (int j = 0; j < spanY; j++) { 154347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (occupied[x + i][y + j] && (blockOccupied == null || blockOccupied[i][j])) { 154447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen fail = true; 154547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 154647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 154747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 154847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (!fail) { 154947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen float distance = (float) 155047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen Math.sqrt((x - cellX) * (x - cellX) + (y - cellY) * (y - cellY)); 155147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (Float.compare(distance, bestDistance) < 0) { 155247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen bestDistance = distance; 155347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen bestXY[0] = x; 155447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen bestXY[1] = y; 155547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 155647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 155747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen x += direction[0]; 155847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen y += direction[1]; 155947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 156047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen return bestXY; 156147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 156247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 1563482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private boolean addViewToTempLocation(View v, Rect rectOccupiedByPotentialDrop, 15648baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen int[] direction, ItemConfiguration currentState) { 15658baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = currentState.map.get(v); 1566482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean success = false; 15678baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, false); 1568482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsForRect(rectOccupiedByPotentialDrop, mTmpOccupied, true); 1569482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 15708baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen findNearestArea(c.x, c.y, c.spanX, c.spanY, direction, mTmpOccupied, null, mTempLocation); 1571482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1572482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (mTempLocation[0] >= 0 && mTempLocation[1] >= 0) { 15738baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen c.x = mTempLocation[0]; 15748baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen c.y = mTempLocation[1]; 1575482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen success = true; 1576482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1577482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 15788baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, true); 1579482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return success; 1580482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1581482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 158247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen // This method looks in the specified direction to see if there is an additional view 158347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen // immediately adjecent in that direction 158447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen private boolean addViewInDirection(ArrayList<View> views, Rect boundingRect, int[] direction, 158519f3792523fe2d55ea791a9286398a6120920690Adam Cohen boolean[][] occupied, View dragView, ItemConfiguration currentState) { 158647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean found = false; 158747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 1588a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka int childCount = mShortcutsAndWidgets.getChildCount(); 158947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen Rect r0 = new Rect(boundingRect); 159047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen Rect r1 = new Rect(); 159147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 159247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen int deltaX = 0; 159347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen int deltaY = 0; 159447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (direction[1] < 0) { 159547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen r0.set(r0.left, r0.top - 1, r0.right, r0.bottom); 159647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen deltaY = -1; 159747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } else if (direction[1] > 0) { 159847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen r0.set(r0.left, r0.top, r0.right, r0.bottom + 1); 159947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen deltaY = 1; 160047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } else if (direction[0] < 0) { 160147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen r0.set(r0.left - 1, r0.top, r0.right, r0.bottom); 160247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen deltaX = -1; 160347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } else if (direction[0] > 0) { 160447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen r0.set(r0.left, r0.top, r0.right + 1, r0.bottom); 160547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen deltaX = 1; 160647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 160747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 160847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen for (int i = 0; i < childCount; i++) { 1609a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka View child = mShortcutsAndWidgets.getChildAt(i); 161019f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (views.contains(child) || child == dragView) continue; 16118baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = currentState.map.get(child); 161247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 16138baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen LayoutParams lp = (LayoutParams) child.getLayoutParams(); 16148baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen r1.set(c.x, c.y, c.x + c.spanX, c.y + c.spanY); 161547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (Rect.intersects(r0, r1)) { 161647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (!lp.canReorder) { 161747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen return false; 161847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 161947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean pushed = false; 16208baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen for (int x = c.x; x < c.x + c.spanX; x++) { 16218baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen for (int y = c.y; y < c.y + c.spanY; y++) { 162247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean inBounds = x - deltaX >= 0 && x -deltaX < mCountX 162347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen && y - deltaY >= 0 && y - deltaY < mCountY; 162447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (inBounds && occupied[x - deltaX][y - deltaY]) { 162547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen pushed = true; 162647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 162747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 162847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 162947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (pushed) { 163047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen views.add(child); 16318baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen boundingRect.union(c.x, c.y, c.x + c.spanX, c.y + c.spanY); 163247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen found = true; 163347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 163447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 163547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 163647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen return found; 163747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 163847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 16398baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen private boolean addViewsToTempLocation(ArrayList<View> views, Rect rectOccupiedByPotentialDrop, 164019f3792523fe2d55ea791a9286398a6120920690Adam Cohen int[] direction, boolean push, View dragView, ItemConfiguration currentState) { 164147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (views.size() == 0) return true; 164247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 164347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean success = false; 164447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen Rect boundingRect = null; 16458baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // We construct a rect which represents the entire group of views passed in 164647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen for (View v: views) { 16478baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = currentState.map.get(v); 164847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (boundingRect == null) { 16498baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen boundingRect = new Rect(c.x, c.y, c.x + c.spanX, c.y + c.spanY); 165047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } else { 16518baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen boundingRect.union(c.x, c.y, c.x + c.spanX, c.y + c.spanY); 165247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 165347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 165447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 16558baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen @SuppressWarnings("unchecked") 165647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen ArrayList<View> dup = (ArrayList<View>) views.clone(); 16578baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // We try and expand the group of views in the direction vector passed, based on 16588baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // whether they are physically adjacent, ie. based on "push mechanics". 165919f3792523fe2d55ea791a9286398a6120920690Adam Cohen while (push && addViewInDirection(dup, boundingRect, direction, mTmpOccupied, dragView, 16608baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen currentState)) { 166147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 16628baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen 16638baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // Mark the occupied state as false for the group of views we want to move. 166447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen for (View v: dup) { 16658baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = currentState.map.get(v); 16668baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, false); 166747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 166847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 166947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean[][] blockOccupied = new boolean[boundingRect.width()][boundingRect.height()]; 167047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen int top = boundingRect.top; 167147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen int left = boundingRect.left; 16728baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // We mark more precisely which parts of the bounding rect are truly occupied, allowing 16738baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // for tetris-style interlocking. 167447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen for (View v: dup) { 16758baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = currentState.map.get(v); 16768baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen markCellsForView(c.x - left, c.y - top, c.spanX, c.spanY, blockOccupied, true); 167747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 167847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 167947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen markCellsForRect(rectOccupiedByPotentialDrop, mTmpOccupied, true); 168047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 16818baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen if (push) { 16828baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen findNearestAreaInDirection(boundingRect.left, boundingRect.top, boundingRect.width(), 16838baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen boundingRect.height(), direction, mTmpOccupied, blockOccupied, mTempLocation); 16848baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen } else { 16858baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen findNearestArea(boundingRect.left, boundingRect.top, boundingRect.width(), 16868baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen boundingRect.height(), direction, mTmpOccupied, blockOccupied, mTempLocation); 16878baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen } 168847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 16898baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // If we successfuly found a location by pushing the block of views, we commit it 169047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (mTempLocation[0] >= 0 && mTempLocation[1] >= 0) { 16918baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen int deltaX = mTempLocation[0] - boundingRect.left; 16928baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen int deltaY = mTempLocation[1] - boundingRect.top; 169347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen for (View v: dup) { 16948baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = currentState.map.get(v); 16958baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen c.x += deltaX; 16968baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen c.y += deltaY; 169747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 169847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen success = true; 169947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 1700482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 17018baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // In either case, we set the occupied array as marked for the location of the views 17028baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen for (View v: dup) { 17038baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = currentState.map.get(v); 17048baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, true); 1705482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1706482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return success; 1707482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1708482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1709482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private void markCellsForRect(Rect r, boolean[][] occupied, boolean value) { 1710482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsForView(r.left, r.top, r.width(), r.height(), occupied, value); 1711482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1712482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 17134abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // This method tries to find a reordering solution which satisfies the push mechanic by trying 17144abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // to push items in each of the cardinal directions, in an order based on the direction vector 17154abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // passed. 17164abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen private boolean attemptPushInDirection(ArrayList<View> intersectingViews, Rect occupied, 17174abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen int[] direction, View ignoreView, ItemConfiguration solution) { 17184abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen if ((Math.abs(direction[0]) + Math.abs(direction[1])) > 1) { 17194abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // If the direction vector has two non-zero components, we try pushing 17204abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // separately in each of the components. 17214abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen int temp = direction[1]; 17224abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[1] = 0; 17234abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen if (addViewsToTempLocation(intersectingViews, occupied, direction, true, 17244abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen ignoreView, solution)) { 17254abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen return true; 17264abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen } 17274abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[1] = temp; 17284abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen temp = direction[0]; 17294abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[0] = 0; 17304abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen if (addViewsToTempLocation(intersectingViews, occupied, direction, true, 17314abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen ignoreView, solution)) { 17324abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen return true; 17334abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen } 17344abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // Revert the direction 17354abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[0] = temp; 17364abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen 17374abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // Now we try pushing in each component of the opposite direction 17384abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[0] *= -1; 17394abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[1] *= -1; 17404abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen temp = direction[1]; 17414abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[1] = 0; 17424abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen if (addViewsToTempLocation(intersectingViews, occupied, direction, true, 17434abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen ignoreView, solution)) { 17444abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen return true; 17454abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen } 17464abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen 17474abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[1] = temp; 17484abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen temp = direction[0]; 17494abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[0] = 0; 17504abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen if (addViewsToTempLocation(intersectingViews, occupied, direction, true, 17514abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen ignoreView, solution)) { 17524abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen return true; 17534abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen } 17544abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // revert the direction 17554abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[0] = temp; 17564abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[0] *= -1; 17574abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[1] *= -1; 17584abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen 17594abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen } else { 17604abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // If the direction vector has a single non-zero component, we push first in the 17614abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // direction of the vector 17624abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen if (addViewsToTempLocation(intersectingViews, occupied, direction, true, 17634abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen ignoreView, solution)) { 17644abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen return true; 17654abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen } 17664abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen 17674abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // Then we try the opposite direction 17684abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[0] *= -1; 17694abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[1] *= -1; 17704abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen if (addViewsToTempLocation(intersectingViews, occupied, direction, true, 17714abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen ignoreView, solution)) { 17724abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen return true; 17734abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen } 17744abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // Switch the direction back 17754abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[0] *= -1; 17764abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[1] *= -1; 17774abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen 17784abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // If we have failed to find a push solution with the above, then we try 17794abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // to find a solution by pushing along the perpendicular axis. 17804abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen 17814abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // Swap the components 17824abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen int temp = direction[1]; 17834abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[1] = direction[0]; 17844abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[0] = temp; 17854abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen if (addViewsToTempLocation(intersectingViews, occupied, direction, true, 17864abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen ignoreView, solution)) { 17874abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen return true; 17884abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen } 17894abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen 17904abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // Then we try the opposite direction 17914abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[0] *= -1; 17924abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[1] *= -1; 17934abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen if (addViewsToTempLocation(intersectingViews, occupied, direction, true, 17944abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen ignoreView, solution)) { 17954abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen return true; 17964abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen } 17974abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // Switch the direction back 17984abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[0] *= -1; 17994abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[1] *= -1; 18004abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen 18014abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // Swap the components back 18024abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen temp = direction[1]; 18034abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[1] = direction[0]; 18044abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[0] = temp; 18054abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen } 18064abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen return false; 18074abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen } 18084abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen 1809482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private boolean rearrangementExists(int cellX, int cellY, int spanX, int spanY, int[] direction, 18108baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen View ignoreView, ItemConfiguration solution) { 1811e3e03bcd313ba8060f2832b6a16dea6fd6d532eaWinson Chung // Return early if get invalid cell positions 1812e3e03bcd313ba8060f2832b6a16dea6fd6d532eaWinson Chung if (cellX < 0 || cellY < 0) return false; 1813482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 18148baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen mIntersectingViews.clear(); 1815482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mOccupiedRect.set(cellX, cellY, cellX + spanX, cellY + spanY); 1816482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 18178baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // Mark the desired location of the view currently being dragged. 1818482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (ignoreView != null) { 18198baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = solution.map.get(ignoreView); 182019f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (c != null) { 182119f3792523fe2d55ea791a9286398a6120920690Adam Cohen c.x = cellX; 182219f3792523fe2d55ea791a9286398a6120920690Adam Cohen c.y = cellY; 182319f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 1824482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1825482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen Rect r0 = new Rect(cellX, cellY, cellX + spanX, cellY + spanY); 1826482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen Rect r1 = new Rect(); 18278baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen for (View child: solution.map.keySet()) { 1828482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (child == ignoreView) continue; 18298baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = solution.map.get(child); 1830482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen LayoutParams lp = (LayoutParams) child.getLayoutParams(); 18318baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen r1.set(c.x, c.y, c.x + c.spanX, c.y + c.spanY); 1832482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (Rect.intersects(r0, r1)) { 1833482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (!lp.canReorder) { 1834482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return false; 1835482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1836482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mIntersectingViews.add(child); 1837482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1838482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 183947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 18404abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // First we try to find a solution which respects the push mechanic. That is, 18414abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // we try to find a solution such that no displaced item travels through another item 18424abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // without also displacing that item. 18434abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen if (attemptPushInDirection(mIntersectingViews, mOccupiedRect, direction, ignoreView, 184419f3792523fe2d55ea791a9286398a6120920690Adam Cohen solution)) { 184547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen return true; 184647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 184747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 18484abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // Next we try moving the views as a block, but without requiring the push mechanic. 184919f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (addViewsToTempLocation(mIntersectingViews, mOccupiedRect, direction, false, ignoreView, 185019f3792523fe2d55ea791a9286398a6120920690Adam Cohen solution)) { 1851482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return true; 1852482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 185347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 1854482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // Ok, they couldn't move as a block, let's move them individually 1855482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (View v : mIntersectingViews) { 18568baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen if (!addViewToTempLocation(v, mOccupiedRect, direction, solution)) { 1857482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return false; 1858482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1859482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1860482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return true; 1861482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1862482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1863482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen /* 1864482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * Returns a pair (x, y), where x,y are in {-1, 0, 1} corresponding to vector between 1865482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * the provided point and the provided cell 1866482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen */ 186747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen private void computeDirectionVector(float deltaX, float deltaY, int[] result) { 1868482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen double angle = Math.atan(((float) deltaY) / deltaX); 1869482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1870482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result[0] = 0; 1871482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result[1] = 0; 1872482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (Math.abs(Math.cos(angle)) > 0.5f) { 1873482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result[0] = (int) Math.signum(deltaX); 1874482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1875482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (Math.abs(Math.sin(angle)) > 0.5f) { 1876482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result[1] = (int) Math.signum(deltaY); 1877482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1878482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1879482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 18808baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen private void copyOccupiedArray(boolean[][] occupied) { 18818baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen for (int i = 0; i < mCountX; i++) { 18828baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen for (int j = 0; j < mCountY; j++) { 18838baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen occupied[i][j] = mOccupied[i][j]; 18848baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen } 18858baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen } 18868baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen } 18878baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen 1888482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen ItemConfiguration simpleSwap(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, 1889482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int spanY, int[] direction, View dragView, boolean decX, ItemConfiguration solution) { 18908baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // Copy the current state into the solution. This solution will be manipulated as necessary. 18918baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen copyCurrentStateToSolution(solution, false); 18928baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // Copy the current occupied array into the temporary occupied array. This array will be 18938baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // manipulated as necessary to find a solution. 18948baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen copyOccupiedArray(mTmpOccupied); 1895482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1896482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // We find the nearest cell into which we would place the dragged item, assuming there's 1897482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // nothing in its way. 1898482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int result[] = new int[2]; 1899482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result = findNearestArea(pixelX, pixelY, spanX, spanY, result); 1900482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1901482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean success = false; 1902482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // First we try the exact nearest position of the item being dragged, 1903482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // we will then want to try to move this around to other neighbouring positions 19048baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen success = rearrangementExists(result[0], result[1], spanX, spanY, direction, dragView, 19058baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen solution); 1906482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1907482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (!success) { 1908482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // We try shrinking the widget down to size in an alternating pattern, shrink 1 in 1909482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // x, then 1 in y etc. 1910482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (spanX > minSpanX && (minSpanY == spanY || decX)) { 1911482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return simpleSwap(pixelX, pixelY, minSpanX, minSpanY, spanX - 1, spanY, direction, 1912482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen dragView, false, solution); 1913482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } else if (spanY > minSpanY) { 1914482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return simpleSwap(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY - 1, direction, 1915482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen dragView, true, solution); 1916482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1917482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.isSolution = false; 1918482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } else { 1919482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.isSolution = true; 1920482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewX = result[0]; 1921482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewY = result[1]; 1922482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewSpanX = spanX; 1923482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewSpanY = spanY; 1924482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1925482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return solution; 1926482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1927482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1928482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private void copyCurrentStateToSolution(ItemConfiguration solution, boolean temp) { 1929a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka int childCount = mShortcutsAndWidgets.getChildCount(); 1930482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < childCount; i++) { 1931a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka View child = mShortcutsAndWidgets.getChildAt(i); 1932482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen LayoutParams lp = (LayoutParams) child.getLayoutParams(); 19338baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c; 1934482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (temp) { 19358baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen c = new CellAndSpan(lp.tmpCellX, lp.tmpCellY, lp.cellHSpan, lp.cellVSpan); 1936482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } else { 19378baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen c = new CellAndSpan(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan); 1938482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 19398baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen solution.map.put(child, c); 1940482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1941482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1942482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1943482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private void copySolutionToTempState(ItemConfiguration solution, View dragView) { 1944482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < mCountX; i++) { 1945482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int j = 0; j < mCountY; j++) { 1946482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mTmpOccupied[i][j] = false; 1947482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1948482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1949482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1950a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka int childCount = mShortcutsAndWidgets.getChildCount(); 1951482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < childCount; i++) { 1952a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka View child = mShortcutsAndWidgets.getChildAt(i); 1953482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (child == dragView) continue; 1954482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen LayoutParams lp = (LayoutParams) child.getLayoutParams(); 19558baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = solution.map.get(child); 19568baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen if (c != null) { 19578baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen lp.tmpCellX = c.x; 19588baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen lp.tmpCellY = c.y; 19598baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen lp.cellHSpan = c.spanX; 19608baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen lp.cellVSpan = c.spanY; 19618baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, true); 1962482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1963482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1964482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsForView(solution.dragViewX, solution.dragViewY, solution.dragViewSpanX, 1965482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewSpanY, mTmpOccupied, true); 1966482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1967482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1968482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private void animateItemsToSolution(ItemConfiguration solution, View dragView, boolean 1969482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen commitDragView) { 1970482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1971482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean[][] occupied = DESTRUCTIVE_REORDER ? mOccupied : mTmpOccupied; 1972482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < mCountX; i++) { 1973482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int j = 0; j < mCountY; j++) { 1974482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen occupied[i][j] = false; 1975482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1976482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1977482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1978a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka int childCount = mShortcutsAndWidgets.getChildCount(); 1979482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < childCount; i++) { 1980a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka View child = mShortcutsAndWidgets.getChildAt(i); 1981482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (child == dragView) continue; 19828baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = solution.map.get(child); 19838baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen if (c != null) { 198419f3792523fe2d55ea791a9286398a6120920690Adam Cohen animateChildToPosition(child, c.x, c.y, REORDER_ANIMATION_DURATION, 0, 198519f3792523fe2d55ea791a9286398a6120920690Adam Cohen DESTRUCTIVE_REORDER, false); 19868baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen markCellsForView(c.x, c.y, c.spanX, c.spanY, occupied, true); 1987482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1988482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1989482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (commitDragView) { 1990482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsForView(solution.dragViewX, solution.dragViewY, solution.dragViewSpanX, 1991482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewSpanY, occupied, true); 1992482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1993482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1994482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 199519f3792523fe2d55ea791a9286398a6120920690Adam Cohen // This method starts or changes the reorder hint animations 199619f3792523fe2d55ea791a9286398a6120920690Adam Cohen private void beginOrAdjustHintAnimations(ItemConfiguration solution, View dragView, int delay) { 199719f3792523fe2d55ea791a9286398a6120920690Adam Cohen int childCount = mShortcutsAndWidgets.getChildCount(); 199819f3792523fe2d55ea791a9286398a6120920690Adam Cohen for (int i = 0; i < childCount; i++) { 199919f3792523fe2d55ea791a9286398a6120920690Adam Cohen View child = mShortcutsAndWidgets.getChildAt(i); 200019f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (child == dragView) continue; 200119f3792523fe2d55ea791a9286398a6120920690Adam Cohen CellAndSpan c = solution.map.get(child); 200219f3792523fe2d55ea791a9286398a6120920690Adam Cohen LayoutParams lp = (LayoutParams) child.getLayoutParams(); 200319f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (c != null) { 200419f3792523fe2d55ea791a9286398a6120920690Adam Cohen ReorderHintAnimation rha = new ReorderHintAnimation(child, lp.cellX, lp.cellY, 200519f3792523fe2d55ea791a9286398a6120920690Adam Cohen c.x, c.y, c.spanX, c.spanY); 2006d024f9845a0974ab525baad085f316031cd5a742Adam Cohen rha.animate(); 200719f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 200819f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 200919f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 201019f3792523fe2d55ea791a9286398a6120920690Adam Cohen 201119f3792523fe2d55ea791a9286398a6120920690Adam Cohen // Class which represents the reorder hint animations. These animations show that an item is 201219f3792523fe2d55ea791a9286398a6120920690Adam Cohen // in a temporary state, and hint at where the item will return to. 201319f3792523fe2d55ea791a9286398a6120920690Adam Cohen class ReorderHintAnimation { 201419f3792523fe2d55ea791a9286398a6120920690Adam Cohen View child; 2015d024f9845a0974ab525baad085f316031cd5a742Adam Cohen float finalDeltaX; 2016d024f9845a0974ab525baad085f316031cd5a742Adam Cohen float finalDeltaY; 2017d024f9845a0974ab525baad085f316031cd5a742Adam Cohen float initDeltaX; 2018d024f9845a0974ab525baad085f316031cd5a742Adam Cohen float initDeltaY; 2019d024f9845a0974ab525baad085f316031cd5a742Adam Cohen float finalScale; 2020d024f9845a0974ab525baad085f316031cd5a742Adam Cohen float initScale; 202150e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely private static final int DURATION = 300; 2022e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen Animator a; 202319f3792523fe2d55ea791a9286398a6120920690Adam Cohen 202419f3792523fe2d55ea791a9286398a6120920690Adam Cohen public ReorderHintAnimation(View child, int cellX0, int cellY0, int cellX1, int cellY1, 202519f3792523fe2d55ea791a9286398a6120920690Adam Cohen int spanX, int spanY) { 202619f3792523fe2d55ea791a9286398a6120920690Adam Cohen regionToCenterPoint(cellX0, cellY0, spanX, spanY, mTmpPoint); 202719f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int x0 = mTmpPoint[0]; 202819f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int y0 = mTmpPoint[1]; 202919f3792523fe2d55ea791a9286398a6120920690Adam Cohen regionToCenterPoint(cellX1, cellY1, spanX, spanY, mTmpPoint); 203019f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int x1 = mTmpPoint[0]; 203119f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int y1 = mTmpPoint[1]; 203219f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int dX = x1 - x0; 203319f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int dY = y1 - y0; 2034d024f9845a0974ab525baad085f316031cd5a742Adam Cohen finalDeltaX = 0; 2035d024f9845a0974ab525baad085f316031cd5a742Adam Cohen finalDeltaY = 0; 203619f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (dX == dY && dX == 0) { 203719f3792523fe2d55ea791a9286398a6120920690Adam Cohen } else { 203819f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (dY == 0) { 2039d024f9845a0974ab525baad085f316031cd5a742Adam Cohen finalDeltaX = - Math.signum(dX) * mReorderHintAnimationMagnitude; 204019f3792523fe2d55ea791a9286398a6120920690Adam Cohen } else if (dX == 0) { 2041d024f9845a0974ab525baad085f316031cd5a742Adam Cohen finalDeltaY = - Math.signum(dY) * mReorderHintAnimationMagnitude; 204219f3792523fe2d55ea791a9286398a6120920690Adam Cohen } else { 204319f3792523fe2d55ea791a9286398a6120920690Adam Cohen double angle = Math.atan( (float) (dY) / dX); 2044d024f9845a0974ab525baad085f316031cd5a742Adam Cohen finalDeltaX = (int) (- Math.signum(dX) * 2045fe41ac641bdef7ea96dcbac59b4f3abdbdff6cfeAdam Cohen Math.abs(Math.cos(angle) * mReorderHintAnimationMagnitude)); 2046d024f9845a0974ab525baad085f316031cd5a742Adam Cohen finalDeltaY = (int) (- Math.signum(dY) * 2047fe41ac641bdef7ea96dcbac59b4f3abdbdff6cfeAdam Cohen Math.abs(Math.sin(angle) * mReorderHintAnimationMagnitude)); 204819f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 204919f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 2050d024f9845a0974ab525baad085f316031cd5a742Adam Cohen initDeltaX = child.getTranslationX(); 2051d024f9845a0974ab525baad085f316031cd5a742Adam Cohen initDeltaY = child.getTranslationY(); 2052d024f9845a0974ab525baad085f316031cd5a742Adam Cohen finalScale = 1.0f - 4.0f / child.getWidth(); 2053d024f9845a0974ab525baad085f316031cd5a742Adam Cohen initScale = child.getScaleX(); 2054d024f9845a0974ab525baad085f316031cd5a742Adam Cohen 205550e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely child.setPivotY(child.getMeasuredHeight() * 0.5f); 205650e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely child.setPivotX(child.getMeasuredWidth() * 0.5f); 205719f3792523fe2d55ea791a9286398a6120920690Adam Cohen this.child = child; 205819f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 205919f3792523fe2d55ea791a9286398a6120920690Adam Cohen 2060d024f9845a0974ab525baad085f316031cd5a742Adam Cohen void animate() { 206119f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (mShakeAnimators.containsKey(child)) { 206219f3792523fe2d55ea791a9286398a6120920690Adam Cohen ReorderHintAnimation oldAnimation = mShakeAnimators.get(child); 2063d024f9845a0974ab525baad085f316031cd5a742Adam Cohen oldAnimation.cancel(); 206419f3792523fe2d55ea791a9286398a6120920690Adam Cohen mShakeAnimators.remove(child); 2065e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen if (finalDeltaX == 0 && finalDeltaY == 0) { 2066e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen completeAnimationImmediately(); 2067e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen return; 2068e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen } 206919f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 2070d024f9845a0974ab525baad085f316031cd5a742Adam Cohen if (finalDeltaX == 0 && finalDeltaY == 0) { 207119f3792523fe2d55ea791a9286398a6120920690Adam Cohen return; 207219f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 2073e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen ValueAnimator va = ValueAnimator.ofFloat(0f, 1f); 2074e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen a = va; 207519f3792523fe2d55ea791a9286398a6120920690Adam Cohen va.setRepeatMode(ValueAnimator.REVERSE); 207619f3792523fe2d55ea791a9286398a6120920690Adam Cohen va.setRepeatCount(ValueAnimator.INFINITE); 20777bdfc9700b1cad043c04c757f134db1bf3df00daAdam Cohen va.setDuration(DURATION); 2078d024f9845a0974ab525baad085f316031cd5a742Adam Cohen va.setStartDelay((int) (Math.random() * 60)); 207919f3792523fe2d55ea791a9286398a6120920690Adam Cohen va.addUpdateListener(new AnimatorUpdateListener() { 208019f3792523fe2d55ea791a9286398a6120920690Adam Cohen @Override 208119f3792523fe2d55ea791a9286398a6120920690Adam Cohen public void onAnimationUpdate(ValueAnimator animation) { 208219f3792523fe2d55ea791a9286398a6120920690Adam Cohen float r = ((Float) animation.getAnimatedValue()).floatValue(); 2083d024f9845a0974ab525baad085f316031cd5a742Adam Cohen float x = r * finalDeltaX + (1 - r) * initDeltaX; 2084d024f9845a0974ab525baad085f316031cd5a742Adam Cohen float y = r * finalDeltaY + (1 - r) * initDeltaY; 208519f3792523fe2d55ea791a9286398a6120920690Adam Cohen child.setTranslationX(x); 208619f3792523fe2d55ea791a9286398a6120920690Adam Cohen child.setTranslationY(y); 2087d024f9845a0974ab525baad085f316031cd5a742Adam Cohen float s = r * finalScale + (1 - r) * initScale; 208850e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely child.setScaleX(s); 208950e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely child.setScaleY(s); 209019f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 209119f3792523fe2d55ea791a9286398a6120920690Adam Cohen }); 209219f3792523fe2d55ea791a9286398a6120920690Adam Cohen va.addListener(new AnimatorListenerAdapter() { 209319f3792523fe2d55ea791a9286398a6120920690Adam Cohen public void onAnimationRepeat(Animator animation) { 209419f3792523fe2d55ea791a9286398a6120920690Adam Cohen // We make sure to end only after a full period 2095d024f9845a0974ab525baad085f316031cd5a742Adam Cohen initDeltaX = 0; 2096d024f9845a0974ab525baad085f316031cd5a742Adam Cohen initDeltaY = 0; 2097d024f9845a0974ab525baad085f316031cd5a742Adam Cohen initScale = 1.0f; 209819f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 209919f3792523fe2d55ea791a9286398a6120920690Adam Cohen }); 210019f3792523fe2d55ea791a9286398a6120920690Adam Cohen mShakeAnimators.put(child, this); 210119f3792523fe2d55ea791a9286398a6120920690Adam Cohen va.start(); 210219f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 210319f3792523fe2d55ea791a9286398a6120920690Adam Cohen 2104d024f9845a0974ab525baad085f316031cd5a742Adam Cohen private void cancel() { 2105e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen if (a != null) { 2106e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen a.cancel(); 2107e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen } 210819f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 2109e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen 211050e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely private void completeAnimationImmediately() { 2111e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen if (a != null) { 2112e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen a.cancel(); 2113e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen } 211450e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely 211550e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely AnimatorSet s = new AnimatorSet(); 2116e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen a = s; 211750e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely s.playTogether( 211850e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely ObjectAnimator.ofFloat(child, "scaleX", 1f), 211950e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely ObjectAnimator.ofFloat(child, "scaleY", 1f), 212050e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely ObjectAnimator.ofFloat(child, "translationX", 0f), 2121faf22e15f18479ee84ef15869694cd581df38dc5Brandon Keely ObjectAnimator.ofFloat(child, "translationY", 0f) 212250e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely ); 212350e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely s.setDuration(REORDER_ANIMATION_DURATION); 212450e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely s.setInterpolator(new android.view.animation.DecelerateInterpolator(1.5f)); 212550e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely s.start(); 212650e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely } 212719f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 212819f3792523fe2d55ea791a9286398a6120920690Adam Cohen 212919f3792523fe2d55ea791a9286398a6120920690Adam Cohen private void completeAndClearReorderHintAnimations() { 213019f3792523fe2d55ea791a9286398a6120920690Adam Cohen for (ReorderHintAnimation a: mShakeAnimators.values()) { 213150e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely a.completeAnimationImmediately(); 213219f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 213319f3792523fe2d55ea791a9286398a6120920690Adam Cohen mShakeAnimators.clear(); 213419f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 213519f3792523fe2d55ea791a9286398a6120920690Adam Cohen 2136482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private void commitTempPlacement() { 2137482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < mCountX; i++) { 2138482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int j = 0; j < mCountY; j++) { 2139482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mOccupied[i][j] = mTmpOccupied[i][j]; 2140482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2141482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2142a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka int childCount = mShortcutsAndWidgets.getChildCount(); 2143482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < childCount; i++) { 2144ea889a294be004f4b1c21e9b874f9e63abfb8bd6Adam Cohen View child = mShortcutsAndWidgets.getChildAt(i); 2145ea889a294be004f4b1c21e9b874f9e63abfb8bd6Adam Cohen LayoutParams lp = (LayoutParams) child.getLayoutParams(); 2146ea889a294be004f4b1c21e9b874f9e63abfb8bd6Adam Cohen ItemInfo info = (ItemInfo) child.getTag(); 21472acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen // We do a null check here because the item info can be null in the case of the 21482acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen // AllApps button in the hotseat. 21492acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen if (info != null) { 21502acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen info.cellX = lp.cellX = lp.tmpCellX; 21512acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen info.cellY = lp.cellY = lp.tmpCellY; 2152bebf042666cffe52039b875a549a582abd78a431Adam Cohen info.spanX = lp.cellHSpan; 2153bebf042666cffe52039b875a549a582abd78a431Adam Cohen info.spanY = lp.cellVSpan; 21542acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen } 2155482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 21562acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen mLauncher.getWorkspace().updateItemLocationsInDatabase(this); 2157482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2158482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2159482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public void setUseTempCoords(boolean useTempCoords) { 2160a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka int childCount = mShortcutsAndWidgets.getChildCount(); 2161482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < childCount; i++) { 2162a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka LayoutParams lp = (LayoutParams) mShortcutsAndWidgets.getChildAt(i).getLayoutParams(); 2163482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen lp.useTmpCoords = useTempCoords; 2164482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2165482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2166482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2167482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen ItemConfiguration findConfigurationNoShuffle(int pixelX, int pixelY, int minSpanX, int minSpanY, 2168482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int spanX, int spanY, View dragView, ItemConfiguration solution) { 2169482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int[] result = new int[2]; 2170482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int[] resultSpan = new int[2]; 2171482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen findNearestVacantArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, null, result, 2172482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen resultSpan); 2173482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (result[0] >= 0 && result[1] >= 0) { 2174482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen copyCurrentStateToSolution(solution, false); 2175482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewX = result[0]; 2176482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewY = result[1]; 2177482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewSpanX = resultSpan[0]; 2178482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewSpanY = resultSpan[1]; 2179482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.isSolution = true; 2180482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } else { 2181482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.isSolution = false; 2182482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2183482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return solution; 2184482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2185482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2186482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public void prepareChildForDrag(View child) { 2187482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsAsUnoccupiedForView(child); 2188482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2189482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 219019f3792523fe2d55ea791a9286398a6120920690Adam Cohen /* This seems like it should be obvious and straight-forward, but when the direction vector 219119f3792523fe2d55ea791a9286398a6120920690Adam Cohen needs to match with the notion of the dragView pushing other views, we have to employ 219219f3792523fe2d55ea791a9286398a6120920690Adam Cohen a slightly more subtle notion of the direction vector. The question is what two points is 219319f3792523fe2d55ea791a9286398a6120920690Adam Cohen the vector between? The center of the dragView and its desired destination? Not quite, as 219419f3792523fe2d55ea791a9286398a6120920690Adam Cohen this doesn't necessarily coincide with the interaction of the dragView and items occupying 219519f3792523fe2d55ea791a9286398a6120920690Adam Cohen those cells. Instead we use some heuristics to often lock the vector to up, down, left 219619f3792523fe2d55ea791a9286398a6120920690Adam Cohen or right, which helps make pushing feel right. 219719f3792523fe2d55ea791a9286398a6120920690Adam Cohen */ 219819f3792523fe2d55ea791a9286398a6120920690Adam Cohen private void getDirectionVectorForDrop(int dragViewCenterX, int dragViewCenterY, int spanX, 219919f3792523fe2d55ea791a9286398a6120920690Adam Cohen int spanY, View dragView, int[] resultDirection) { 220019f3792523fe2d55ea791a9286398a6120920690Adam Cohen int[] targetDestination = new int[2]; 220119f3792523fe2d55ea791a9286398a6120920690Adam Cohen 220219f3792523fe2d55ea791a9286398a6120920690Adam Cohen findNearestArea(dragViewCenterX, dragViewCenterY, spanX, spanY, targetDestination); 220319f3792523fe2d55ea791a9286398a6120920690Adam Cohen Rect dragRect = new Rect(); 220419f3792523fe2d55ea791a9286398a6120920690Adam Cohen regionToRect(targetDestination[0], targetDestination[1], spanX, spanY, dragRect); 220519f3792523fe2d55ea791a9286398a6120920690Adam Cohen dragRect.offset(dragViewCenterX - dragRect.centerX(), dragViewCenterY - dragRect.centerY()); 220619f3792523fe2d55ea791a9286398a6120920690Adam Cohen 220719f3792523fe2d55ea791a9286398a6120920690Adam Cohen Rect dropRegionRect = new Rect(); 220819f3792523fe2d55ea791a9286398a6120920690Adam Cohen getViewsIntersectingRegion(targetDestination[0], targetDestination[1], spanX, spanY, 220919f3792523fe2d55ea791a9286398a6120920690Adam Cohen dragView, dropRegionRect, mIntersectingViews); 221019f3792523fe2d55ea791a9286398a6120920690Adam Cohen 221119f3792523fe2d55ea791a9286398a6120920690Adam Cohen int dropRegionSpanX = dropRegionRect.width(); 221219f3792523fe2d55ea791a9286398a6120920690Adam Cohen int dropRegionSpanY = dropRegionRect.height(); 221319f3792523fe2d55ea791a9286398a6120920690Adam Cohen 221419f3792523fe2d55ea791a9286398a6120920690Adam Cohen regionToRect(dropRegionRect.left, dropRegionRect.top, dropRegionRect.width(), 221519f3792523fe2d55ea791a9286398a6120920690Adam Cohen dropRegionRect.height(), dropRegionRect); 221619f3792523fe2d55ea791a9286398a6120920690Adam Cohen 221719f3792523fe2d55ea791a9286398a6120920690Adam Cohen int deltaX = (dropRegionRect.centerX() - dragViewCenterX) / spanX; 221819f3792523fe2d55ea791a9286398a6120920690Adam Cohen int deltaY = (dropRegionRect.centerY() - dragViewCenterY) / spanY; 221919f3792523fe2d55ea791a9286398a6120920690Adam Cohen 222019f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (dropRegionSpanX == mCountX || spanX == mCountX) { 222119f3792523fe2d55ea791a9286398a6120920690Adam Cohen deltaX = 0; 222219f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 222319f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (dropRegionSpanY == mCountY || spanY == mCountY) { 222419f3792523fe2d55ea791a9286398a6120920690Adam Cohen deltaY = 0; 222519f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 222619f3792523fe2d55ea791a9286398a6120920690Adam Cohen 222719f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (deltaX == 0 && deltaY == 0) { 222819f3792523fe2d55ea791a9286398a6120920690Adam Cohen // No idea what to do, give a random direction. 222919f3792523fe2d55ea791a9286398a6120920690Adam Cohen resultDirection[0] = 1; 223019f3792523fe2d55ea791a9286398a6120920690Adam Cohen resultDirection[1] = 0; 223119f3792523fe2d55ea791a9286398a6120920690Adam Cohen } else { 223219f3792523fe2d55ea791a9286398a6120920690Adam Cohen computeDirectionVector(deltaX, deltaY, resultDirection); 223319f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 223419f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 223519f3792523fe2d55ea791a9286398a6120920690Adam Cohen 223619f3792523fe2d55ea791a9286398a6120920690Adam Cohen // For a given cell and span, fetch the set of views intersecting the region. 223719f3792523fe2d55ea791a9286398a6120920690Adam Cohen private void getViewsIntersectingRegion(int cellX, int cellY, int spanX, int spanY, 223819f3792523fe2d55ea791a9286398a6120920690Adam Cohen View dragView, Rect boundingRect, ArrayList<View> intersectingViews) { 223919f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (boundingRect != null) { 224019f3792523fe2d55ea791a9286398a6120920690Adam Cohen boundingRect.set(cellX, cellY, cellX + spanX, cellY + spanY); 224119f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 224219f3792523fe2d55ea791a9286398a6120920690Adam Cohen intersectingViews.clear(); 224319f3792523fe2d55ea791a9286398a6120920690Adam Cohen Rect r0 = new Rect(cellX, cellY, cellX + spanX, cellY + spanY); 224419f3792523fe2d55ea791a9286398a6120920690Adam Cohen Rect r1 = new Rect(); 224519f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int count = mShortcutsAndWidgets.getChildCount(); 224619f3792523fe2d55ea791a9286398a6120920690Adam Cohen for (int i = 0; i < count; i++) { 224719f3792523fe2d55ea791a9286398a6120920690Adam Cohen View child = mShortcutsAndWidgets.getChildAt(i); 224819f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (child == dragView) continue; 224919f3792523fe2d55ea791a9286398a6120920690Adam Cohen LayoutParams lp = (LayoutParams) child.getLayoutParams(); 225019f3792523fe2d55ea791a9286398a6120920690Adam Cohen r1.set(lp.cellX, lp.cellY, lp.cellX + lp.cellHSpan, lp.cellY + lp.cellVSpan); 225119f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (Rect.intersects(r0, r1)) { 225219f3792523fe2d55ea791a9286398a6120920690Adam Cohen mIntersectingViews.add(child); 225319f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (boundingRect != null) { 225419f3792523fe2d55ea791a9286398a6120920690Adam Cohen boundingRect.union(r1); 225519f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 225619f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 225719f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 225819f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 225919f3792523fe2d55ea791a9286398a6120920690Adam Cohen 226019f3792523fe2d55ea791a9286398a6120920690Adam Cohen boolean isNearestDropLocationOccupied(int pixelX, int pixelY, int spanX, int spanY, 226119f3792523fe2d55ea791a9286398a6120920690Adam Cohen View dragView, int[] result) { 226219f3792523fe2d55ea791a9286398a6120920690Adam Cohen result = findNearestArea(pixelX, pixelY, spanX, spanY, result); 226319f3792523fe2d55ea791a9286398a6120920690Adam Cohen getViewsIntersectingRegion(result[0], result[1], spanX, spanY, dragView, null, 226419f3792523fe2d55ea791a9286398a6120920690Adam Cohen mIntersectingViews); 226519f3792523fe2d55ea791a9286398a6120920690Adam Cohen return !mIntersectingViews.isEmpty(); 226619f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 226719f3792523fe2d55ea791a9286398a6120920690Adam Cohen 226819f3792523fe2d55ea791a9286398a6120920690Adam Cohen void revertTempState() { 226919f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (!isItemPlacementDirty() || DESTRUCTIVE_REORDER) return; 227019f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int count = mShortcutsAndWidgets.getChildCount(); 227119f3792523fe2d55ea791a9286398a6120920690Adam Cohen for (int i = 0; i < count; i++) { 227219f3792523fe2d55ea791a9286398a6120920690Adam Cohen View child = mShortcutsAndWidgets.getChildAt(i); 227319f3792523fe2d55ea791a9286398a6120920690Adam Cohen LayoutParams lp = (LayoutParams) child.getLayoutParams(); 227419f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (lp.tmpCellX != lp.cellX || lp.tmpCellY != lp.cellY) { 227519f3792523fe2d55ea791a9286398a6120920690Adam Cohen lp.tmpCellX = lp.cellX; 227619f3792523fe2d55ea791a9286398a6120920690Adam Cohen lp.tmpCellY = lp.cellY; 227719f3792523fe2d55ea791a9286398a6120920690Adam Cohen animateChildToPosition(child, lp.cellX, lp.cellY, REORDER_ANIMATION_DURATION, 227819f3792523fe2d55ea791a9286398a6120920690Adam Cohen 0, false, false); 227919f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 228019f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 228119f3792523fe2d55ea791a9286398a6120920690Adam Cohen completeAndClearReorderHintAnimations(); 228219f3792523fe2d55ea791a9286398a6120920690Adam Cohen setItemPlacementDirty(false); 228319f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 228419f3792523fe2d55ea791a9286398a6120920690Adam Cohen 2285bebf042666cffe52039b875a549a582abd78a431Adam Cohen boolean createAreaForResize(int cellX, int cellY, int spanX, int spanY, 2286bebf042666cffe52039b875a549a582abd78a431Adam Cohen View dragView, int[] direction, boolean commit) { 2287bebf042666cffe52039b875a549a582abd78a431Adam Cohen int[] pixelXY = new int[2]; 2288bebf042666cffe52039b875a549a582abd78a431Adam Cohen regionToCenterPoint(cellX, cellY, spanX, spanY, pixelXY); 2289bebf042666cffe52039b875a549a582abd78a431Adam Cohen 2290bebf042666cffe52039b875a549a582abd78a431Adam Cohen // First we determine if things have moved enough to cause a different layout 2291bebf042666cffe52039b875a549a582abd78a431Adam Cohen ItemConfiguration swapSolution = simpleSwap(pixelXY[0], pixelXY[1], spanX, spanY, 2292bebf042666cffe52039b875a549a582abd78a431Adam Cohen spanX, spanY, direction, dragView, true, new ItemConfiguration()); 2293bebf042666cffe52039b875a549a582abd78a431Adam Cohen 2294bebf042666cffe52039b875a549a582abd78a431Adam Cohen setUseTempCoords(true); 2295bebf042666cffe52039b875a549a582abd78a431Adam Cohen if (swapSolution != null && swapSolution.isSolution) { 2296bebf042666cffe52039b875a549a582abd78a431Adam Cohen // If we're just testing for a possible location (MODE_ACCEPT_DROP), we don't bother 2297bebf042666cffe52039b875a549a582abd78a431Adam Cohen // committing anything or animating anything as we just want to determine if a solution 2298bebf042666cffe52039b875a549a582abd78a431Adam Cohen // exists 2299bebf042666cffe52039b875a549a582abd78a431Adam Cohen copySolutionToTempState(swapSolution, dragView); 2300bebf042666cffe52039b875a549a582abd78a431Adam Cohen setItemPlacementDirty(true); 2301bebf042666cffe52039b875a549a582abd78a431Adam Cohen animateItemsToSolution(swapSolution, dragView, commit); 2302bebf042666cffe52039b875a549a582abd78a431Adam Cohen 2303bebf042666cffe52039b875a549a582abd78a431Adam Cohen if (commit) { 2304bebf042666cffe52039b875a549a582abd78a431Adam Cohen commitTempPlacement(); 2305bebf042666cffe52039b875a549a582abd78a431Adam Cohen completeAndClearReorderHintAnimations(); 2306bebf042666cffe52039b875a549a582abd78a431Adam Cohen setItemPlacementDirty(false); 2307bebf042666cffe52039b875a549a582abd78a431Adam Cohen } else { 2308bebf042666cffe52039b875a549a582abd78a431Adam Cohen beginOrAdjustHintAnimations(swapSolution, dragView, 2309bebf042666cffe52039b875a549a582abd78a431Adam Cohen REORDER_ANIMATION_DURATION); 2310bebf042666cffe52039b875a549a582abd78a431Adam Cohen } 2311bebf042666cffe52039b875a549a582abd78a431Adam Cohen mShortcutsAndWidgets.requestLayout(); 2312bebf042666cffe52039b875a549a582abd78a431Adam Cohen } 2313bebf042666cffe52039b875a549a582abd78a431Adam Cohen return swapSolution.isSolution; 2314bebf042666cffe52039b875a549a582abd78a431Adam Cohen } 2315bebf042666cffe52039b875a549a582abd78a431Adam Cohen 2316482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int[] createArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, int spanY, 2317482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen View dragView, int[] result, int resultSpan[], int mode) { 2318482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // First we determine if things have moved enough to cause a different layout 231947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen result = findNearestArea(pixelX, pixelY, spanX, spanY, result); 2320482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2321482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (resultSpan == null) { 2322482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen resultSpan = new int[2]; 2323482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2324482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 232519f3792523fe2d55ea791a9286398a6120920690Adam Cohen // When we are checking drop validity or actually dropping, we don't recompute the 232619f3792523fe2d55ea791a9286398a6120920690Adam Cohen // direction vector, since we want the solution to match the preview, and it's possible 232719f3792523fe2d55ea791a9286398a6120920690Adam Cohen // that the exact position of the item has changed to result in a new reordering outcome. 2328b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen if ((mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL || mode == MODE_ACCEPT_DROP) 2329b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen && mPreviousReorderDirection[0] != INVALID_DIRECTION) { 233019f3792523fe2d55ea791a9286398a6120920690Adam Cohen mDirectionVector[0] = mPreviousReorderDirection[0]; 233119f3792523fe2d55ea791a9286398a6120920690Adam Cohen mDirectionVector[1] = mPreviousReorderDirection[1]; 233219f3792523fe2d55ea791a9286398a6120920690Adam Cohen // We reset this vector after drop 2333b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen if (mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL) { 2334b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen mPreviousReorderDirection[0] = INVALID_DIRECTION; 2335b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen mPreviousReorderDirection[1] = INVALID_DIRECTION; 233619f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 233719f3792523fe2d55ea791a9286398a6120920690Adam Cohen } else { 233819f3792523fe2d55ea791a9286398a6120920690Adam Cohen getDirectionVectorForDrop(pixelX, pixelY, spanX, spanY, dragView, mDirectionVector); 233919f3792523fe2d55ea791a9286398a6120920690Adam Cohen mPreviousReorderDirection[0] = mDirectionVector[0]; 234019f3792523fe2d55ea791a9286398a6120920690Adam Cohen mPreviousReorderDirection[1] = mDirectionVector[1]; 234119f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 234219f3792523fe2d55ea791a9286398a6120920690Adam Cohen 2343482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen ItemConfiguration swapSolution = simpleSwap(pixelX, pixelY, minSpanX, minSpanY, 2344482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen spanX, spanY, mDirectionVector, dragView, true, new ItemConfiguration()); 2345482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2346482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // We attempt the approach which doesn't shuffle views at all 2347482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen ItemConfiguration noShuffleSolution = findConfigurationNoShuffle(pixelX, pixelY, minSpanX, 2348482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen minSpanY, spanX, spanY, dragView, new ItemConfiguration()); 2349482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2350482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen ItemConfiguration finalSolution = null; 2351482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (swapSolution.isSolution && swapSolution.area() >= noShuffleSolution.area()) { 2352482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen finalSolution = swapSolution; 2353482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } else if (noShuffleSolution.isSolution) { 2354482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen finalSolution = noShuffleSolution; 2355482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2356482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2357482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean foundSolution = true; 2358482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (!DESTRUCTIVE_REORDER) { 2359482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen setUseTempCoords(true); 2360482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2361482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2362482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (finalSolution != null) { 2363482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result[0] = finalSolution.dragViewX; 2364482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result[1] = finalSolution.dragViewY; 2365482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen resultSpan[0] = finalSolution.dragViewSpanX; 2366482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen resultSpan[1] = finalSolution.dragViewSpanY; 2367482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2368482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // If we're just testing for a possible location (MODE_ACCEPT_DROP), we don't bother 2369482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // committing anything or animating anything as we just want to determine if a solution 2370482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // exists 2371482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (mode == MODE_DRAG_OVER || mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL) { 2372482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (!DESTRUCTIVE_REORDER) { 2373482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen copySolutionToTempState(finalSolution, dragView); 2374482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2375482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen setItemPlacementDirty(true); 2376482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen animateItemsToSolution(finalSolution, dragView, mode == MODE_ON_DROP); 2377482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 237819f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (!DESTRUCTIVE_REORDER && 237919f3792523fe2d55ea791a9286398a6120920690Adam Cohen (mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL)) { 2380482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen commitTempPlacement(); 238119f3792523fe2d55ea791a9286398a6120920690Adam Cohen completeAndClearReorderHintAnimations(); 238219f3792523fe2d55ea791a9286398a6120920690Adam Cohen setItemPlacementDirty(false); 238319f3792523fe2d55ea791a9286398a6120920690Adam Cohen } else { 238419f3792523fe2d55ea791a9286398a6120920690Adam Cohen beginOrAdjustHintAnimations(finalSolution, dragView, 238519f3792523fe2d55ea791a9286398a6120920690Adam Cohen REORDER_ANIMATION_DURATION); 2386482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2387482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2388482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } else { 2389482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen foundSolution = false; 2390482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result[0] = result[1] = resultSpan[0] = resultSpan[1] = -1; 2391482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2392482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2393482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if ((mode == MODE_ON_DROP || !foundSolution) && !DESTRUCTIVE_REORDER) { 2394482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen setUseTempCoords(false); 2395482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2396482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2397a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.requestLayout(); 2398482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return result; 2399482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2400482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 240119f3792523fe2d55ea791a9286398a6120920690Adam Cohen void setItemPlacementDirty(boolean dirty) { 240219f3792523fe2d55ea791a9286398a6120920690Adam Cohen mItemPlacementDirty = dirty; 2403482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 240419f3792523fe2d55ea791a9286398a6120920690Adam Cohen boolean isItemPlacementDirty() { 240519f3792523fe2d55ea791a9286398a6120920690Adam Cohen return mItemPlacementDirty; 2406482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2407482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2408482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private class ItemConfiguration { 24098baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen HashMap<View, CellAndSpan> map = new HashMap<View, CellAndSpan>(); 2410482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean isSolution = false; 2411482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int dragViewX, dragViewY, dragViewSpanX, dragViewSpanY; 2412482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2413482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int area() { 2414482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return dragViewSpanX * dragViewSpanY; 2415482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 24168baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen } 24178baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen 24188baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen private class CellAndSpan { 24198baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen int x, y; 24208baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen int spanX, spanY; 24218baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen 24228baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen public CellAndSpan(int x, int y, int spanX, int spanY) { 24238baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen this.x = x; 24248baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen this.y = y; 24258baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen this.spanX = spanX; 24268baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen this.spanY = spanY; 2427482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2428482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2429482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2430df0353815c629fc678824b07a234b89a1ff94208Adam Cohen /** 2431df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * Find a vacant area that will fit the given bounds nearest the requested 2432df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * cell location. Uses Euclidean distance to score multiple vacant areas. 2433df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * 2434df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param pixelX The X location at which you want to search for a vacant area. 2435df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param pixelY The Y location at which you want to search for a vacant area. 2436df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param spanX Horizontal span of the object. 2437df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param spanY Vertical span of the object. 2438df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param ignoreView Considers space occupied by this view as unoccupied 2439df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param result Previously returned value to possibly recycle. 2440df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @return The X, Y cell of a vacant area that can contain this object, 2441df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * nearest the requested location. 2442df0353815c629fc678824b07a234b89a1ff94208Adam Cohen */ 2443df0353815c629fc678824b07a234b89a1ff94208Adam Cohen int[] findNearestVacantArea( 2444df0353815c629fc678824b07a234b89a1ff94208Adam Cohen int pixelX, int pixelY, int spanX, int spanY, View ignoreView, int[] result) { 2445df0353815c629fc678824b07a234b89a1ff94208Adam Cohen return findNearestArea(pixelX, pixelY, spanX, spanY, ignoreView, true, result); 2446df0353815c629fc678824b07a234b89a1ff94208Adam Cohen } 2447df0353815c629fc678824b07a234b89a1ff94208Adam Cohen 2448df0353815c629fc678824b07a234b89a1ff94208Adam Cohen /** 2449d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * Find a vacant area that will fit the given bounds nearest the requested 2450d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * cell location. Uses Euclidean distance to score multiple vacant areas. 2451d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * 2452d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param pixelX The X location at which you want to search for a vacant area. 2453d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param pixelY The Y location at which you want to search for a vacant area. 2454d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param minSpanX The minimum horizontal span required 2455d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param minSpanY The minimum vertical span required 2456d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param spanX Horizontal span of the object. 2457d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param spanY Vertical span of the object. 2458d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param ignoreView Considers space occupied by this view as unoccupied 2459d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param result Previously returned value to possibly recycle. 2460d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @return The X, Y cell of a vacant area that can contain this object, 2461d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * nearest the requested location. 2462d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen */ 2463d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int[] findNearestVacantArea(int pixelX, int pixelY, int minSpanX, int minSpanY, 2464d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int spanX, int spanY, View ignoreView, int[] result, int[] resultSpan) { 2465482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return findNearestArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, ignoreView, true, 2466482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result, resultSpan, mOccupied); 2467d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 2468d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen 2469d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen /** 2470df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * Find a starting cell position that will fit the given bounds nearest the requested 2471df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * cell location. Uses Euclidean distance to score multiple vacant areas. 2472df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * 2473df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param pixelX The X location at which you want to search for a vacant area. 2474df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param pixelY The Y location at which you want to search for a vacant area. 2475df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param spanX Horizontal span of the object. 2476df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param spanY Vertical span of the object. 2477df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param ignoreView Considers space occupied by this view as unoccupied 2478df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param result Previously returned value to possibly recycle. 2479df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @return The X, Y cell of a vacant area that can contain this object, 2480df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * nearest the requested location. 2481df0353815c629fc678824b07a234b89a1ff94208Adam Cohen */ 2482df0353815c629fc678824b07a234b89a1ff94208Adam Cohen int[] findNearestArea( 2483df0353815c629fc678824b07a234b89a1ff94208Adam Cohen int pixelX, int pixelY, int spanX, int spanY, int[] result) { 2484df0353815c629fc678824b07a234b89a1ff94208Adam Cohen return findNearestArea(pixelX, pixelY, spanX, spanY, null, false, result); 2485df0353815c629fc678824b07a234b89a1ff94208Adam Cohen } 2486df0353815c629fc678824b07a234b89a1ff94208Adam Cohen 24870280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka boolean existsEmptyCell() { 24880280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka return findCellForSpan(null, 1, 1); 24890280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 24900280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 24910280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka /** 24920280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * Finds the upper-left coordinate of the first rectangle in the grid that can 24930280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * hold a cell of the specified dimensions. If intersectX and intersectY are not -1, 24940280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * then this method will only return coordinates for rectangles that contain the cell 24950280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * (intersectX, intersectY) 24960280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * 24970280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param cellXY The array that will contain the position of a vacant cell if such a cell 24980280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * can be found. 24990280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param spanX The horizontal span of the cell we want to find. 25000280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param spanY The vertical span of the cell we want to find. 25010280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * 25020280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @return True if a vacant cell of the specified dimension was found, false otherwise. 25030280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka */ 25040280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka boolean findCellForSpan(int[] cellXY, int spanX, int spanY) { 2505482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return findCellForSpanThatIntersectsIgnoring(cellXY, spanX, spanY, -1, -1, null, mOccupied); 25060280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 25070280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 25080280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka /** 25090280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * Like above, but ignores any cells occupied by the item "ignoreView" 25100280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * 25110280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param cellXY The array that will contain the position of a vacant cell if such a cell 25120280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * can be found. 25130280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param spanX The horizontal span of the cell we want to find. 25140280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param spanY The vertical span of the cell we want to find. 25150280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param ignoreView The home screen item we should treat as not occupying any space 25160280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @return 25170280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka */ 25180280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka boolean findCellForSpanIgnoring(int[] cellXY, int spanX, int spanY, View ignoreView) { 2519482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return findCellForSpanThatIntersectsIgnoring(cellXY, spanX, spanY, -1, -1, 2520482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen ignoreView, mOccupied); 25210280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 25220280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 25230280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka /** 25240280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * Like above, but if intersectX and intersectY are not -1, then this method will try to 25250280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * return coordinates for rectangles that contain the cell [intersectX, intersectY] 25260280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * 25270280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param spanX The horizontal span of the cell we want to find. 25280280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param spanY The vertical span of the cell we want to find. 25290280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param ignoreView The home screen item we should treat as not occupying any space 25300280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param intersectX The X coordinate of the cell that we should try to overlap 25310280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param intersectX The Y coordinate of the cell that we should try to overlap 25320280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * 25330280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @return True if a vacant cell of the specified dimension was found, false otherwise. 25340280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka */ 25350280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka boolean findCellForSpanThatIntersects(int[] cellXY, int spanX, int spanY, 25360280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka int intersectX, int intersectY) { 25370280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka return findCellForSpanThatIntersectsIgnoring( 2538482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen cellXY, spanX, spanY, intersectX, intersectY, null, mOccupied); 25390280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 25400280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 25410280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka /** 25420280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * The superset of the above two methods 25430280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka */ 25440280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka boolean findCellForSpanThatIntersectsIgnoring(int[] cellXY, int spanX, int spanY, 2545482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int intersectX, int intersectY, View ignoreView, boolean occupied[][]) { 2546c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka // mark space take by ignoreView as available (method checks if ignoreView is null) 2547482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsAsUnoccupiedForView(ignoreView, occupied); 25480280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 254928750fba6a2d141eb9a1e566718c17236030b815Michael Jurka boolean foundCell = false; 25500280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka while (true) { 25510280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka int startX = 0; 25520280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka if (intersectX >= 0) { 25530280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka startX = Math.max(startX, intersectX - (spanX - 1)); 25540280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 25550280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka int endX = mCountX - (spanX - 1); 25560280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka if (intersectX >= 0) { 25570280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka endX = Math.min(endX, intersectX + (spanX - 1) + (spanX == 1 ? 1 : 0)); 25580280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 25590280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka int startY = 0; 25600280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka if (intersectY >= 0) { 25610280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka startY = Math.max(startY, intersectY - (spanY - 1)); 25620280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 25630280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka int endY = mCountY - (spanY - 1); 25640280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka if (intersectY >= 0) { 25650280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka endY = Math.min(endY, intersectY + (spanY - 1) + (spanY == 1 ? 1 : 0)); 25660280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 25670280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 2568bbc60d8e79416e37cbede55c159bf6aaa6c171d5Winson Chung for (int y = startY; y < endY && !foundCell; y++) { 25690280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka inner: 2570bbc60d8e79416e37cbede55c159bf6aaa6c171d5Winson Chung for (int x = startX; x < endX; x++) { 25710280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka for (int i = 0; i < spanX; i++) { 25720280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka for (int j = 0; j < spanY; j++) { 2573482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (occupied[x + i][y + j]) { 2574bbc60d8e79416e37cbede55c159bf6aaa6c171d5Winson Chung // small optimization: we can skip to after the column we just found 25750280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // an occupied cell 2576bbc60d8e79416e37cbede55c159bf6aaa6c171d5Winson Chung x += i; 25770280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka continue inner; 25780280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 25790280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 25800280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 25810280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka if (cellXY != null) { 25820280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka cellXY[0] = x; 25830280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka cellXY[1] = y; 25840280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 258528750fba6a2d141eb9a1e566718c17236030b815Michael Jurka foundCell = true; 258628750fba6a2d141eb9a1e566718c17236030b815Michael Jurka break; 25870280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 25880280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 25890280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka if (intersectX == -1 && intersectY == -1) { 25900280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka break; 25910280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } else { 25920280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // if we failed to find anything, try again but without any requirements of 25930280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // intersecting 25940280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka intersectX = -1; 25950280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka intersectY = -1; 25960280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka continue; 25970280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 25980280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 25990280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 2600c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka // re-mark space taken by ignoreView as occupied 2601482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsAsOccupiedForView(ignoreView, occupied); 260228750fba6a2d141eb9a1e566718c17236030b815Michael Jurka return foundCell; 26030280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 26040280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 260531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 2606c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung * A drag event has begun over this layout. 2607c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung * It may have begun over this layout (in which case onDragChild is called first), 2608c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung * or it may have begun on another layout. 2609c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung */ 2610c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung void onDragEnter() { 2611c6cc61d45836e4081920883cc4d448ccb0bb8417Adam Cohen mDragEnforcer.onDragEnter(); 2612c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung mDragging = true; 2613c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung } 2614c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung 2615c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung /** 26160280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * Called when drag has left this CellLayout or has been completed (successfully or not) 26176569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy */ 26180280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka void onDragExit() { 2619c6cc61d45836e4081920883cc4d448ccb0bb8417Adam Cohen mDragEnforcer.onDragExit(); 26204be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // This can actually be called when we aren't in a drag, e.g. when adding a new 26214be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // item to this layout via the customize drawer. 26224be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // Guard against that case. 26234be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato if (mDragging) { 26244be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato mDragging = false; 26254be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato } 262608ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy 262708ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy // Invalidate the drag data 2628d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen mDragCell[0] = mDragCell[1] = -1; 262908ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy mDragOutlineAnims[mDragOutlineCurrent].animateOut(); 263008ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy mDragOutlineCurrent = (mDragOutlineCurrent + 1) % mDragOutlineAnims.length; 263119f3792523fe2d55ea791a9286398a6120920690Adam Cohen revertTempState(); 263233945b21544bc98381df17726a3537c292d8c985Michael Jurka setIsDragOverlapping(false); 26336569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy } 26346569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 26356569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy /** 2636aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * Mark a child as having been dropped. 2637de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy * At the beginning of the drag operation, the child may have been on another 2638ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy * screen, but it is re-parented before this method is called. 263931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 264031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param child The child that is being dropped 264131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 2642716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen void onDropChild(View child) { 2643d94533d04a5f8f5485f106d10af60169857ea899Romain Guy if (child != null) { 2644d94533d04a5f8f5485f106d10af60169857ea899Romain Guy LayoutParams lp = (LayoutParams) child.getLayoutParams(); 264584f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy lp.dropped = true; 2646d94533d04a5f8f5485f106d10af60169857ea899Romain Guy child.requestLayout(); 2647d94533d04a5f8f5485f106d10af60169857ea899Romain Guy } 264831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 264931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 265031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 265131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Computes a bounding rectangle for a range of cells 2652aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * 265331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param cellX X coordinate of upper left corner expressed as a cell position 265431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param cellY Y coordinate of upper left corner expressed as a cell position 2655aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * @param cellHSpan Width in cells 265631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param cellVSpan Height in cells 26576569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy * @param resultRect Rect into which to put the results 265831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 2659d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen public void cellToRect(int cellX, int cellY, int cellHSpan, int cellVSpan, Rect resultRect) { 266031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int cellWidth = mCellWidth; 266131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int cellHeight = mCellHeight; 266231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int widthGap = mWidthGap; 266331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int heightGap = mHeightGap; 2664aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 26654b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung final int hStartPadding = getPaddingLeft(); 26664b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung final int vStartPadding = getPaddingTop(); 2667aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 266831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int width = cellHSpan * cellWidth + ((cellHSpan - 1) * widthGap); 266931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int height = cellVSpan * cellHeight + ((cellVSpan - 1) * heightGap); 267031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 267131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int x = hStartPadding + cellX * (cellWidth + widthGap); 267231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int y = vStartPadding + cellY * (cellHeight + heightGap); 2673aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 26746569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy resultRect.set(x, y, x + width, y + height); 267531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 2676aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 267731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 2678aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * Computes the required horizontal and vertical cell spans to always 267931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * fit the given rectangle. 2680aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * 268131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param width Width in pixels 268231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param height Height in pixels 26838f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy * @param result An array of length 2 in which to store the result (may be null). 268431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 26858f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy public int[] rectToCell(int width, int height, int[] result) { 26869987a5c45e7d01a780d73b269bdce8d8a5309219Michael Jurka return rectToCell(getResources(), width, height, result); 26879987a5c45e7d01a780d73b269bdce8d8a5309219Michael Jurka } 26889987a5c45e7d01a780d73b269bdce8d8a5309219Michael Jurka 26899987a5c45e7d01a780d73b269bdce8d8a5309219Michael Jurka public static int[] rectToCell(Resources resources, int width, int height, int[] result) { 269031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // Always assume we're working with the smallest span to make sure we 269131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // reserve enough space in both orientations. 269279e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato int actualWidth = resources.getDimensionPixelSize(R.dimen.workspace_cell_width); 269379e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato int actualHeight = resources.getDimensionPixelSize(R.dimen.workspace_cell_height); 269431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int smallerSize = Math.min(actualWidth, actualHeight); 269579e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato 269631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // Always round up to next largest cell 269754c725cc294cd43ed0650179bfae64a622547660Winson Chung int spanX = (int) Math.ceil(width / (float) smallerSize); 269854c725cc294cd43ed0650179bfae64a622547660Winson Chung int spanY = (int) Math.ceil(height / (float) smallerSize); 269979e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato 27008f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy if (result == null) { 27018f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy return new int[] { spanX, spanY }; 27028f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy } 27038f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy result[0] = spanX; 27048f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy result[1] = spanY; 27058f86ddcb90063a56c25c9c782316574bc4e5dd93Patrick Dubroy return result; 270631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 270731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 2708f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka public int[] cellSpansToSize(int hSpans, int vSpans) { 2709f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka int[] size = new int[2]; 2710f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka size[0] = hSpans * mCellWidth + (hSpans - 1) * mWidthGap; 2711f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka size[1] = vSpans * mCellHeight + (vSpans - 1) * mHeightGap; 2712f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka return size; 2713f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka } 2714f12c75cb48f87955600c56ccbe0aac84b0c11b28Michael Jurka 271531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 2716047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy * Calculate the grid spans needed to fit given item 2717047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy */ 2718047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy public void calculateSpans(ItemInfo info) { 2719047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy final int minWidth; 2720047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy final int minHeight; 2721047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy 2722047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy if (info instanceof LauncherAppWidgetInfo) { 2723047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy minWidth = ((LauncherAppWidgetInfo) info).minWidth; 2724047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy minHeight = ((LauncherAppWidgetInfo) info).minHeight; 2725047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy } else if (info instanceof PendingAddWidgetInfo) { 2726047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy minWidth = ((PendingAddWidgetInfo) info).minWidth; 2727047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy minHeight = ((PendingAddWidgetInfo) info).minHeight; 2728047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy } else { 2729047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy // It's not a widget, so it must be 1x1 2730047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy info.spanX = info.spanY = 1; 2731047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy return; 2732047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy } 2733047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy int[] spans = rectToCell(minWidth, minHeight, null); 2734047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy info.spanX = spans[0]; 2735047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy info.spanY = spans[1]; 2736047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy } 2737047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy 2738047379aa61b4719ab38ce595f23732e8f3b1b8e1Patrick Dubroy /** 273931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Find the first vacant cell, if there is one. 274031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 274131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param vacant Holds the x and y coordinate of the vacant cell 274231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param spanX Horizontal cell span. 274331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param spanY Vertical cell span. 2744aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * 274531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @return True if a vacant cell was found 274631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 274731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public boolean getVacantCell(int[] vacant, int spanX, int spanY) { 274831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 27490280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka return findVacantCell(vacant, spanX, spanY, mCountX, mCountY, mOccupied); 275031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 275131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 275231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project static boolean findVacantCell(int[] vacant, int spanX, int spanY, 275331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int xCount, int yCount, boolean[][] occupied) { 275431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 27552801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen for (int y = 0; y < yCount; y++) { 27562801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen for (int x = 0; x < xCount; x++) { 275731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project boolean available = !occupied[x][y]; 275831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectout: for (int i = x; i < x + spanX - 1 && x < xCount; i++) { 275931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int j = y; j < y + spanY - 1 && y < yCount; j++) { 276031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project available = available && !occupied[i][j]; 276131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (!available) break out; 276231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 276331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 276431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 276531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (available) { 276631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project vacant[0] = x; 276731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project vacant[1] = y; 276831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return true; 276931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 277031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 277131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 277231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 277331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return false; 277431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 277531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 27760280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka private void clearOccupiedCells() { 27770280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka for (int x = 0; x < mCountX; x++) { 27780280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka for (int y = 0; y < mCountY; y++) { 27790280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka mOccupied[x][y] = false; 278031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 278131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 27820280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 278331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 2784d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen public void onMove(View view, int newCellX, int newCellY, int newSpanX, int newSpanY) { 27850280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka markCellsAsUnoccupiedForView(view); 2786482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsForView(newCellX, newCellY, newSpanX, newSpanY, mOccupied, true); 27870280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 278831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 2789d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen public void markCellsAsOccupiedForView(View view) { 2790482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsAsOccupiedForView(view, mOccupied); 2791482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2792482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public void markCellsAsOccupiedForView(View view, boolean[][] occupied) { 2793a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka if (view == null || view.getParent() != mShortcutsAndWidgets) return; 27940280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka LayoutParams lp = (LayoutParams) view.getLayoutParams(); 2795482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, occupied, true); 27960280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 27970280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 2798d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen public void markCellsAsUnoccupiedForView(View view) { 2799482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsAsUnoccupiedForView(view, mOccupied); 2800482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2801482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public void markCellsAsUnoccupiedForView(View view, boolean occupied[][]) { 2802a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka if (view == null || view.getParent() != mShortcutsAndWidgets) return; 28030280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka LayoutParams lp = (LayoutParams) view.getLayoutParams(); 2804482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, occupied, false); 28050280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 28060280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 2807482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private void markCellsForView(int cellX, int cellY, int spanX, int spanY, boolean[][] occupied, 2808482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean value) { 2809482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (cellX < 0 || cellY < 0) return; 28100280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka for (int x = cellX; x < cellX + spanX && x < mCountX; x++) { 28110280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka for (int y = cellY; y < cellY + spanY && y < mCountY; y++) { 2812482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen occupied[x][y] = value; 281331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 281431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 281531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 281631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 28172801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen public int getDesiredWidth() { 28188b805b17158886035b38261eb611d8641701ae43Michael Jurka return getPaddingLeft() + getPaddingRight() + (mCountX * mCellWidth) + 28192801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen (Math.max((mCountX - 1), 0) * mWidthGap); 28202801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen } 28212801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen 28222801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen public int getDesiredHeight() { 28238b805b17158886035b38261eb611d8641701ae43Michael Jurka return getPaddingTop() + getPaddingBottom() + (mCountY * mCellHeight) + 28242801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen (Math.max((mCountY - 1), 0) * mHeightGap); 28252801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen } 28262801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen 282766d72178af91d455700875635473be942bc90e54Michael Jurka public boolean isOccupied(int x, int y) { 282866d72178af91d455700875635473be942bc90e54Michael Jurka if (x < mCountX && y < mCountY) { 282966d72178af91d455700875635473be942bc90e54Michael Jurka return mOccupied[x][y]; 283066d72178af91d455700875635473be942bc90e54Michael Jurka } else { 283166d72178af91d455700875635473be942bc90e54Michael Jurka throw new RuntimeException("Position exceeds the bound of this CellLayout"); 283266d72178af91d455700875635473be942bc90e54Michael Jurka } 283366d72178af91d455700875635473be942bc90e54Michael Jurka } 283466d72178af91d455700875635473be942bc90e54Michael Jurka 283531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 283631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) { 283731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return new CellLayout.LayoutParams(getContext(), attrs); 283831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 283931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 284031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 284131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { 284231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return p instanceof CellLayout.LayoutParams; 284331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 284431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 284531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 284631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { 284731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return new CellLayout.LayoutParams(p); 284831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 284931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 2850aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung public static class CellLayoutAnimationController extends LayoutAnimationController { 2851aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung public CellLayoutAnimationController(Animation animation, float delay) { 2852aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung super(animation, delay); 2853aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung } 2854aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 2855aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung @Override 2856aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung protected long getDelayForView(View view) { 2857aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung return (int) (Math.random() * 150); 2858aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung } 2859aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung } 2860aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 286131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public static class LayoutParams extends ViewGroup.MarginLayoutParams { 286231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 286331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Horizontal location of the item in the grid. 286431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 286531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @ViewDebug.ExportedProperty 286631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public int cellX; 286731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 286831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 286931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Vertical location of the item in the grid. 287031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 287131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @ViewDebug.ExportedProperty 287231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public int cellY; 287331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 287431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 2875482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * Temporary horizontal location of the item in the grid during reorder 2876482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen */ 2877482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public int tmpCellX; 2878482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2879482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen /** 2880482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * Temporary vertical location of the item in the grid during reorder 2881482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen */ 2882482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public int tmpCellY; 2883482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2884482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen /** 2885482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * Indicates that the temporary coordinates should be used to layout the items 2886482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen */ 2887482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public boolean useTmpCoords; 2888482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2889482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen /** 289031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Number of cells spanned horizontally by the item. 289131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 289231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @ViewDebug.ExportedProperty 289331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public int cellHSpan; 289431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 289531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 289631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Number of cells spanned vertically by the item. 289731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 289831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @ViewDebug.ExportedProperty 289931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public int cellVSpan; 2900aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 29011b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen /** 29021b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen * Indicates whether the item will set its x, y, width and height parameters freely, 29031b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen * or whether these will be computed based on cellX, cellY, cellHSpan and cellVSpan. 29041b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen */ 2905d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen public boolean isLockedToGrid = true; 2906d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen 2907482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen /** 2908482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * Indicates whether this item can be reordered. Always true except in the case of the 2909482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * the AllApps button. 2910482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen */ 2911482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public boolean canReorder = true; 2912482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 291331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // X coordinate of the view in the layout. 291431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @ViewDebug.ExportedProperty 291531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int x; 291631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // Y coordinate of the view in the layout. 291731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @ViewDebug.ExportedProperty 291831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int y; 291931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 292084f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy boolean dropped; 2921fcb9e7144e58614f5ae0e9b272fb7ce040848c67Romain Guy 292231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public LayoutParams(Context c, AttributeSet attrs) { 292331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project super(c, attrs); 292431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellHSpan = 1; 292531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellVSpan = 1; 292631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 292731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 292831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public LayoutParams(ViewGroup.LayoutParams source) { 292931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project super(source); 293031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellHSpan = 1; 293131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellVSpan = 1; 293231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 2933aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 2934aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung public LayoutParams(LayoutParams source) { 2935aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung super(source); 2936aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung this.cellX = source.cellX; 2937aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung this.cellY = source.cellY; 2938aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung this.cellHSpan = source.cellHSpan; 2939aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung this.cellVSpan = source.cellVSpan; 2940aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung } 2941aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 294231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public LayoutParams(int cellX, int cellY, int cellHSpan, int cellVSpan) { 29438f19cdd62f6e2be05e3890916eabd11317ae1bc2Romain Guy super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); 294431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this.cellX = cellX; 294531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this.cellY = cellY; 294631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this.cellHSpan = cellHSpan; 294731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this.cellVSpan = cellVSpan; 294831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 294931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 29507f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public void setup(int cellWidth, int cellHeight, int widthGap, int heightGap) { 2951d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen if (isLockedToGrid) { 2952d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen final int myCellHSpan = cellHSpan; 2953d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen final int myCellVSpan = cellVSpan; 2954482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int myCellX = useTmpCoords ? tmpCellX : cellX; 2955482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int myCellY = useTmpCoords ? tmpCellY : cellY; 29561b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen 2957d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen width = myCellHSpan * cellWidth + ((myCellHSpan - 1) * widthGap) - 2958d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen leftMargin - rightMargin; 2959d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen height = myCellVSpan * cellHeight + ((myCellVSpan - 1) * heightGap) - 2960d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen topMargin - bottomMargin; 2961eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung x = (int) (myCellX * (cellWidth + widthGap) + leftMargin); 2962eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung y = (int) (myCellY * (cellHeight + heightGap) + topMargin); 2963d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen } 2964d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen } 2965d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen 2966aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung public String toString() { 2967aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung return "(" + this.cellX + ", " + this.cellY + ")"; 2968aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung } 29697f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 29707f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public void setWidth(int width) { 29717f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen this.width = width; 29727f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 29737f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 29747f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public int getWidth() { 29757f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen return width; 29767f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 29777f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 29787f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public void setHeight(int height) { 29797f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen this.height = height; 29807f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 29817f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 29827f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public int getHeight() { 29837f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen return height; 29847f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 29857f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 29867f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public void setX(int x) { 29877f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen this.x = x; 29887f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 29897f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 29907f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public int getX() { 29917f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen return x; 29927f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 29937f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 29947f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public void setY(int y) { 29957f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen this.y = y; 29967f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 29977f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 29987f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public int getY() { 29997f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen return y; 30007f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 300131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 300231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 30030280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // This class stores info for two purposes: 30040280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // 1. When dragging items (mDragInfo in Workspace), we store the View, its cellX & cellY, 30050280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // its spanX, spanY, and the screen it is on 30060280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // 2. When long clicking on an empty cell in a CellLayout, we save information about the 30070280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // cellX and cellY coordinates and which page was clicked. We then set this as a tag on 30080280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // the CellLayout that was long clicked 3009e5fb0f27bca7afb996258a7163c76ca7390d7bffMichael Jurka static final class CellInfo { 301031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project View cell; 3011a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka int cellX = -1; 3012a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka int cellY = -1; 301331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int spanX; 301431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int spanY; 301531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int screen; 30163d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung long container; 301731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 301831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 301931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public String toString() { 3020aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung return "Cell[view=" + (cell == null ? "null" : cell.getClass()) 3021aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung + ", x=" + cellX + ", y=" + cellY + "]"; 302231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 302331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 3024d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka 3025d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka public boolean lastDownOnOccupiedCell() { 3026d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka return mLastDownOnOccupiedCell; 3027d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka } 302831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project} 3029