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 17325dc23624160689e59fbac708cf6f222b20d025Daniel Sandlerpackage com.android.launcher3; 1831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 194be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onoratoimport android.animation.Animator; 20629758ff081a354e43aa409159211210ee4ee85aMichael Jurkaimport android.animation.AnimatorListenerAdapter; 2150e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keelyimport android.animation.AnimatorSet; 2200397b1d9233409d9d6b233b077ae12d09768ce8Chet Haaseimport android.animation.TimeInterpolator; 23de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroyimport android.animation.ValueAnimator; 24de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroyimport android.animation.ValueAnimator.AnimatorUpdateListener; 25c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohenimport android.annotation.TargetApi; 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; 3431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.graphics.Rect; 35482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohenimport android.graphics.drawable.ColorDrawable; 366569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroyimport android.graphics.drawable.Drawable; 372805e639cdea6ae0051155611d122ed27556e658Sunny Goyalimport android.graphics.drawable.TransitionDrawable; 38c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohenimport android.os.Build; 391462de39f01cec0ba785386532719cb0207dd827Adam Cohenimport android.os.Parcelable; 40c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohenimport android.support.v4.view.ViewCompat; 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; 48c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohenimport android.view.accessibility.AccessibilityEvent; 49150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chungimport android.view.animation.DecelerateInterpolator; 5031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 514b6eb269502d05edabf883535a7099da5862de42Sunny Goyalimport com.android.launcher3.BubbleTextView.BubbleTextShadowHandler; 52325dc23624160689e59fbac708cf6f222b20d025Daniel Sandlerimport com.android.launcher3.FolderIcon.FolderRingAnimator; 53e9b651eef1b9f3647eba94f833bff3fc52f5956bSunny Goyalimport com.android.launcher3.accessibility.DragAndDropAccessibilityDelegate; 54e9b651eef1b9f3647eba94f833bff3fc52f5956bSunny Goyalimport com.android.launcher3.accessibility.FolderAccessibilityHelper; 55e9b651eef1b9f3647eba94f833bff3fc52f5956bSunny Goyalimport com.android.launcher3.accessibility.WorkspaceAccessibilityHelper; 56091440a9cb9d4f42406631004aa484cbb79214caAdam Cohenimport com.android.launcher3.util.Thunk; 578e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy 5869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohenimport java.util.ArrayList; 59c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohenimport java.util.Arrays; 60f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohenimport java.util.Collections; 61f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohenimport java.util.Comparator; 62bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohenimport java.util.HashMap; 63d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohenimport java.util.Stack; 64c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen 654b6eb269502d05edabf883535a7099da5862de42Sunny Goyalpublic class CellLayout extends ViewGroup implements BubbleTextShadowHandler { 66e9b651eef1b9f3647eba94f833bff3fc52f5956bSunny Goyal public static final int WORKSPACE_ACCESSIBILITY_DRAG = 2; 67e9b651eef1b9f3647eba94f833bff3fc52f5956bSunny Goyal public static final int FOLDER_ACCESSIBILITY_DRAG = 1; 68e9b651eef1b9f3647eba94f833bff3fc52f5956bSunny Goyal 69aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung static final String TAG = "CellLayout"; 70aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 712acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen private Launcher mLauncher; 72091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen @Thunk int mCellWidth; 73091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen @Thunk int mCellHeight; 7411a1a53651924b544513f1f6971a735b18d67539Winson Chung private int mFixedCellWidth; 7511a1a53651924b544513f1f6971a735b18d67539Winson Chung private int mFixedCellHeight; 76aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 77091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen @Thunk int mCountX; 78091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen @Thunk int mCountY; 7931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 80234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen private int mOriginalWidthGap; 81234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen private int mOriginalHeightGap; 82091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen @Thunk int mWidthGap; 83091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen @Thunk int mHeightGap; 844b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung private int mMaxGap; 85917e38851cbc6caffe1f8dade4db452bace522baAdam Cohen private boolean mDropPending = false; 86c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen private boolean mIsDragTarget = true; 8731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 88de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy // These are temporary variables to prevent having to allocate a new object just to 89de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy // return an (x, y) value from helper functions. Do NOT use them to maintain other state. 90091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen @Thunk final int[] mTmpPoint = new int[2]; 912805e639cdea6ae0051155611d122ed27556e658Sunny Goyal @Thunk final int[] mTempLocation = new int[2]; 926569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 9331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project boolean[][] mOccupied; 94482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean[][] mTmpOccupied; 9531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 96dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka private OnTouchListener mInterceptTouchListener; 97ef044dd380ac3abf354027750efdc16d5d48ac70Mady Mellor private StylusEventHelper mStylusEventHelper; 98dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka 9969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen private ArrayList<FolderRingAnimator> mFolderOuterRings = new ArrayList<FolderRingAnimator>(); 100c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen private int[] mFolderLeaveBehindCell = {-1, -1}; 10169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 1025f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka private float mBackgroundAlpha; 103f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen 1042805e639cdea6ae0051155611d122ed27556e658Sunny Goyal private static final int BACKGROUND_ACTIVATE_DURATION = 120; 1052805e639cdea6ae0051155611d122ed27556e658Sunny Goyal private final TransitionDrawable mBackground; 1062805e639cdea6ae0051155611d122ed27556e658Sunny Goyal 107f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen // These values allow a fixed measurement to be set on the CellLayout. 108f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen private int mFixedWidth = -1; 109f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen private int mFixedHeight = -1; 110f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen 11133945b21544bc98381df17726a3537c292d8c985Michael Jurka // If we're actively dragging something over this screen, mIsDragOverlapping is true 11233945b21544bc98381df17726a3537c292d8c985Michael Jurka private boolean mIsDragOverlapping = false; 1136569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 114150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung // These arrays are used to implement the drag visualization on x-large screens. 1154be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // They are used as circular arrays, indexed by mDragOutlineCurrent. 116091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen @Thunk Rect[] mDragOutlines = new Rect[4]; 117091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen @Thunk float[] mDragOutlineAlphas = new float[mDragOutlines.length]; 1184be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato private InterruptibleInOutAnimator[] mDragOutlineAnims = 1194be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato new InterruptibleInOutAnimator[mDragOutlines.length]; 120150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung 121150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung // Used as an index into the above 3 arrays; indicates which is the most current value. 1224be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato private int mDragOutlineCurrent = 0; 1238e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy private final Paint mDragOutlinePaint = new Paint(); 124150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung 1254fe5a37dda8eb1869f9328d94236eb2c23f8109cSunny Goyal private final ClickShadowView mTouchFeedbackView; 12696864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy 127316490e636aad788fcfbfc2e04dd4f0e145bdd00Sunny Goyal @Thunk HashMap<CellLayout.LayoutParams, Animator> mReorderAnimators = new HashMap<>(); 128316490e636aad788fcfbfc2e04dd4f0e145bdd00Sunny Goyal @Thunk HashMap<View, ReorderPreviewAnimation> mShakeAnimators = new HashMap<>(); 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; 141307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen private float mHotseatScale = 1f; 1420dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn 143fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen public static final int MODE_SHOW_REORDER_HINT = 0; 144fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen public static final int MODE_DRAG_OVER = 1; 145fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen public static final int MODE_ON_DROP = 2; 146fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen public static final int MODE_ON_DROP_EXTERNAL = 3; 147fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen public static final int MODE_ACCEPT_DROP = 4; 14819f3792523fe2d55ea791a9286398a6120920690Adam Cohen private static final boolean DESTRUCTIVE_REORDER = false; 149482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private static final boolean DEBUG_VISUALIZE_OCCUPIED = false; 150482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 151a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen static final int LANDSCAPE = 0; 152a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen static final int PORTRAIT = 1; 153a897f397e553826f327d853d5728d0e1d24513a6Adam Cohen 154fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen private static final float REORDER_PREVIEW_MAGNITUDE = 0.12f; 15519f3792523fe2d55ea791a9286398a6120920690Adam Cohen private static final int REORDER_ANIMATION_DURATION = 150; 156091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen @Thunk float mReorderPreviewAnimationMagnitude; 15719f3792523fe2d55ea791a9286398a6120920690Adam Cohen 158482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private ArrayList<View> mIntersectingViews = new ArrayList<View>(); 159482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private Rect mOccupiedRect = new Rect(); 160482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private int[] mDirectionVector = new int[2]; 16119f3792523fe2d55ea791a9286398a6120920690Adam Cohen int[] mPreviousReorderDirection = new int[2]; 162b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen private static final int INVALID_DIRECTION = -100; 163482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1642805e639cdea6ae0051155611d122ed27556e658Sunny Goyal private final Rect mTempRect = new Rect(); 1653a6e7f330e680ef718ca7c0921d842efb4d8bbaeWinson Chung 166ca99383daef92fed673de22126875cb485be494fMichael Jurka private final static Paint sPaint = new Paint(); 1678a0bff5e35f63321178bbf777ec24d42544866b3Romain Guy 168c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen // Related to accessible drag and drop 169e9b651eef1b9f3647eba94f833bff3fc52f5956bSunny Goyal private DragAndDropAccessibilityDelegate mTouchHelper; 170c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen private boolean mUseTouchHelper = false; 171c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen 17231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public CellLayout(Context context) { 17331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this(context, null); 17431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 17531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 17631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public CellLayout(Context context, AttributeSet attrs) { 17731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this(context, attrs, 0); 17831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 17931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 18031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public CellLayout(Context context, AttributeSet attrs, int defStyle) { 18131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project super(context, attrs, defStyle); 1826569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 1836569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy // A ViewGroup usually does not draw, but CellLayout needs to draw a rectangle to show 1846569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy // the user where a dragged item will land when dropped. 1856569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy setWillNotDraw(false); 186ce3cbd145b4222779abae32869da8dd3c2aefb67Romain Guy setClipToPadding(false); 1872acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen mLauncher = (Launcher) context; 188a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka 1892e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen DeviceProfile grid = mLauncher.getDeviceProfile(); 19031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CellLayout, defStyle, 0); 19131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 19211a1a53651924b544513f1f6971a735b18d67539Winson Chung mCellWidth = mCellHeight = -1; 1935f7099af8573c2229427318acd551b92efae02a3Nilesh Agrawal mFixedCellWidth = mFixedCellHeight = -1; 1945f8afe6280eae34620067696173e71943e1a30a3Winson Chung mWidthGap = mOriginalWidthGap = 0; 1955f8afe6280eae34620067696173e71943e1a30a3Winson Chung mHeightGap = mOriginalHeightGap = 0; 1965f8afe6280eae34620067696173e71943e1a30a3Winson Chung mMaxGap = Integer.MAX_VALUE; 1972e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen mCountX = (int) grid.inv.numColumns; 1982e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen mCountY = (int) grid.inv.numRows; 1990280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka mOccupied = new boolean[mCountX][mCountY]; 200482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mTmpOccupied = new boolean[mCountX][mCountY]; 2015b53f29f809a0dad4a1e0717ba610ce737ee0f43Adam Cohen mPreviousReorderDirection[0] = INVALID_DIRECTION; 2025b53f29f809a0dad4a1e0717ba610ce737ee0f43Adam Cohen mPreviousReorderDirection[1] = INVALID_DIRECTION; 20331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 20431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project a.recycle(); 20531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 20631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project setAlwaysDrawnWithCacheEnabled(false); 20731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 208046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy final Resources res = getResources(); 2096e1c0d34bb31cacc24c57c89ab01deaa8985814fWinson Chung mHotseatScale = (float) grid.hotseatIconSizePx / grid.iconSizePx; 210de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy 2112805e639cdea6ae0051155611d122ed27556e658Sunny Goyal mBackground = (TransitionDrawable) res.getDrawable(R.drawable.bg_screenpanel); 2122805e639cdea6ae0051155611d122ed27556e658Sunny Goyal mBackground.setCallback(this); 213e8f1d047b1b788bc9884be2417e7aa0cec7e8ae8Winson Chung mBackground.setAlpha((int) (mBackgroundAlpha * 255)); 214b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung 215fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen mReorderPreviewAnimationMagnitude = (REORDER_PREVIEW_MAGNITUDE * 2165f8afe6280eae34620067696173e71943e1a30a3Winson Chung grid.iconSizePx); 21719f3792523fe2d55ea791a9286398a6120920690Adam Cohen 218046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy // Initialize the data structures used for the drag visualization. 219ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy mEaseOutInterpolator = new DecelerateInterpolator(2.5f); // Quint ease out 220b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung mDragCell[0] = mDragCell[1] = -1; 2214be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato for (int i = 0; i < mDragOutlines.length; i++) { 222d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen mDragOutlines[i] = new Rect(-1, -1, -1, -1); 223046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy } 224046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy 225046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy // When dragging things around the home screens, we show a green outline of 226046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy // where the item will land. The outlines gradually fade out, leaving a trail 227046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy // behind the drag path. 228046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy // Set up all the animations that are used to implement this fading. 229046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy final int duration = res.getInteger(R.integer.config_dragOutlineFadeTime); 230472b281d5cb4f5660df981a6c912266b9f5703feChet Haase final float fromAlphaValue = 0; 231472b281d5cb4f5660df981a6c912266b9f5703feChet Haase final float toAlphaValue = (float)res.getInteger(R.integer.config_dragOutlineMaxAlpha); 2324be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato 2338e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy Arrays.fill(mDragOutlineAlphas, fromAlphaValue); 2344be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato 2354be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato for (int i = 0; i < mDragOutlineAnims.length; i++) { 236046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy final InterruptibleInOutAnimator anim = 237f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka new InterruptibleInOutAnimator(this, duration, fromAlphaValue, toAlphaValue); 238ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy anim.getAnimator().setInterpolator(mEaseOutInterpolator); 239046e7eb472acac800128ab026f3bc6348b0f933fPatrick Dubroy final int thisIndex = i; 240472b281d5cb4f5660df981a6c912266b9f5703feChet Haase anim.getAnimator().addUpdateListener(new AnimatorUpdateListener() { 241de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy public void onAnimationUpdate(ValueAnimator animation) { 2424be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato final Bitmap outline = (Bitmap)anim.getTag(); 2434be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato 2444be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // If an animation is started and then stopped very quickly, we can still 2454be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // get spurious updates we've cleared the tag. Guard against this. 2464be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato if (outline == null) { 2473a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka @SuppressWarnings("all") // suppress dead code warning 2483a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka final boolean debug = false; 2493a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka if (debug) { 250fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy Object val = animation.getAnimatedValue(); 251fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy Log.d(TAG, "anim " + thisIndex + " update: " + val + 252fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy ", isStopped " + anim.isStopped()); 253fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy } 2544be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // Try to prevent it from continuing to run 2554be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato animation.cancel(); 2564be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato } else { 257472b281d5cb4f5660df981a6c912266b9f5703feChet Haase mDragOutlineAlphas[thisIndex] = (Float) animation.getAnimatedValue(); 258d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen CellLayout.this.invalidate(mDragOutlines[thisIndex]); 2594be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato } 260de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy } 261de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy }); 2624be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // The animation holds a reference to the drag outline bitmap as long is it's 2634be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // running. This way the bitmap can be GCed when the animations are complete. 264472b281d5cb4f5660df981a6c912266b9f5703feChet Haase anim.getAnimator().addListener(new AnimatorListenerAdapter() { 2653c4c20fbe682cb4b3ef94f09afe0af09171583f3Michael Jurka @Override 2664be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato public void onAnimationEnd(Animator animation) { 267472b281d5cb4f5660df981a6c912266b9f5703feChet Haase if ((Float) ((ValueAnimator) animation).getAnimatedValue() == 0f) { 2684be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato anim.setTag(null); 2694be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato } 2704be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato } 2714be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato }); 2724be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato mDragOutlineAnims[i] = anim; 273de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy } 274ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy 275a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets = new ShortcutAndWidgetContainer(context); 2762374abfda3e53f84e005df8923170308e4df8c03Adam Cohen mShortcutsAndWidgets.setCellDimensions(mCellWidth, mCellHeight, mWidthGap, mHeightGap, 2775f8afe6280eae34620067696173e71943e1a30a3Winson Chung mCountX, mCountY); 2782374abfda3e53f84e005df8923170308e4df8c03Adam Cohen 279ef044dd380ac3abf354027750efdc16d5d48ac70Mady Mellor mStylusEventHelper = new StylusEventHelper(this); 280ef044dd380ac3abf354027750efdc16d5d48ac70Mady Mellor 2814fe5a37dda8eb1869f9328d94236eb2c23f8109cSunny Goyal mTouchFeedbackView = new ClickShadowView(context); 2824fe5a37dda8eb1869f9328d94236eb2c23f8109cSunny Goyal addView(mTouchFeedbackView); 283a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka addView(mShortcutsAndWidgets); 28418014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka } 28518014791be2e3f41080f0bf621c618e3f096c5c7Michael Jurka 286c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen @TargetApi(Build.VERSION_CODES.LOLLIPOP) 287e9b651eef1b9f3647eba94f833bff3fc52f5956bSunny Goyal public void enableAccessibleDrag(boolean enable, int dragType) { 288c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen mUseTouchHelper = enable; 289c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen if (!enable) { 290c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen ViewCompat.setAccessibilityDelegate(this, null); 291c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO); 292c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen getShortcutsAndWidgets().setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO); 293c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen setOnClickListener(mLauncher); 294c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen } else { 295e9b651eef1b9f3647eba94f833bff3fc52f5956bSunny Goyal if (dragType == WORKSPACE_ACCESSIBILITY_DRAG && 296e9b651eef1b9f3647eba94f833bff3fc52f5956bSunny Goyal !(mTouchHelper instanceof WorkspaceAccessibilityHelper)) { 297e9b651eef1b9f3647eba94f833bff3fc52f5956bSunny Goyal mTouchHelper = new WorkspaceAccessibilityHelper(this); 298e9b651eef1b9f3647eba94f833bff3fc52f5956bSunny Goyal } else if (dragType == FOLDER_ACCESSIBILITY_DRAG && 299e9b651eef1b9f3647eba94f833bff3fc52f5956bSunny Goyal !(mTouchHelper instanceof FolderAccessibilityHelper)) { 300e9b651eef1b9f3647eba94f833bff3fc52f5956bSunny Goyal mTouchHelper = new FolderAccessibilityHelper(this); 301e9b651eef1b9f3647eba94f833bff3fc52f5956bSunny Goyal } 302c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen ViewCompat.setAccessibilityDelegate(this, mTouchHelper); 303c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); 304c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen getShortcutsAndWidgets().setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); 305c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen setOnClickListener(mTouchHelper); 306c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen } 307c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen 308c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen // Invalidate the accessibility hierarchy 309c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen if (getParent() != null) { 310c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen getParent().notifySubtreeAccessibilityStateChanged( 311c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen this, this, AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE); 312c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen } 313c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen } 314c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen 315c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen @Override 316c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen public boolean dispatchHoverEvent(MotionEvent event) { 317c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen // Always attempt to dispatch hover events to accessibility first. 318c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen if (mUseTouchHelper && mTouchHelper.dispatchHoverEvent(event)) { 319c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen return true; 320c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen } 321c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen return super.dispatchHoverEvent(event); 322c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen } 323c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen 324c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen @Override 325c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen public boolean onInterceptTouchEvent(MotionEvent ev) { 326c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen if (mUseTouchHelper || 327c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen (mInterceptTouchListener != null && mInterceptTouchListener.onTouch(this, ev))) { 328c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen return true; 329c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen } 330c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen return false; 331c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen } 332c9735cff2e558aa3f3810e49c15ef13049b9429cAdam Cohen 333ef044dd380ac3abf354027750efdc16d5d48ac70Mady Mellor @Override 334ef044dd380ac3abf354027750efdc16d5d48ac70Mady Mellor public boolean onTouchEvent(MotionEvent ev) { 335ef044dd380ac3abf354027750efdc16d5d48ac70Mady Mellor boolean handled = super.onTouchEvent(ev); 336ef044dd380ac3abf354027750efdc16d5d48ac70Mady Mellor // Stylus button press on a home screen should not switch between overview mode and 337ef044dd380ac3abf354027750efdc16d5d48ac70Mady Mellor // the home screen mode, however, once in overview mode stylus button press should be 338ef044dd380ac3abf354027750efdc16d5d48ac70Mady Mellor // enabled to allow rearranging the different home screens. So check what mode 339ef044dd380ac3abf354027750efdc16d5d48ac70Mady Mellor // the workspace is in, and only perform stylus button presses while in overview mode. 340ef044dd380ac3abf354027750efdc16d5d48ac70Mady Mellor if (mLauncher.mWorkspace.isInOverviewMode() 341ef044dd380ac3abf354027750efdc16d5d48ac70Mady Mellor && mStylusEventHelper.checkAndPerformStylusEvent(ev)) { 342ef044dd380ac3abf354027750efdc16d5d48ac70Mady Mellor return true; 343ef044dd380ac3abf354027750efdc16d5d48ac70Mady Mellor } 344ef044dd380ac3abf354027750efdc16d5d48ac70Mady Mellor return handled; 345ef044dd380ac3abf354027750efdc16d5d48ac70Mady Mellor } 346ef044dd380ac3abf354027750efdc16d5d48ac70Mady Mellor 34701f2d7fa4b24b21543012060305d693899b4beaaChris Craik public void enableHardwareLayer(boolean hasLayer) { 34801f2d7fa4b24b21543012060305d693899b4beaaChris Craik mShortcutsAndWidgets.setLayerType(hasLayer ? LAYER_TYPE_HARDWARE : LAYER_TYPE_NONE, sPaint); 349d51f33a6316c34fc69b8040946ed9a62519bb225Michael Jurka } 350d51f33a6316c34fc69b8040946ed9a62519bb225Michael Jurka 351d51f33a6316c34fc69b8040946ed9a62519bb225Michael Jurka public void buildHardwareLayer() { 352d51f33a6316c34fc69b8040946ed9a62519bb225Michael Jurka mShortcutsAndWidgets.buildLayer(); 3532801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen } 3542801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen 355307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen public float getChildrenScale() { 356307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen return mIsHotseat ? mHotseatScale : 1.0f; 357307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen } 358307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen 3595f8afe6280eae34620067696173e71943e1a30a3Winson Chung public void setCellDimensions(int width, int height) { 36011a1a53651924b544513f1f6971a735b18d67539Winson Chung mFixedCellWidth = mCellWidth = width; 36111a1a53651924b544513f1f6971a735b18d67539Winson Chung mFixedCellHeight = mCellHeight = height; 3625f8afe6280eae34620067696173e71943e1a30a3Winson Chung mShortcutsAndWidgets.setCellDimensions(mCellWidth, mCellHeight, mWidthGap, mHeightGap, 3635f8afe6280eae34620067696173e71943e1a30a3Winson Chung mCountX, mCountY); 3645f8afe6280eae34620067696173e71943e1a30a3Winson Chung } 3655f8afe6280eae34620067696173e71943e1a30a3Winson Chung 3662801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen public void setGridSize(int x, int y) { 3672801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen mCountX = x; 3682801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen mCountY = y; 3692801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen mOccupied = new boolean[mCountX][mCountY]; 370482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mTmpOccupied = new boolean[mCountX][mCountY]; 3717fbec10b36818f100b631f3d73fe1ad5360975aaAdam Cohen mTempRectStack.clear(); 3722374abfda3e53f84e005df8923170308e4df8c03Adam Cohen mShortcutsAndWidgets.setCellDimensions(mCellWidth, mCellHeight, mWidthGap, mHeightGap, 3735f8afe6280eae34620067696173e71943e1a30a3Winson Chung mCountX, mCountY); 37476fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen requestLayout(); 3752801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen } 3762801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen 3772374abfda3e53f84e005df8923170308e4df8c03Adam Cohen // Set whether or not to invert the layout horizontally if the layout is in RTL mode. 3782374abfda3e53f84e005df8923170308e4df8c03Adam Cohen public void setInvertIfRtl(boolean invert) { 3792374abfda3e53f84e005df8923170308e4df8c03Adam Cohen mShortcutsAndWidgets.setInvertIfRtl(invert); 3802374abfda3e53f84e005df8923170308e4df8c03Adam Cohen } 3812374abfda3e53f84e005df8923170308e4df8c03Adam Cohen 382917e38851cbc6caffe1f8dade4db452bace522baAdam Cohen public void setDropPending(boolean pending) { 383917e38851cbc6caffe1f8dade4db452bace522baAdam Cohen mDropPending = pending; 384917e38851cbc6caffe1f8dade4db452bace522baAdam Cohen } 385917e38851cbc6caffe1f8dade4db452bace522baAdam Cohen 386917e38851cbc6caffe1f8dade4db452bace522baAdam Cohen public boolean isDropPending() { 387917e38851cbc6caffe1f8dade4db452bace522baAdam Cohen return mDropPending; 388917e38851cbc6caffe1f8dade4db452bace522baAdam Cohen } 389917e38851cbc6caffe1f8dade4db452bace522baAdam Cohen 3904b6eb269502d05edabf883535a7099da5862de42Sunny Goyal @Override 3914b6eb269502d05edabf883535a7099da5862de42Sunny Goyal public void setPressedIcon(BubbleTextView icon, Bitmap background) { 392508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal if (icon == null || background == null) { 393508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal mTouchFeedbackView.setBitmap(null); 394508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal mTouchFeedbackView.animate().cancel(); 395508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal } else { 396508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal if (mTouchFeedbackView.setBitmap(background)) { 3974fe5a37dda8eb1869f9328d94236eb2c23f8109cSunny Goyal mTouchFeedbackView.alignWithIconView(icon, mShortcutsAndWidgets); 3984fe5a37dda8eb1869f9328d94236eb2c23f8109cSunny Goyal mTouchFeedbackView.animateShadow(); 399508da15509224b46fcccabbe78f3e92fe69a67d8Sunny Goyal } 40096864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy } 40196864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy } 40296864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy 403c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen void disableDragTarget() { 404c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen mIsDragTarget = false; 405c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen } 406c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen 407c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen boolean isDragTarget() { 408c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen return mIsDragTarget; 409c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen } 410c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen 411c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen void setIsDragOverlapping(boolean isDragOverlapping) { 412c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen if (mIsDragOverlapping != isDragOverlapping) { 413c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen mIsDragOverlapping = isDragOverlapping; 4142805e639cdea6ae0051155611d122ed27556e658Sunny Goyal if (mIsDragOverlapping) { 4152805e639cdea6ae0051155611d122ed27556e658Sunny Goyal mBackground.startTransition(BACKGROUND_ACTIVATE_DURATION); 4162805e639cdea6ae0051155611d122ed27556e658Sunny Goyal } else { 417e8f1d047b1b788bc9884be2417e7aa0cec7e8ae8Winson Chung if (mBackgroundAlpha > 0f) { 418e8f1d047b1b788bc9884be2417e7aa0cec7e8ae8Winson Chung mBackground.reverseTransition(BACKGROUND_ACTIVATE_DURATION); 419e8f1d047b1b788bc9884be2417e7aa0cec7e8ae8Winson Chung } else { 420e8f1d047b1b788bc9884be2417e7aa0cec7e8ae8Winson Chung mBackground.resetTransition(); 421e8f1d047b1b788bc9884be2417e7aa0cec7e8ae8Winson Chung } 4222805e639cdea6ae0051155611d122ed27556e658Sunny Goyal } 423c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen invalidate(); 424c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen } 425c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen } 426c50438c802355dff714b04f42a32e518cb9e91d8Adam Cohen 42733945b21544bc98381df17726a3537c292d8c985Michael Jurka boolean getIsDragOverlapping() { 42833945b21544bc98381df17726a3537c292d8c985Michael Jurka return mIsDragOverlapping; 42933945b21544bc98381df17726a3537c292d8c985Michael Jurka } 43033945b21544bc98381df17726a3537c292d8c985Michael Jurka 431a6abce8464b57ce91e8f083951ad263370fc2da8Romain Guy @Override 4321262e369484ce7f2565655ed80e6299232c70bd7Patrick Dubroy protected void onDraw(Canvas canvas) { 433057397714327b42c55804624cc06c7761d999f84Sunny Goyal if (!mIsDragTarget) { 434057397714327b42c55804624cc06c7761d999f84Sunny Goyal return; 435057397714327b42c55804624cc06c7761d999f84Sunny Goyal } 436057397714327b42c55804624cc06c7761d999f84Sunny Goyal 4373e7c7634531302271270c8cf418abc959d621cbcMichael Jurka // When we're large, we are either drawn in a "hover" state (ie when dragging an item to 4383e7c7634531302271270c8cf418abc959d621cbcMichael Jurka // a neighboring page) or with just a normal background (if backgroundAlpha > 0.0f) 4393e7c7634531302271270c8cf418abc959d621cbcMichael Jurka // When we're small, we are either drawn normally or in the "accepts drops" state (during 4403e7c7634531302271270c8cf418abc959d621cbcMichael Jurka // a drag). However, we also drag the mini hover background *over* one of those two 4413e7c7634531302271270c8cf418abc959d621cbcMichael Jurka // backgrounds 442057397714327b42c55804624cc06c7761d999f84Sunny Goyal if (mBackgroundAlpha > 0.0f) { 4432805e639cdea6ae0051155611d122ed27556e658Sunny Goyal mBackground.draw(canvas); 444a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka } 44531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 4468e58e916061cbe2623697efac0924f2aa3753a92Patrick Dubroy final Paint paint = mDragOutlinePaint; 4474be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato for (int i = 0; i < mDragOutlines.length; i++) { 448472b281d5cb4f5660df981a6c912266b9f5703feChet Haase final float alpha = mDragOutlineAlphas[i]; 4494be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato if (alpha > 0) { 450d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen final Rect r = mDragOutlines[i]; 4513a6e7f330e680ef718ca7c0921d842efb4d8bbaeWinson Chung mTempRect.set(r); 4523a6e7f330e680ef718ca7c0921d842efb4d8bbaeWinson Chung Utilities.scaleRectAboutCenter(mTempRect, getChildrenScale()); 4534be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato final Bitmap b = (Bitmap) mDragOutlineAnims[i].getTag(); 454472b281d5cb4f5660df981a6c912266b9f5703feChet Haase paint.setAlpha((int)(alpha + .5f)); 4553a6e7f330e680ef718ca7c0921d842efb4d8bbaeWinson Chung canvas.drawBitmap(b, null, mTempRect, paint); 456150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung } 4576569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy } 45896864c3c27d03b98d5a25b74b7647be064071144Patrick Dubroy 459482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (DEBUG_VISUALIZE_OCCUPIED) { 460482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int[] pt = new int[2]; 461482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen ColorDrawable cd = new ColorDrawable(Color.RED); 462e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen cd.setBounds(0, 0, mCellWidth, mCellHeight); 463482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < mCountX; i++) { 464482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int j = 0; j < mCountY; j++) { 465482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (mOccupied[i][j]) { 466482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen cellToPoint(i, j, pt); 467482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen canvas.save(); 468482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen canvas.translate(pt[0], pt[1]); 469482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen cd.draw(canvas); 470482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen canvas.restore(); 471482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 472482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 473482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 474482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 475482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 476850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn int previewOffset = FolderRingAnimator.sPreviewSize; 477850d2e718560cb12ae73292e9d39f21a93d3c2c1Andrew Flynn 47869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen // The folder outer / inner ring image(s) 4792e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen DeviceProfile grid = mLauncher.getDeviceProfile(); 48069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen for (int i = 0; i < mFolderOuterRings.size(); i++) { 48169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen FolderRingAnimator fra = mFolderOuterRings.get(i); 48269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 4835108bc0fd9f7e30c87c223fbb75f024e271b2103Adam Cohen Drawable d; 4845108bc0fd9f7e30c87c223fbb75f024e271b2103Adam Cohen int width, height; 48569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen cellToPoint(fra.mCellX, fra.mCellY, mTempLocation); 4865f8afe6280eae34620067696173e71943e1a30a3Winson Chung View child = getChildAt(fra.mCellX, fra.mCellY); 487558f1c2ac73c3a0c3c0c316222b6b7f9c76e2501Adam Cohen 48889f9705077c054b541af7da52be832760e2ae2e8Winson Chung if (child != null) { 489558f1c2ac73c3a0c3c0c316222b6b7f9c76e2501Adam Cohen int centerX = mTempLocation[0] + mCellWidth / 2; 490558f1c2ac73c3a0c3c0c316222b6b7f9c76e2501Adam Cohen int centerY = mTempLocation[1] + previewOffset / 2 + 491558f1c2ac73c3a0c3c0c316222b6b7f9c76e2501Adam Cohen child.getPaddingTop() + grid.folderBackgroundOffset; 492558f1c2ac73c3a0c3c0c316222b6b7f9c76e2501Adam Cohen 4935108bc0fd9f7e30c87c223fbb75f024e271b2103Adam Cohen // Draw outer ring, if it exists 4945108bc0fd9f7e30c87c223fbb75f024e271b2103Adam Cohen if (FolderIcon.HAS_OUTER_RING) { 4955108bc0fd9f7e30c87c223fbb75f024e271b2103Adam Cohen d = FolderRingAnimator.sSharedOuterRingDrawable; 4965108bc0fd9f7e30c87c223fbb75f024e271b2103Adam Cohen width = (int) (fra.getOuterRingSize() * getChildrenScale()); 4975108bc0fd9f7e30c87c223fbb75f024e271b2103Adam Cohen height = width; 4985108bc0fd9f7e30c87c223fbb75f024e271b2103Adam Cohen canvas.save(); 4995108bc0fd9f7e30c87c223fbb75f024e271b2103Adam Cohen canvas.translate(centerX - width / 2, centerY - height / 2); 5005108bc0fd9f7e30c87c223fbb75f024e271b2103Adam Cohen d.setBounds(0, 0, width, height); 5015108bc0fd9f7e30c87c223fbb75f024e271b2103Adam Cohen d.draw(canvas); 5025108bc0fd9f7e30c87c223fbb75f024e271b2103Adam Cohen canvas.restore(); 5035108bc0fd9f7e30c87c223fbb75f024e271b2103Adam Cohen } 50489f9705077c054b541af7da52be832760e2ae2e8Winson Chung 50589f9705077c054b541af7da52be832760e2ae2e8Winson Chung // Draw inner ring 50689f9705077c054b541af7da52be832760e2ae2e8Winson Chung d = FolderRingAnimator.sSharedInnerRingDrawable; 50789f9705077c054b541af7da52be832760e2ae2e8Winson Chung width = (int) (fra.getInnerRingSize() * getChildrenScale()); 50889f9705077c054b541af7da52be832760e2ae2e8Winson Chung height = width; 50989f9705077c054b541af7da52be832760e2ae2e8Winson Chung canvas.save(); 51089f9705077c054b541af7da52be832760e2ae2e8Winson Chung canvas.translate(centerX - width / 2, centerY - width / 2); 51189f9705077c054b541af7da52be832760e2ae2e8Winson Chung d.setBounds(0, 0, width, height); 51289f9705077c054b541af7da52be832760e2ae2e8Winson Chung d.draw(canvas); 51389f9705077c054b541af7da52be832760e2ae2e8Winson Chung canvas.restore(); 51489f9705077c054b541af7da52be832760e2ae2e8Winson Chung } 51569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen } 516c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen 517c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen if (mFolderLeaveBehindCell[0] >= 0 && mFolderLeaveBehindCell[1] >= 0) { 518c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen Drawable d = FolderIcon.sSharedFolderLeaveBehind; 519c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen int width = d.getIntrinsicWidth(); 520c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen int height = d.getIntrinsicHeight(); 521c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen 522c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen cellToPoint(mFolderLeaveBehindCell[0], mFolderLeaveBehindCell[1], mTempLocation); 5235f8afe6280eae34620067696173e71943e1a30a3Winson Chung View child = getChildAt(mFolderLeaveBehindCell[0], mFolderLeaveBehindCell[1]); 52489f9705077c054b541af7da52be832760e2ae2e8Winson Chung if (child != null) { 52589f9705077c054b541af7da52be832760e2ae2e8Winson Chung int centerX = mTempLocation[0] + mCellWidth / 2; 52689f9705077c054b541af7da52be832760e2ae2e8Winson Chung int centerY = mTempLocation[1] + previewOffset / 2 + 52789f9705077c054b541af7da52be832760e2ae2e8Winson Chung child.getPaddingTop() + grid.folderBackgroundOffset; 52889f9705077c054b541af7da52be832760e2ae2e8Winson Chung 52989f9705077c054b541af7da52be832760e2ae2e8Winson Chung canvas.save(); 53089f9705077c054b541af7da52be832760e2ae2e8Winson Chung canvas.translate(centerX - width / 2, centerY - width / 2); 53189f9705077c054b541af7da52be832760e2ae2e8Winson Chung d.setBounds(0, 0, width, height); 53289f9705077c054b541af7da52be832760e2ae2e8Winson Chung d.draw(canvas); 53389f9705077c054b541af7da52be832760e2ae2e8Winson Chung canvas.restore(); 53489f9705077c054b541af7da52be832760e2ae2e8Winson Chung } 535c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen } 53669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen } 53769ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 53869ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen public void showFolderAccept(FolderRingAnimator fra) { 53969ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen mFolderOuterRings.add(fra); 54069ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen } 54169ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen 54269ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen public void hideFolderAccept(FolderRingAnimator fra) { 54369ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen if (mFolderOuterRings.contains(fra)) { 54469ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen mFolderOuterRings.remove(fra); 54569ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen } 54669ce2e5beaa1a57c7b8fa14a2d6ff0b3abeb93c0Adam Cohen invalidate(); 5476569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy } 5486569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 549c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen public void setFolderLeaveBehindCell(int x, int y) { 550c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen mFolderLeaveBehindCell[0] = x; 551c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen mFolderLeaveBehindCell[1] = y; 552c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen invalidate(); 553c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen } 554c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen 555c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen public void clearFolderLeaveBehind() { 556c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen mFolderLeaveBehindCell[0] = -1; 557c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen mFolderLeaveBehindCell[1] = -1; 558c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen invalidate(); 559c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen } 560c51934bfdfed6a5011c6d6c5b7b70f2d75613d41Adam Cohen 5616569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy @Override 562e6235dd225404239b55c459245543f3302326112Michael Jurka public boolean shouldDelayChildPressedState() { 563e6235dd225404239b55c459245543f3302326112Michael Jurka return false; 564e6235dd225404239b55c459245543f3302326112Michael Jurka } 565e6235dd225404239b55c459245543f3302326112Michael Jurka 5661462de39f01cec0ba785386532719cb0207dd827Adam Cohen public void restoreInstanceState(SparseArray<Parcelable> states) { 56733a152fa4958b5c0b8c4b2f3857d62809862d15fSunny Goyal try { 56833a152fa4958b5c0b8c4b2f3857d62809862d15fSunny Goyal dispatchRestoreInstanceState(states); 56933a152fa4958b5c0b8c4b2f3857d62809862d15fSunny Goyal } catch (IllegalArgumentException ex) { 57033a152fa4958b5c0b8c4b2f3857d62809862d15fSunny Goyal if (LauncherAppState.isDogfoodBuild()) { 57133a152fa4958b5c0b8c4b2f3857d62809862d15fSunny Goyal throw ex; 57233a152fa4958b5c0b8c4b2f3857d62809862d15fSunny Goyal } 57333a152fa4958b5c0b8c4b2f3857d62809862d15fSunny Goyal // Mismatched viewId / viewType preventing restore. Skip restore on production builds. 57433a152fa4958b5c0b8c4b2f3857d62809862d15fSunny Goyal Log.e(TAG, "Ignoring an error while restoring a view instance state", ex); 57533a152fa4958b5c0b8c4b2f3857d62809862d15fSunny Goyal } 5761462de39f01cec0ba785386532719cb0207dd827Adam Cohen } 5771462de39f01cec0ba785386532719cb0207dd827Adam Cohen 578e6235dd225404239b55c459245543f3302326112Michael Jurka @Override 57983f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey public void cancelLongPress() { 58083f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey super.cancelLongPress(); 58183f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey 58283f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey // Cancel long press for all children 58383f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey final int count = getChildCount(); 58483f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey for (int i = 0; i < count; i++) { 58583f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey final View child = getChildAt(i); 58683f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey child.cancelLongPress(); 58783f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey } 58883f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey } 58983f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey 590dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka public void setOnInterceptTouchListener(View.OnTouchListener listener) { 591dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka mInterceptTouchListener = listener; 592dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } 593dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka 594ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song public int getCountX() { 595d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen return mCountX; 59631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 59731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 598ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song public int getCountY() { 599d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen return mCountY; 60031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 60131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 6020dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn public void setIsHotseat(boolean isHotseat) { 6030dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn mIsHotseat = isHotseat; 6045f8afe6280eae34620067696173e71943e1a30a3Winson Chung mShortcutsAndWidgets.setIsHotseat(isHotseat); 6050dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn } 6060dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn 607e9b651eef1b9f3647eba94f833bff3fc52f5956bSunny Goyal public boolean isHotseat() { 608e9b651eef1b9f3647eba94f833bff3fc52f5956bSunny Goyal return mIsHotseat; 609e9b651eef1b9f3647eba94f833bff3fc52f5956bSunny Goyal } 610e9b651eef1b9f3647eba94f833bff3fc52f5956bSunny Goyal 6110dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn public boolean addViewToCellLayout(View child, int index, int childId, LayoutParams params, 612f7a29e83f06909b378dba39c83a522375682710aSunny Goyal boolean markCells) { 613aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung final LayoutParams lp = params; 614aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 615de38e42fe89fd7490221427908cd97c51da21b44Andrew Flynn // Hotseat icons - remove text 6160dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn if (child instanceof BubbleTextView) { 6170dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn BubbleTextView bubbleChild = (BubbleTextView) child; 6185f8afe6280eae34620067696173e71943e1a30a3Winson Chung bubbleChild.setTextVisibility(!mIsHotseat); 6190dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn } 6200dca1ec41479a74f8da080224fa0c7eacab674d6Andrew Flynn 621307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen child.setScaleX(getChildrenScale()); 622307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen child.setScaleY(getChildrenScale()); 623307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen 62431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // Generate an id for each view, this assumes we have at most 256x256 cells 62531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // per workspace screen 626d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen if (lp.cellX >= 0 && lp.cellX <= mCountX - 1 && lp.cellY >= 0 && lp.cellY <= mCountY - 1) { 627aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung // If the horizontal or vertical span is set to -1, it is taken to 628aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung // mean that it spans the extent of the CellLayout 629d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen if (lp.cellHSpan < 0) lp.cellHSpan = mCountX; 630d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen if (lp.cellVSpan < 0) lp.cellVSpan = mCountY; 631aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 632aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung child.setId(childId); 633f7a29e83f06909b378dba39c83a522375682710aSunny Goyal mShortcutsAndWidgets.addView(child, index, lp); 634dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka 635f3ca3ab6958b104cbf2c2fa04add97d372a94d1cMichael Jurka if (markCells) markCellsAsOccupiedForView(child); 6360280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 637aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung return true; 638aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung } 639aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung return false; 64031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 6413e7c7634531302271270c8cf418abc959d621cbcMichael Jurka 64231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 6430280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka public void removeAllViews() { 6440280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka clearOccupiedCells(); 645a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.removeAllViews(); 6460280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 6470280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 6480280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka @Override 6490280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka public void removeAllViewsInLayout() { 650a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka if (mShortcutsAndWidgets.getChildCount() > 0) { 6517cfc2825c3a1029f962d2fc387ae2eaa85b51798Michael Jurka clearOccupiedCells(); 652a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.removeAllViewsInLayout(); 6537cfc2825c3a1029f962d2fc387ae2eaa85b51798Michael Jurka } 6540280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 6550280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 6560280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka @Override 6570280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka public void removeView(View view) { 6580280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka markCellsAsUnoccupiedForView(view); 659a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.removeView(view); 6600280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 6610280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 6620280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka @Override 6630280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka public void removeViewAt(int index) { 664a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka markCellsAsUnoccupiedForView(mShortcutsAndWidgets.getChildAt(index)); 665a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.removeViewAt(index); 6660280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 6670280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 6680280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka @Override 6690280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka public void removeViewInLayout(View view) { 6700280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka markCellsAsUnoccupiedForView(view); 671a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.removeViewInLayout(view); 6720280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 6730280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 6740280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka @Override 6750280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka public void removeViews(int start, int count) { 6760280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka for (int i = start; i < start + count; i++) { 677a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka markCellsAsUnoccupiedForView(mShortcutsAndWidgets.getChildAt(i)); 6780280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 679a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.removeViews(start, count); 6800280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 6810280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 6820280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka @Override 6830280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka public void removeViewsInLayout(int start, int count) { 6840280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka for (int i = start; i < start + count; i++) { 685a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka markCellsAsUnoccupiedForView(mShortcutsAndWidgets.getChildAt(i)); 6860280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 687a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.removeViewsInLayout(start, count); 688abded66084680bb31cc7ea403c88f44f79a3c884Michael Jurka } 689abded66084680bb31cc7ea403c88f44f79a3c884Michael Jurka 6906569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy /** 691aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * Given a point, return the cell that strictly encloses that point 69231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param x X coordinate of the point 69331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param y Y coordinate of the point 69431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param result Array of 2 ints to hold the x and y coordinate of the cell 69531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 696e9b651eef1b9f3647eba94f833bff3fc52f5956bSunny Goyal public void pointToCellExact(int x, int y, int[] result) { 6974b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung final int hStartPadding = getPaddingLeft(); 6984b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung final int vStartPadding = getPaddingTop(); 69931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 70031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project result[0] = (x - hStartPadding) / (mCellWidth + mWidthGap); 70131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project result[1] = (y - vStartPadding) / (mCellHeight + mHeightGap); 70231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 703d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen final int xAxis = mCountX; 704d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen final int yAxis = mCountY; 70531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 70631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (result[0] < 0) result[0] = 0; 70731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (result[0] >= xAxis) result[0] = xAxis - 1; 70831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (result[1] < 0) result[1] = 0; 70931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (result[1] >= yAxis) result[1] = yAxis - 1; 71031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 711aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 71231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 71331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Given a point, return the cell that most closely encloses that point 71431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param x X coordinate of the point 71531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param y Y coordinate of the point 71631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param result Array of 2 ints to hold the x and y coordinate of the cell 71731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 71831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project void pointToCellRounded(int x, int y, int[] result) { 71931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project pointToCellExact(x + (mCellWidth / 2), y + (mCellHeight / 2), result); 72031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 72131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 72231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 72331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Given a cell coordinate, return the point that represents the upper left corner of that cell 724aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * 725aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * @param cellX X coordinate of the cell 72631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param cellY Y coordinate of the cell 727aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * 72831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param result Array of 2 ints to hold the x and y coordinate of the point 72931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 73031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project void cellToPoint(int cellX, int cellY, int[] result) { 7314b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung final int hStartPadding = getPaddingLeft(); 7324b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung final int vStartPadding = getPaddingTop(); 73331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 73431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project result[0] = hStartPadding + cellX * (mCellWidth + mWidthGap); 73531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project result[1] = vStartPadding + cellY * (mCellHeight + mHeightGap); 73631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 73731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 738e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen /** 739482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * Given a cell coordinate, return the point that represents the center of the cell 740e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen * 741e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen * @param cellX X coordinate of the cell 742e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen * @param cellY Y coordinate of the cell 743e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen * 744e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen * @param result Array of 2 ints to hold the x and y coordinate of the point 745e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen */ 746e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen void cellToCenterPoint(int cellX, int cellY, int[] result) { 74747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen regionToCenterPoint(cellX, cellY, 1, 1, result); 74847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 74947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 75047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen /** 75147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * Given a cell coordinate and span return the point that represents the center of the regio 75247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * 75347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param cellX X coordinate of the cell 75447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param cellY Y coordinate of the cell 75547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * 75647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param result Array of 2 ints to hold the x and y coordinate of the point 75747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen */ 75847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen void regionToCenterPoint(int cellX, int cellY, int spanX, int spanY, int[] result) { 7594b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung final int hStartPadding = getPaddingLeft(); 7604b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung final int vStartPadding = getPaddingTop(); 76147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen result[0] = hStartPadding + cellX * (mCellWidth + mWidthGap) + 76247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen (spanX * mCellWidth + (spanX - 1) * mWidthGap) / 2; 76347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen result[1] = vStartPadding + cellY * (mCellHeight + mHeightGap) + 76447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen (spanY * mCellHeight + (spanY - 1) * mHeightGap) / 2; 765e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen } 766e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen 76719f3792523fe2d55ea791a9286398a6120920690Adam Cohen /** 76819f3792523fe2d55ea791a9286398a6120920690Adam Cohen * Given a cell coordinate and span fills out a corresponding pixel rect 76919f3792523fe2d55ea791a9286398a6120920690Adam Cohen * 77019f3792523fe2d55ea791a9286398a6120920690Adam Cohen * @param cellX X coordinate of the cell 77119f3792523fe2d55ea791a9286398a6120920690Adam Cohen * @param cellY Y coordinate of the cell 77219f3792523fe2d55ea791a9286398a6120920690Adam Cohen * @param result Rect in which to write the result 77319f3792523fe2d55ea791a9286398a6120920690Adam Cohen */ 77419f3792523fe2d55ea791a9286398a6120920690Adam Cohen void regionToRect(int cellX, int cellY, int spanX, int spanY, Rect result) { 77519f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int hStartPadding = getPaddingLeft(); 77619f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int vStartPadding = getPaddingTop(); 77719f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int left = hStartPadding + cellX * (mCellWidth + mWidthGap); 77819f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int top = vStartPadding + cellY * (mCellHeight + mHeightGap); 77919f3792523fe2d55ea791a9286398a6120920690Adam Cohen result.set(left, top, left + (spanX * mCellWidth + (spanX - 1) * mWidthGap), 78019f3792523fe2d55ea791a9286398a6120920690Adam Cohen top + (spanY * mCellHeight + (spanY - 1) * mHeightGap)); 78119f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 78219f3792523fe2d55ea791a9286398a6120920690Adam Cohen 783482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public float getDistanceFromCell(float x, float y, int[] cell) { 784482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen cellToCenterPoint(cell[0], cell[1], mTmpPoint); 785f7a29e83f06909b378dba39c83a522375682710aSunny Goyal return (float) Math.hypot(x - mTmpPoint[0], y - mTmpPoint[1]); 786482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 787482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 78884f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy int getCellWidth() { 78984f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy return mCellWidth; 79084f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy } 79184f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy 79284f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy int getCellHeight() { 79384f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy return mCellHeight; 79484f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy } 79584f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy 796d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen int getWidthGap() { 797d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen return mWidthGap; 798d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen } 799d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen 800d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen int getHeightGap() { 801d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen return mHeightGap; 802d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen } 803d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen 804f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen public void setFixedSize(int width, int height) { 805f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen mFixedWidth = width; 806f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen mFixedHeight = height; 807f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen } 808f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen 80931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 81031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 8115f8afe6280eae34620067696173e71943e1a30a3Winson Chung int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec); 81231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec); 8135f8afe6280eae34620067696173e71943e1a30a3Winson Chung int widthSize = MeasureSpec.getSize(widthMeasureSpec); 8145f8afe6280eae34620067696173e71943e1a30a3Winson Chung int heightSize = MeasureSpec.getSize(heightMeasureSpec); 8152d75f125f4e8bb5358dfdb63096d0493488ac2e5Winson Chung int childWidthSize = widthSize - (getPaddingLeft() + getPaddingRight()); 8162d75f125f4e8bb5358dfdb63096d0493488ac2e5Winson Chung int childHeightSize = heightSize - (getPaddingTop() + getPaddingBottom()); 81711a1a53651924b544513f1f6971a735b18d67539Winson Chung if (mFixedCellWidth < 0 || mFixedCellHeight < 0) { 818c6205603efe1f2987caf96504c87d720a25b5a94Sunny Goyal int cw = DeviceProfile.calculateCellWidth(childWidthSize, mCountX); 819c6205603efe1f2987caf96504c87d720a25b5a94Sunny Goyal int ch = DeviceProfile.calculateCellHeight(childHeightSize, mCountY); 82011a1a53651924b544513f1f6971a735b18d67539Winson Chung if (cw != mCellWidth || ch != mCellHeight) { 82111a1a53651924b544513f1f6971a735b18d67539Winson Chung mCellWidth = cw; 82211a1a53651924b544513f1f6971a735b18d67539Winson Chung mCellHeight = ch; 82311a1a53651924b544513f1f6971a735b18d67539Winson Chung mShortcutsAndWidgets.setCellDimensions(mCellWidth, mCellHeight, mWidthGap, 82411a1a53651924b544513f1f6971a735b18d67539Winson Chung mHeightGap, mCountX, mCountY); 82511a1a53651924b544513f1f6971a735b18d67539Winson Chung } 8265f8afe6280eae34620067696173e71943e1a30a3Winson Chung } 827aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 8282d75f125f4e8bb5358dfdb63096d0493488ac2e5Winson Chung int newWidth = childWidthSize; 8292d75f125f4e8bb5358dfdb63096d0493488ac2e5Winson Chung int newHeight = childHeightSize; 830f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen if (mFixedWidth > 0 && mFixedHeight > 0) { 831f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen newWidth = mFixedWidth; 832f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen newHeight = mFixedHeight; 833f0f4eda31841f41d892bf18847c1acdc45d2cd64Adam Cohen } else if (widthSpecMode == MeasureSpec.UNSPECIFIED || heightSpecMode == MeasureSpec.UNSPECIFIED) { 83431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project throw new RuntimeException("CellLayout cannot have UNSPECIFIED dimensions"); 83531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 83631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 837d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen int numWidthGaps = mCountX - 1; 838d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen int numHeightGaps = mCountY - 1; 839d22015cd37ea6ef53762eca5be57daca123ff607Adam Cohen 840234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen if (mOriginalWidthGap < 0 || mOriginalHeightGap < 0) { 8412d75f125f4e8bb5358dfdb63096d0493488ac2e5Winson Chung int hSpace = childWidthSize; 8422d75f125f4e8bb5358dfdb63096d0493488ac2e5Winson Chung int vSpace = childHeightSize; 843f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen int hFreeSpace = hSpace - (mCountX * mCellWidth); 844f4bd5792d505a83ef35b30e4fa4e786ac0df58a3Adam Cohen int vFreeSpace = vSpace - (mCountY * mCellHeight); 8454b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung mWidthGap = Math.min(mMaxGap, numWidthGaps > 0 ? (hFreeSpace / numWidthGaps) : 0); 8464b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung mHeightGap = Math.min(mMaxGap,numHeightGaps > 0 ? (vFreeSpace / numHeightGaps) : 0); 8475f8afe6280eae34620067696173e71943e1a30a3Winson Chung mShortcutsAndWidgets.setCellDimensions(mCellWidth, mCellHeight, mWidthGap, 8485f8afe6280eae34620067696173e71943e1a30a3Winson Chung mHeightGap, mCountX, mCountY); 849234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen } else { 850234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen mWidthGap = mOriginalWidthGap; 851234c4cd54406e363a2ebc213f6ae5be284414988Adam Cohen mHeightGap = mOriginalHeightGap; 852ece7f5b3b55cab646941123e03589241a61678e2Winson Chung } 8534fe5a37dda8eb1869f9328d94236eb2c23f8109cSunny Goyal 8544fe5a37dda8eb1869f9328d94236eb2c23f8109cSunny Goyal // Make the feedback view large enough to hold the blur bitmap. 8554fe5a37dda8eb1869f9328d94236eb2c23f8109cSunny Goyal mTouchFeedbackView.measure( 8564fe5a37dda8eb1869f9328d94236eb2c23f8109cSunny Goyal MeasureSpec.makeMeasureSpec(mCellWidth + mTouchFeedbackView.getExtraSize(), 8574fe5a37dda8eb1869f9328d94236eb2c23f8109cSunny Goyal MeasureSpec.EXACTLY), 8584fe5a37dda8eb1869f9328d94236eb2c23f8109cSunny Goyal MeasureSpec.makeMeasureSpec(mCellHeight + mTouchFeedbackView.getExtraSize(), 8594fe5a37dda8eb1869f9328d94236eb2c23f8109cSunny Goyal MeasureSpec.EXACTLY)); 8604fe5a37dda8eb1869f9328d94236eb2c23f8109cSunny Goyal 8614fe5a37dda8eb1869f9328d94236eb2c23f8109cSunny Goyal mShortcutsAndWidgets.measure( 8624fe5a37dda8eb1869f9328d94236eb2c23f8109cSunny Goyal MeasureSpec.makeMeasureSpec(newWidth, MeasureSpec.EXACTLY), 8634fe5a37dda8eb1869f9328d94236eb2c23f8109cSunny Goyal MeasureSpec.makeMeasureSpec(newHeight, MeasureSpec.EXACTLY)); 8644fe5a37dda8eb1869f9328d94236eb2c23f8109cSunny Goyal 8654fe5a37dda8eb1869f9328d94236eb2c23f8109cSunny Goyal int maxWidth = mShortcutsAndWidgets.getMeasuredWidth(); 8664fe5a37dda8eb1869f9328d94236eb2c23f8109cSunny Goyal int maxHeight = mShortcutsAndWidgets.getMeasuredHeight(); 8672d75f125f4e8bb5358dfdb63096d0493488ac2e5Winson Chung if (mFixedWidth > 0 && mFixedHeight > 0) { 8682d75f125f4e8bb5358dfdb63096d0493488ac2e5Winson Chung setMeasuredDimension(maxWidth, maxHeight); 8692d75f125f4e8bb5358dfdb63096d0493488ac2e5Winson Chung } else { 8702d75f125f4e8bb5358dfdb63096d0493488ac2e5Winson Chung setMeasuredDimension(widthSize, heightSize); 8712d75f125f4e8bb5358dfdb63096d0493488ac2e5Winson Chung } 87231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 87331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 87431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 87528750fba6a2d141eb9a1e566718c17236030b815Michael Jurka protected void onLayout(boolean changed, int l, int t, int r, int b) { 87638848ca3a9527e62eef1816770d25e7382cc4e4eWinson Chung int offset = getMeasuredWidth() - getPaddingLeft() - getPaddingRight() - 87738848ca3a9527e62eef1816770d25e7382cc4e4eWinson Chung (mCountX * mCellWidth); 87838848ca3a9527e62eef1816770d25e7382cc4e4eWinson Chung int left = getPaddingLeft() + (int) Math.ceil(offset / 2f); 87938848ca3a9527e62eef1816770d25e7382cc4e4eWinson Chung int top = getPaddingTop(); 8804fe5a37dda8eb1869f9328d94236eb2c23f8109cSunny Goyal 8814fe5a37dda8eb1869f9328d94236eb2c23f8109cSunny Goyal mTouchFeedbackView.layout(left, top, 8824fe5a37dda8eb1869f9328d94236eb2c23f8109cSunny Goyal left + mTouchFeedbackView.getMeasuredWidth(), 8834fe5a37dda8eb1869f9328d94236eb2c23f8109cSunny Goyal top + mTouchFeedbackView.getMeasuredHeight()); 8844fe5a37dda8eb1869f9328d94236eb2c23f8109cSunny Goyal mShortcutsAndWidgets.layout(left, top, 8854fe5a37dda8eb1869f9328d94236eb2c23f8109cSunny Goyal left + r - l, 8864fe5a37dda8eb1869f9328d94236eb2c23f8109cSunny Goyal top + b - t); 88731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 88831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 88931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 890dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka protected void onSizeChanged(int w, int h, int oldw, int oldh) { 891dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka super.onSizeChanged(w, h, oldw, oldh); 89282a9bd2c03645494cb0965abc03a9a18823e07e5Winson Chung 89382a9bd2c03645494cb0965abc03a9a18823e07e5Winson Chung // Expand the background drawing bounds by the padding baked into the background drawable 8942805e639cdea6ae0051155611d122ed27556e658Sunny Goyal mBackground.getPadding(mTempRect); 8952805e639cdea6ae0051155611d122ed27556e658Sunny Goyal mBackground.setBounds(-mTempRect.left, -mTempRect.top, 8962805e639cdea6ae0051155611d122ed27556e658Sunny Goyal w + mTempRect.right, h + mTempRect.bottom); 897dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } 898dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka 899dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka @Override 90031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected void setChildrenDrawingCacheEnabled(boolean enabled) { 901a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.setChildrenDrawingCacheEnabled(enabled); 90231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 90331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 90431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 90531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected void setChildrenDrawnWithCacheEnabled(boolean enabled) { 906a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.setChildrenDrawnWithCacheEnabled(enabled); 90731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 90831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 9095f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka public float getBackgroundAlpha() { 9105f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka return mBackgroundAlpha; 911dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } 912dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka 9135f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka public void setBackgroundAlpha(float alpha) { 914afaa05014e0bf3ed1192f9ddec2af4283bc50248Michael Jurka if (mBackgroundAlpha != alpha) { 915afaa05014e0bf3ed1192f9ddec2af4283bc50248Michael Jurka mBackgroundAlpha = alpha; 9162805e639cdea6ae0051155611d122ed27556e658Sunny Goyal mBackground.setAlpha((int) (mBackgroundAlpha * 255)); 917afaa05014e0bf3ed1192f9ddec2af4283bc50248Michael Jurka } 918dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } 919dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka 9202805e639cdea6ae0051155611d122ed27556e658Sunny Goyal @Override 9212805e639cdea6ae0051155611d122ed27556e658Sunny Goyal protected boolean verifyDrawable(Drawable who) { 9222805e639cdea6ae0051155611d122ed27556e658Sunny Goyal return super.verifyDrawable(who) || (mIsDragTarget && who == mBackground); 9232805e639cdea6ae0051155611d122ed27556e658Sunny Goyal } 9242805e639cdea6ae0051155611d122ed27556e658Sunny Goyal 925a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka public void setShortcutAndWidgetAlpha(float alpha) { 92602b508110484906118c277368d570a707604ec9cSunny Goyal mShortcutsAndWidgets.setAlpha(alpha); 927dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka } 928dee0589388ba0f6373912e18bf86243282fb3b9bMichael Jurka 929a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka public ShortcutAndWidgetContainer getShortcutsAndWidgets() { 930dcbcc86353e9ed52daac87f292aece667cd0ac71Sunny Goyal return mShortcutsAndWidgets; 931a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka } 932a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka 933440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy public View getChildAt(int x, int y) { 934a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka return mShortcutsAndWidgets.getChildAt(x, y); 935440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy } 936440c360bc395c43683fa9ca226e59f9e35f9e926Patrick Dubroy 93776fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen public boolean animateChildToPosition(final View child, int cellX, int cellY, int duration, 938482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int delay, boolean permanent, boolean adjustOccupied) { 939a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka ShortcutAndWidgetContainer clc = getShortcutsAndWidgets(); 940482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean[][] occupied = mOccupied; 941482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (!permanent) { 942482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen occupied = mTmpOccupied; 943482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 944482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 94519f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (clc.indexOfChild(child) != -1) { 946bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 947bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen final ItemInfo info = (ItemInfo) child.getTag(); 948bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen 949bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen // We cancel any existing animations 950bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen if (mReorderAnimators.containsKey(lp)) { 951bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen mReorderAnimators.get(lp).cancel(); 952bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen mReorderAnimators.remove(lp); 953bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 954bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen 955482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int oldX = lp.x; 956482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int oldY = lp.y; 957482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (adjustOccupied) { 958482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen occupied[lp.cellX][lp.cellY] = false; 959482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen occupied[cellX][cellY] = true; 960482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 961bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen lp.isLockedToGrid = true; 962482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (permanent) { 963482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen lp.cellX = info.cellX = cellX; 964482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen lp.cellY = info.cellY = cellY; 965482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } else { 966482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen lp.tmpCellX = cellX; 967482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen lp.tmpCellY = cellY; 968482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 969bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen clc.setupLp(lp); 970bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen lp.isLockedToGrid = false; 971482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int newX = lp.x; 972482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int newY = lp.y; 973bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen 97476fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen lp.x = oldX; 97576fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen lp.y = oldY; 97676fc085d28178a5d4fb3787ede956281a2cc3179Adam Cohen 977482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // Exit early if we're not actually moving the view 978482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (oldX == newX && oldY == newY) { 979482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen lp.isLockedToGrid = true; 980482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return true; 981482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 982482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 983f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka ValueAnimator va = LauncherAnimUtils.ofFloat(child, 0f, 1f); 984482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen va.setDuration(duration); 985482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mReorderAnimators.put(lp, va); 986482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 987482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen va.addUpdateListener(new AnimatorUpdateListener() { 988482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen @Override 989bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen public void onAnimationUpdate(ValueAnimator animation) { 990482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen float r = ((Float) animation.getAnimatedValue()).floatValue(); 99119f3792523fe2d55ea791a9286398a6120920690Adam Cohen lp.x = (int) ((1 - r) * oldX + r * newX); 99219f3792523fe2d55ea791a9286398a6120920690Adam Cohen lp.y = (int) ((1 - r) * oldY + r * newY); 9936b8a02d63a5d9cab8209381993e37db6a6afb753Adam Cohen child.requestLayout(); 994bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 995bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen }); 996482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen va.addListener(new AnimatorListenerAdapter() { 997bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen boolean cancelled = false; 998bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen public void onAnimationEnd(Animator animation) { 999bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen // If the animation was cancelled, it means that another animation 1000bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen // has interrupted this one, and we don't want to lock the item into 1001bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen // place just yet. 1002bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen if (!cancelled) { 1003bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen lp.isLockedToGrid = true; 1004482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen child.requestLayout(); 1005bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 1006bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen if (mReorderAnimators.containsKey(lp)) { 1007bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen mReorderAnimators.remove(lp); 1008bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 1009bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 1010bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen public void onAnimationCancel(Animator animation) { 1011bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen cancelled = true; 1012bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 1013bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen }); 1014482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen va.setStartDelay(delay); 1015482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen va.start(); 1016bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen return true; 1017bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 1018bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen return false; 1019bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen } 1020bfbfd26c627a18f8e1e3e6d0e53e78feab360203Adam Cohen 1021482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen void visualizeDropLocation(View v, Bitmap dragOutline, int originX, int originY, int cellX, 1022482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int cellY, int spanX, int spanY, boolean resize, Point dragOffset, Rect dragRegion) { 102308ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy final int oldDragCellX = mDragCell[0]; 102408ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy final int oldDragCellY = mDragCell[1]; 1025482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 10262801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen if (dragOutline == null && v == null) { 10272801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen return; 10282801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen } 10292801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen 1030482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (cellX != oldDragCellX || cellY != oldDragCellY) { 1031482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mDragCell[0] = cellX; 1032482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mDragCell[1] = cellY; 10336569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy // Find the top left corner of the rect the object will occupy 1034de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy final int[] topLeft = mTmpPoint; 1035482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen cellToPoint(cellX, cellY, topLeft); 1036de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy 10374be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato int left = topLeft[0]; 10384be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato int top = topLeft[1]; 10396569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 1040b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung if (v != null && dragOffset == null) { 104199e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen // When drawing the drag outline, it did not account for margin offsets 104299e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen // added by the view's parent. 104399e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen MarginLayoutParams lp = (MarginLayoutParams) v.getLayoutParams(); 104499e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen left += lp.leftMargin; 104599e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen top += lp.topMargin; 104699e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen 104799e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen // Offsets due to the size difference between the View and the dragOutline. 104899e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen // There is a size difference to account for the outer blur, which may lie 104999e8b40b374d49baabf0c4f4e4278ac25828899bAdam Cohen // outside the bounds of the view. 1050a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung top += (v.getHeight() - dragOutline.getHeight()) / 2; 1051ae915cecd36af4973061a1cb0b58c5be1be699a0Adam Cohen // We center about the x axis 1052ae915cecd36af4973061a1cb0b58c5be1be699a0Adam Cohen left += ((mCellWidth * spanX) + ((spanX - 1) * mWidthGap) 1053ae915cecd36af4973061a1cb0b58c5be1be699a0Adam Cohen - dragOutline.getWidth()) / 2; 10546639687cd67bab1aeef2a75e5c6bc458b20dc082Adam Cohen } else { 1055b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung if (dragOffset != null && dragRegion != null) { 1056b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung // Center the drag region *horizontally* in the cell and apply a drag 1057b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung // outline offset 1058b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung left += dragOffset.x + ((mCellWidth * spanX) + ((spanX - 1) * mWidthGap) 1059b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung - dragRegion.width()) / 2; 106069737c3e49ff3edc42899609fdbc96e356f8638eWinson Chung int cHeight = getShortcutsAndWidgets().getCellContentHeight(); 106169737c3e49ff3edc42899609fdbc96e356f8638eWinson Chung int cellPaddingY = (int) Math.max(0, ((mCellHeight - cHeight) / 2f)); 106269737c3e49ff3edc42899609fdbc96e356f8638eWinson Chung top += dragOffset.y + cellPaddingY; 1063b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung } else { 1064b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung // Center the drag outline in the cell 1065b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung left += ((mCellWidth * spanX) + ((spanX - 1) * mWidthGap) 1066b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung - dragOutline.getWidth()) / 2; 1067b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung top += ((mCellHeight * spanY) + ((spanY - 1) * mHeightGap) 1068b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung - dragOutline.getHeight()) / 2; 1069b8c69f3c17a40adc2d85e8e996f754c383c293dcWinson Chung } 1070a9abd0e0bdedb5cbbd12b84cb83037a735e79a20Winson Chung } 10714be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato final int oldIndex = mDragOutlineCurrent; 107208ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy mDragOutlineAnims[oldIndex].animateOut(); 107308ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy mDragOutlineCurrent = (oldIndex + 1) % mDragOutlines.length; 1074d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen Rect r = mDragOutlines[mDragOutlineCurrent]; 1075d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen r.set(left, top, left + dragOutline.getWidth(), top + dragOutline.getHeight()); 1076d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (resize) { 1077482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen cellToRect(cellX, cellY, spanX, spanY, r); 1078d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1079150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung 108008ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy mDragOutlineAnims[mDragOutlineCurrent].setTag(dragOutline); 108108ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy mDragOutlineAnims[mDragOutlineCurrent].animateIn(); 10826569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy } 10836569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy } 10846569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 1085e0310965022e7a1adb7ad489505d404186608689Adam Cohen public void clearDragOutlines() { 1086e0310965022e7a1adb7ad489505d404186608689Adam Cohen final int oldIndex = mDragOutlineCurrent; 1087e0310965022e7a1adb7ad489505d404186608689Adam Cohen mDragOutlineAnims[oldIndex].animateOut(); 1088d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen mDragCell[0] = mDragCell[1] = -1; 1089e0310965022e7a1adb7ad489505d404186608689Adam Cohen } 1090e0310965022e7a1adb7ad489505d404186608689Adam Cohen 109131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 109270864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * Find a vacant area that will fit the given bounds nearest the requested 109370864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * cell location. Uses Euclidean distance to score multiple vacant areas. 1094aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * 109551afc022fa76c79f0d1ece470ddc126c08fea8a4Romain Guy * @param pixelX The X location at which you want to search for a vacant area. 109651afc022fa76c79f0d1ece470ddc126c08fea8a4Romain Guy * @param pixelY The Y location at which you want to search for a vacant area. 109770864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * @param spanX Horizontal span of the object. 109870864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * @param spanY Vertical span of the object. 1099de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy * @param result Array in which to place the result, or null (in which case a new array will 1100de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy * be allocated) 110170864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * @return The X, Y cell of a vacant area that can contain this object, 110270864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * nearest the requested location. 110331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 1104f7a29e83f06909b378dba39c83a522375682710aSunny Goyal int[] findNearestVacantArea(int pixelX, int pixelY, int spanX, int spanY, int[] result) { 1105f7a29e83f06909b378dba39c83a522375682710aSunny Goyal return findNearestVacantArea(pixelX, pixelY, spanX, spanY, spanX, spanY, result, null); 11066a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka } 1107aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 11086a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka /** 11096a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * Find a vacant area that will fit the given bounds nearest the requested 11106a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * cell location. Uses Euclidean distance to score multiple vacant areas. 11116a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * 11126a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * @param pixelX The X location at which you want to search for a vacant area. 11136a1435d78d5133b1f37274c4d358bf6d22e10229Michael Jurka * @param pixelY The Y location at which you want to search for a vacant area. 1114d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param minSpanX The minimum horizontal span required 1115d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param minSpanY The minimum vertical span required 1116d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param spanX Horizontal span of the object. 1117d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param spanY Vertical span of the object. 1118d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param result Array in which to place the result, or null (in which case a new array will 1119d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * be allocated) 1120d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @return The X, Y cell of a vacant area that can contain this object, 1121d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * nearest the requested location. 1122d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen */ 1123d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int[] findNearestVacantArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, 1124d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int spanY, int[] result, int[] resultSpan) { 1125f7a29e83f06909b378dba39c83a522375682710aSunny Goyal return findNearestArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, true, 1126d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen result, resultSpan); 1127d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1128d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen 1129d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen private final Stack<Rect> mTempRectStack = new Stack<Rect>(); 1130d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen private void lazyInitTempRectStack() { 1131d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (mTempRectStack.isEmpty()) { 1132d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen for (int i = 0; i < mCountX * mCountY; i++) { 1133d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen mTempRectStack.push(new Rect()); 1134d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1135d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1136d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1137482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1138d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen private void recycleTempRects(Stack<Rect> used) { 1139d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen while (!used.isEmpty()) { 1140d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen mTempRectStack.push(used.pop()); 1141d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1142d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1143d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen 1144d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen /** 1145d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * Find a vacant area that will fit the given bounds nearest the requested 1146d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * cell location. Uses Euclidean distance to score multiple vacant areas. 1147d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * 1148d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param pixelX The X location at which you want to search for a vacant area. 1149d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param pixelY The Y location at which you want to search for a vacant area. 1150d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param minSpanX The minimum horizontal span required 1151d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param minSpanY The minimum vertical span required 1152d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param spanX Horizontal span of the object. 1153d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param spanY Vertical span of the object. 1154d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param ignoreOccupied If true, the result can be an occupied cell 1155d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @param result Array in which to place the result, or null (in which case a new array will 1156d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * be allocated) 1157d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * @return The X, Y cell of a vacant area that can contain this object, 1158d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen * nearest the requested location. 1159d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen */ 1160f7a29e83f06909b378dba39c83a522375682710aSunny Goyal private int[] findNearestArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, 1161f7a29e83f06909b378dba39c83a522375682710aSunny Goyal int spanY, boolean ignoreOccupied, int[] result, int[] resultSpan) { 1162d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen lazyInitTempRectStack(); 1163c6ee42e25f203e408826e7eab4ad8faf67ed2ff9Michael Jurka 1164e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen // For items with a spanX / spanY > 1, the passed in point (pixelX, pixelY) corresponds 1165e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen // to the center of the item, but we are searching based on the top-left cell, so 1166e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen // we translate the point over to correspond to the top-left. 1167e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen pixelX -= (mCellWidth + mWidthGap) * (spanX - 1) / 2f; 1168e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen pixelY -= (mCellHeight + mHeightGap) * (spanY - 1) / 2f; 1169e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen 117070864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey // Keep track of best-scoring drop area 1171de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy final int[] bestXY = result != null ? result : new int[2]; 117270864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey double bestDistance = Double.MAX_VALUE; 1173d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen final Rect bestRect = new Rect(-1, -1, -1, -1); 1174d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen final Stack<Rect> validRegions = new Stack<Rect>(); 1175aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 1176de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy final int countX = mCountX; 1177de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy final int countY = mCountY; 1178de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy 1179d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (minSpanX <= 0 || minSpanY <= 0 || spanX <= 0 || spanY <= 0 || 1180d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen spanX < minSpanX || spanY < minSpanY) { 1181d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen return bestXY; 1182d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1183d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen 1184d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen for (int y = 0; y < countY - (minSpanY - 1); y++) { 1185c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka inner: 1186d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen for (int x = 0; x < countX - (minSpanX - 1); x++) { 1187d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int ySize = -1; 1188d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen int xSize = -1; 1189df0353815c629fc678824b07a234b89a1ff94208Adam Cohen if (ignoreOccupied) { 1190d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // First, let's see if this thing fits anywhere 1191d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen for (int i = 0; i < minSpanX; i++) { 1192d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen for (int j = 0; j < minSpanY; j++) { 1193f7a29e83f06909b378dba39c83a522375682710aSunny Goyal if (mOccupied[x + i][y + j]) { 1194df0353815c629fc678824b07a234b89a1ff94208Adam Cohen continue inner; 1195df0353815c629fc678824b07a234b89a1ff94208Adam Cohen } 1196c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka } 1197c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka } 1198d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen xSize = minSpanX; 1199d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen ySize = minSpanY; 1200d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen 1201d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // We know that the item will fit at _some_ acceptable size, now let's see 1202d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // how big we can make it. We'll alternate between incrementing x and y spans 1203d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // until we hit a limit. 1204d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen boolean incX = true; 1205d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen boolean hitMaxX = xSize >= spanX; 1206d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen boolean hitMaxY = ySize >= spanY; 1207d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen while (!(hitMaxX && hitMaxY)) { 1208d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (incX && !hitMaxX) { 1209d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen for (int j = 0; j < ySize; j++) { 1210f7a29e83f06909b378dba39c83a522375682710aSunny Goyal if (x + xSize > countX -1 || mOccupied[x + xSize][y + j]) { 1211d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // We can't move out horizontally 1212d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen hitMaxX = true; 1213d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1214d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1215d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (!hitMaxX) { 1216d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen xSize++; 1217d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1218d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } else if (!hitMaxY) { 1219d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen for (int i = 0; i < xSize; i++) { 1220f7a29e83f06909b378dba39c83a522375682710aSunny Goyal if (y + ySize > countY - 1 || mOccupied[x + i][y + ySize]) { 1221d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // We can't move out vertically 1222d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen hitMaxY = true; 1223d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1224d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1225d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (!hitMaxY) { 1226d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen ySize++; 1227d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1228d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1229d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen hitMaxX |= xSize >= spanX; 1230d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen hitMaxY |= ySize >= spanY; 1231d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen incX = !incX; 1232d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1233d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen incX = true; 1234d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen hitMaxX = xSize >= spanX; 1235d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen hitMaxY = ySize >= spanY; 1236c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka } 12372805e639cdea6ae0051155611d122ed27556e658Sunny Goyal final int[] cellXY = mTmpPoint; 1238e3e27a854f3eca363d3c5ce353d19de475272d87Adam Cohen cellToCenterPoint(x, y, cellXY); 1239c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka 1240d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // We verify that the current rect is not a sub-rect of any of our previous 1241d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // candidates. In this case, the current rect is disqualified in favour of the 1242d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen // containing rect. 1243d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen Rect currentRect = mTempRectStack.pop(); 1244d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen currentRect.set(x, y, x + xSize, y + ySize); 1245d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen boolean contained = false; 1246d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen for (Rect r : validRegions) { 1247d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (r.contains(currentRect)) { 1248d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen contained = true; 1249d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen break; 1250d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1251d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1252d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen validRegions.push(currentRect); 1253f7a29e83f06909b378dba39c83a522375682710aSunny Goyal double distance = Math.hypot(cellXY[0] - pixelX, cellXY[1] - pixelY); 1254482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1255d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if ((distance <= bestDistance && !contained) || 1256d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen currentRect.contains(bestRect)) { 1257c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka bestDistance = distance; 1258c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka bestXY[0] = x; 1259c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka bestXY[1] = y; 1260d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen if (resultSpan != null) { 1261d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen resultSpan[0] = xSize; 1262d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen resultSpan[1] = ySize; 1263d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen } 1264d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen bestRect.set(currentRect); 1265c28de51eedb26848abf9245ddd19e021d30be318Michael Jurka } 126631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 126731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 126831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 1269c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen // Return -1, -1 if no suitable location found 1270c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen if (bestDistance == Double.MAX_VALUE) { 1271c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen bestXY[0] = -1; 1272c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen bestXY[1] = -1; 127370864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey } 1274d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen recycleTempRects(validRegions); 1275c0dcf597084d00e4c23a7fea5fd0738f6c095a6bAdam Cohen return bestXY; 127631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 1277aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 1278482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen /** 1279482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * Find a vacant area that will fit the given bounds nearest the requested 1280482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * cell location, and will also weigh in a suggested direction vector of the 1281482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * desired location. This method computers distance based on unit grid distances, 1282482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * not pixel distances. 1283482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * 128447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param cellX The X cell nearest to which you want to search for a vacant area. 128547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param cellY The Y cell nearest which you want to search for a vacant area. 1286482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * @param spanX Horizontal span of the object. 1287482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * @param spanY Vertical span of the object. 128847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param direction The favored direction in which the views should move from x, y 128947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param exactDirectionOnly If this parameter is true, then only solutions where the direction 129047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * matches exactly. Otherwise we find the best matching direction. 129147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param occoupied The array which represents which cells in the CellLayout are occupied 129247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen * @param blockOccupied The array which represents which cells in the specified block (cellX, 12935f8afe6280eae34620067696173e71943e1a30a3Winson Chung * cellY, spanX, spanY) are occupied. This is used when try to move a group of views. 1294482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * @param result Array in which to place the result, or null (in which case a new array will 1295482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * be allocated) 1296482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * @return The X, Y cell of a vacant area that can contain this object, 1297482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * nearest the requested location. 1298482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen */ 1299482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private int[] findNearestArea(int cellX, int cellY, int spanX, int spanY, int[] direction, 130047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean[][] occupied, boolean blockOccupied[][], int[] result) { 1301482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // Keep track of best-scoring drop area 1302482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int[] bestXY = result != null ? result : new int[2]; 1303482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen float bestDistance = Float.MAX_VALUE; 1304482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int bestDirectionScore = Integer.MIN_VALUE; 1305482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1306482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int countX = mCountX; 1307482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen final int countY = mCountY; 1308482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1309482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int y = 0; y < countY - (spanY - 1); y++) { 1310482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen inner: 1311482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int x = 0; x < countX - (spanX - 1); x++) { 1312482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // First, let's see if this thing fits anywhere 1313482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < spanX; i++) { 1314482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int j = 0; j < spanY; j++) { 131547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (occupied[x + i][y + j] && (blockOccupied == null || blockOccupied[i][j])) { 1316482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen continue inner; 1317482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1318482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1319482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1320482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1321f7a29e83f06909b378dba39c83a522375682710aSunny Goyal float distance = (float) Math.hypot(x - cellX, y - cellY); 1322482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int[] curDirection = mTmpPoint; 132347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen computeDirectionVector(x - cellX, y - cellY, curDirection); 132447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen // The direction score is just the dot product of the two candidate direction 132547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen // and that passed in. 1326482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int curDirectionScore = direction[0] * curDirection[0] + 1327482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen direction[1] * curDirection[1]; 132847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean exactDirectionOnly = false; 132947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean directionMatches = direction[0] == curDirection[0] && 133047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen direction[0] == curDirection[0]; 133147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if ((directionMatches || !exactDirectionOnly) && 133247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen Float.compare(distance, bestDistance) < 0 || (Float.compare(distance, 1333482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen bestDistance) == 0 && curDirectionScore > bestDirectionScore)) { 1334482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen bestDistance = distance; 1335482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen bestDirectionScore = curDirectionScore; 1336482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen bestXY[0] = x; 1337482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen bestXY[1] = y; 1338482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1339482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1340482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1341482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1342482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // Return -1, -1 if no suitable location found 1343482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (bestDistance == Float.MAX_VALUE) { 1344482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen bestXY[0] = -1; 1345482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen bestXY[1] = -1; 1346482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1347482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return bestXY; 1348482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1349482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1350482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private boolean addViewToTempLocation(View v, Rect rectOccupiedByPotentialDrop, 13518baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen int[] direction, ItemConfiguration currentState) { 13528baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = currentState.map.get(v); 1353482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean success = false; 13548baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, false); 1355482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsForRect(rectOccupiedByPotentialDrop, mTmpOccupied, true); 1356482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 13578baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen findNearestArea(c.x, c.y, c.spanX, c.spanY, direction, mTmpOccupied, null, mTempLocation); 1358482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1359482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (mTempLocation[0] >= 0 && mTempLocation[1] >= 0) { 13608baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen c.x = mTempLocation[0]; 13618baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen c.y = mTempLocation[1]; 1362482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen success = true; 1363482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 13648baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, true); 1365482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return success; 1366482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1367482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1368f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen /** 1369f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen * This helper class defines a cluster of views. It helps with defining complex edges 1370f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen * of the cluster and determining how those edges interact with other views. The edges 1371f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen * essentially define a fine-grained boundary around the cluster of views -- like a more 1372f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen * precise version of a bounding box. 1373f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen */ 1374f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen private class ViewCluster { 1375f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen final static int LEFT = 0; 1376f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen final static int TOP = 1; 1377f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen final static int RIGHT = 2; 1378f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen final static int BOTTOM = 3; 1379f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 1380f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen ArrayList<View> views; 1381f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen ItemConfiguration config; 1382f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen Rect boundingRect = new Rect(); 1383f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 1384f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen int[] leftEdge = new int[mCountY]; 1385f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen int[] rightEdge = new int[mCountY]; 1386f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen int[] topEdge = new int[mCountX]; 1387f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen int[] bottomEdge = new int[mCountX]; 1388f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen boolean leftEdgeDirty, rightEdgeDirty, topEdgeDirty, bottomEdgeDirty, boundingRectDirty; 138947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 1390f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen @SuppressWarnings("unchecked") 1391f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen public ViewCluster(ArrayList<View> views, ItemConfiguration config) { 1392f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen this.views = (ArrayList<View>) views.clone(); 1393f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen this.config = config; 1394f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen resetEdges(); 1395f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 139647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 1397f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen void resetEdges() { 1398f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen for (int i = 0; i < mCountX; i++) { 1399f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen topEdge[i] = -1; 1400f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen bottomEdge[i] = -1; 1401f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1402f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen for (int i = 0; i < mCountY; i++) { 1403f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen leftEdge[i] = -1; 1404f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen rightEdge[i] = -1; 1405f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1406f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen leftEdgeDirty = true; 1407f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen rightEdgeDirty = true; 1408f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen bottomEdgeDirty = true; 1409f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen topEdgeDirty = true; 1410f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen boundingRectDirty = true; 1411f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1412f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 1413f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen void computeEdge(int which, int[] edge) { 1414f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen int count = views.size(); 1415f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen for (int i = 0; i < count; i++) { 1416f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen CellAndSpan cs = config.map.get(views.get(i)); 1417f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen switch (which) { 1418f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen case LEFT: 1419f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen int left = cs.x; 1420f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen for (int j = cs.y; j < cs.y + cs.spanY; j++) { 1421f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (left < edge[j] || edge[j] < 0) { 1422f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen edge[j] = left; 1423f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1424f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1425f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen break; 1426f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen case RIGHT: 1427f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen int right = cs.x + cs.spanX; 1428f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen for (int j = cs.y; j < cs.y + cs.spanY; j++) { 1429f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (right > edge[j]) { 1430f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen edge[j] = right; 1431f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1432f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1433f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen break; 1434f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen case TOP: 1435f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen int top = cs.y; 1436f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen for (int j = cs.x; j < cs.x + cs.spanX; j++) { 1437f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (top < edge[j] || edge[j] < 0) { 1438f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen edge[j] = top; 1439f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1440f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1441f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen break; 1442f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen case BOTTOM: 1443f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen int bottom = cs.y + cs.spanY; 1444f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen for (int j = cs.x; j < cs.x + cs.spanX; j++) { 1445f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (bottom > edge[j]) { 1446f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen edge[j] = bottom; 1447f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1448f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1449f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen break; 1450f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1451f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 145247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 145347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 1454f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen boolean isViewTouchingEdge(View v, int whichEdge) { 1455f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen CellAndSpan cs = config.map.get(v); 145647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 1457f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen int[] edge = getEdge(whichEdge); 1458f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 1459f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen switch (whichEdge) { 1460f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen case LEFT: 1461f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen for (int i = cs.y; i < cs.y + cs.spanY; i++) { 1462f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (edge[i] == cs.x + cs.spanX) { 1463f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen return true; 146447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 146547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 1466f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen break; 1467f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen case RIGHT: 1468f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen for (int i = cs.y; i < cs.y + cs.spanY; i++) { 1469f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (edge[i] == cs.x) { 1470f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen return true; 1471f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1472f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1473f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen break; 1474f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen case TOP: 1475f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen for (int i = cs.x; i < cs.x + cs.spanX; i++) { 1476f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (edge[i] == cs.y + cs.spanY) { 1477f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen return true; 1478f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1479f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1480f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen break; 1481f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen case BOTTOM: 1482f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen for (int i = cs.x; i < cs.x + cs.spanX; i++) { 1483f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (edge[i] == cs.y) { 1484f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen return true; 1485f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1486f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1487f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen break; 1488f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1489f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen return false; 1490f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1491f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 1492f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen void shift(int whichEdge, int delta) { 1493f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen for (View v: views) { 1494f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen CellAndSpan c = config.map.get(v); 1495f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen switch (whichEdge) { 1496f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen case LEFT: 1497f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen c.x -= delta; 1498f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen break; 1499f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen case RIGHT: 1500f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen c.x += delta; 1501f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen break; 1502f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen case TOP: 1503f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen c.y -= delta; 1504f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen break; 1505f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen case BOTTOM: 1506f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen default: 1507f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen c.y += delta; 1508f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen break; 1509f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1510f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1511f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen resetEdges(); 1512f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1513f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 1514f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen public void addView(View v) { 1515f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen views.add(v); 1516f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen resetEdges(); 1517f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1518f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 1519f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen public Rect getBoundingRect() { 1520f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (boundingRectDirty) { 1521f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen boolean first = true; 1522f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen for (View v: views) { 1523f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen CellAndSpan c = config.map.get(v); 1524f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (first) { 1525f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen boundingRect.set(c.x, c.y, c.x + c.spanX, c.y + c.spanY); 1526f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen first = false; 1527f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } else { 1528a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen boundingRect.union(c.x, c.y, c.x + c.spanX, c.y + c.spanY); 1529a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen } 153047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 153147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 1532f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen return boundingRect; 1533f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1534f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 1535f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen public int[] getEdge(int which) { 1536f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen switch (which) { 1537f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen case LEFT: 1538f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen return getLeftEdge(); 1539f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen case RIGHT: 1540f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen return getRightEdge(); 1541f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen case TOP: 1542f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen return getTopEdge(); 1543f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen case BOTTOM: 1544f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen default: 1545f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen return getBottomEdge(); 1546f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1547f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1548f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 1549f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen public int[] getLeftEdge() { 1550f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (leftEdgeDirty) { 1551f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen computeEdge(LEFT, leftEdge); 1552f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1553f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen return leftEdge; 1554f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1555f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 1556f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen public int[] getRightEdge() { 1557f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (rightEdgeDirty) { 1558f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen computeEdge(RIGHT, rightEdge); 1559f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1560f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen return rightEdge; 1561f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1562f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 1563f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen public int[] getTopEdge() { 1564f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (topEdgeDirty) { 1565f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen computeEdge(TOP, topEdge); 1566f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1567f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen return topEdge; 1568f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1569f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 1570f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen public int[] getBottomEdge() { 1571f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (bottomEdgeDirty) { 1572f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen computeEdge(BOTTOM, bottomEdge); 1573f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1574f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen return bottomEdge; 1575f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1576f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 1577f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen PositionComparator comparator = new PositionComparator(); 1578f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen class PositionComparator implements Comparator<View> { 1579f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen int whichEdge = 0; 1580f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen public int compare(View left, View right) { 1581f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen CellAndSpan l = config.map.get(left); 1582f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen CellAndSpan r = config.map.get(right); 1583f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen switch (whichEdge) { 1584f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen case LEFT: 1585f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen return (r.x + r.spanX) - (l.x + l.spanX); 1586f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen case RIGHT: 1587f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen return l.x - r.x; 1588f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen case TOP: 1589f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen return (r.y + r.spanY) - (l.y + l.spanY); 1590f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen case BOTTOM: 1591f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen default: 1592f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen return l.y - r.y; 1593f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1594f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1595f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1596f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 1597f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen public void sortConfigurationForEdgePush(int edge) { 1598f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen comparator.whichEdge = edge; 1599f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen Collections.sort(config.sortedViews, comparator); 160047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 160147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 160247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 1603f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen private boolean pushViewsToTempLocation(ArrayList<View> views, Rect rectOccupiedByPotentialDrop, 1604f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen int[] direction, View dragView, ItemConfiguration currentState) { 1605f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 1606f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen ViewCluster cluster = new ViewCluster(views, currentState); 1607f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen Rect clusterRect = cluster.getBoundingRect(); 1608f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen int whichEdge; 1609f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen int pushDistance; 1610f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen boolean fail = false; 1611e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen 1612f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen // Determine the edge of the cluster that will be leading the push and how far 1613f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen // the cluster must be shifted. 1614f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (direction[0] < 0) { 1615f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen whichEdge = ViewCluster.LEFT; 1616f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen pushDistance = clusterRect.right - rectOccupiedByPotentialDrop.left; 1617e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen } else if (direction[0] > 0) { 1618f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen whichEdge = ViewCluster.RIGHT; 1619f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen pushDistance = rectOccupiedByPotentialDrop.right - clusterRect.left; 1620f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } else if (direction[1] < 0) { 1621f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen whichEdge = ViewCluster.TOP; 1622f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen pushDistance = clusterRect.bottom - rectOccupiedByPotentialDrop.top; 1623f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } else { 1624f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen whichEdge = ViewCluster.BOTTOM; 1625f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen pushDistance = rectOccupiedByPotentialDrop.bottom - clusterRect.top; 1626f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1627f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 1628f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen // Break early for invalid push distance. 1629f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (pushDistance <= 0) { 1630f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen return false; 1631f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1632f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 1633f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen // Mark the occupied state as false for the group of views we want to move. 1634f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen for (View v: views) { 1635f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen CellAndSpan c = currentState.map.get(v); 1636f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, false); 1637f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1638f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 1639f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen // We save the current configuration -- if we fail to find a solution we will revert 1640f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen // to the initial state. The process of finding a solution modifies the configuration 1641f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen // in place, hence the need for revert in the failure case. 1642f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen currentState.save(); 1643f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 1644f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen // The pushing algorithm is simplified by considering the views in the order in which 1645f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen // they would be pushed by the cluster. For example, if the cluster is leading with its 1646f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen // left edge, we consider sort the views by their right edge, from right to left. 1647f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen cluster.sortConfigurationForEdgePush(whichEdge); 1648f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 1649f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen while (pushDistance > 0 && !fail) { 1650f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen for (View v: currentState.sortedViews) { 1651f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen // For each view that isn't in the cluster, we see if the leading edge of the 1652f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen // cluster is contacting the edge of that view. If so, we add that view to the 1653f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen // cluster. 1654f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (!cluster.views.contains(v) && v != dragView) { 1655f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (cluster.isViewTouchingEdge(v, whichEdge)) { 1656f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen LayoutParams lp = (LayoutParams) v.getLayoutParams(); 1657f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (!lp.canReorder) { 1658f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen // The push solution includes the all apps button, this is not viable. 1659f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen fail = true; 1660f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen break; 1661f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1662f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen cluster.addView(v); 1663f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen CellAndSpan c = currentState.map.get(v); 1664f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 1665f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen // Adding view to cluster, mark it as not occupied. 1666f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, false); 1667f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1668f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1669f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1670f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen pushDistance--; 1671f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 1672f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen // The cluster has been completed, now we move the whole thing over in the appropriate 1673f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen // direction. 1674f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen cluster.shift(whichEdge, 1); 1675e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen } 1676e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen 1677f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen boolean foundSolution = false; 1678f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen clusterRect = cluster.getBoundingRect(); 1679f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 1680f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen // Due to the nature of the algorithm, the only check required to verify a valid solution 1681f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen // is to ensure that completed shifted cluster lies completely within the cell layout. 1682f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (!fail && clusterRect.left >= 0 && clusterRect.right <= mCountX && clusterRect.top >= 0 && 1683f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen clusterRect.bottom <= mCountY) { 1684f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen foundSolution = true; 1685f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } else { 1686f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen currentState.restore(); 1687f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 1688e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen 1689f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen // In either case, we set the occupied array as marked for the location of the views 1690f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen for (View v: cluster.views) { 1691f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen CellAndSpan c = currentState.map.get(v); 1692f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, true); 1693e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen } 1694f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 1695f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen return foundSolution; 1696e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen } 1697e0489500d2a2cf410cb3cb687cbc59e966d7084eAdam Cohen 16988baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen private boolean addViewsToTempLocation(ArrayList<View> views, Rect rectOccupiedByPotentialDrop, 1699f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen int[] direction, View dragView, ItemConfiguration currentState) { 170047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (views.size() == 0) return true; 170147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 170247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean success = false; 170347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen Rect boundingRect = null; 17048baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // We construct a rect which represents the entire group of views passed in 170547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen for (View v: views) { 17068baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = currentState.map.get(v); 170747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (boundingRect == null) { 17088baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen boundingRect = new Rect(c.x, c.y, c.x + c.spanX, c.y + c.spanY); 170947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } else { 17108baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen boundingRect.union(c.x, c.y, c.x + c.spanX, c.y + c.spanY); 171147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 171247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 171347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 17148baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // Mark the occupied state as false for the group of views we want to move. 1715f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen for (View v: views) { 17168baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = currentState.map.get(v); 17178baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, false); 171847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 171947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 172047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen boolean[][] blockOccupied = new boolean[boundingRect.width()][boundingRect.height()]; 172147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen int top = boundingRect.top; 172247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen int left = boundingRect.left; 17238baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // We mark more precisely which parts of the bounding rect are truly occupied, allowing 1724a56dc1077e09faca984a59b861c5dc6364ae2f21Adam Cohen // for interlocking. 1725f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen for (View v: views) { 17268baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = currentState.map.get(v); 17278baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen markCellsForView(c.x - left, c.y - top, c.spanX, c.spanY, blockOccupied, true); 172847a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 172947a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 173047a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen markCellsForRect(rectOccupiedByPotentialDrop, mTmpOccupied, true); 173147a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 1732f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen findNearestArea(boundingRect.left, boundingRect.top, boundingRect.width(), 1733f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen boundingRect.height(), direction, mTmpOccupied, blockOccupied, mTempLocation); 173447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 17358baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // If we successfuly found a location by pushing the block of views, we commit it 173647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen if (mTempLocation[0] >= 0 && mTempLocation[1] >= 0) { 17378baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen int deltaX = mTempLocation[0] - boundingRect.left; 17388baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen int deltaY = mTempLocation[1] - boundingRect.top; 1739f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen for (View v: views) { 17408baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = currentState.map.get(v); 17418baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen c.x += deltaX; 17428baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen c.y += deltaY; 174347a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 174447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen success = true; 174547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 1746482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 17478baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // In either case, we set the occupied array as marked for the location of the views 1748f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen for (View v: views) { 17498baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = currentState.map.get(v); 17508baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, true); 1751482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1752482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return success; 1753482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1754482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1755482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private void markCellsForRect(Rect r, boolean[][] occupied, boolean value) { 1756482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsForView(r.left, r.top, r.width(), r.height(), occupied, value); 1757482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1758482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 17594abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // This method tries to find a reordering solution which satisfies the push mechanic by trying 17604abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // to push items in each of the cardinal directions, in an order based on the direction vector 17614abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // passed. 17624abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen private boolean attemptPushInDirection(ArrayList<View> intersectingViews, Rect occupied, 17634abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen int[] direction, View ignoreView, ItemConfiguration solution) { 17644abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen if ((Math.abs(direction[0]) + Math.abs(direction[1])) > 1) { 17655f8afe6280eae34620067696173e71943e1a30a3Winson Chung // If the direction vector has two non-zero components, we try pushing 17664abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // separately in each of the components. 17674abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen int temp = direction[1]; 17684abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[1] = 0; 1769f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 1770f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (pushViewsToTempLocation(intersectingViews, occupied, direction, 17714abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen ignoreView, solution)) { 17724abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen return true; 17734abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen } 17744abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[1] = temp; 17754abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen temp = direction[0]; 17764abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[0] = 0; 1777f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 1778f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (pushViewsToTempLocation(intersectingViews, occupied, direction, 17794abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen ignoreView, solution)) { 17804abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen return true; 17814abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen } 17824abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // Revert the direction 17834abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[0] = temp; 17844abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen 17854abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // Now we try pushing in each component of the opposite direction 17864abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[0] *= -1; 17874abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[1] *= -1; 17884abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen temp = direction[1]; 17894abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[1] = 0; 1790f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (pushViewsToTempLocation(intersectingViews, occupied, direction, 17914abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen ignoreView, solution)) { 17924abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen return true; 17934abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen } 17944abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen 17954abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[1] = temp; 17964abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen temp = direction[0]; 17974abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[0] = 0; 1798f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (pushViewsToTempLocation(intersectingViews, occupied, direction, 17994abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen ignoreView, solution)) { 18004abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen return true; 18014abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen } 18024abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // revert the direction 18034abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[0] = temp; 18044abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[0] *= -1; 18054abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[1] *= -1; 18065f8afe6280eae34620067696173e71943e1a30a3Winson Chung 18074abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen } else { 18084abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // If the direction vector has a single non-zero component, we push first in the 18094abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // direction of the vector 1810f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (pushViewsToTempLocation(intersectingViews, occupied, direction, 18114abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen ignoreView, solution)) { 18124abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen return true; 18134abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen } 18144abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // Then we try the opposite direction 18154abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[0] *= -1; 18164abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[1] *= -1; 1817f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (pushViewsToTempLocation(intersectingViews, occupied, direction, 18184abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen ignoreView, solution)) { 18194abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen return true; 18204abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen } 18214abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // Switch the direction back 18224abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[0] *= -1; 18234abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[1] *= -1; 18245f8afe6280eae34620067696173e71943e1a30a3Winson Chung 18255f8afe6280eae34620067696173e71943e1a30a3Winson Chung // If we have failed to find a push solution with the above, then we try 18264abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // to find a solution by pushing along the perpendicular axis. 18274abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen 18284abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // Swap the components 18294abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen int temp = direction[1]; 18304abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[1] = direction[0]; 18314abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[0] = temp; 1832f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (pushViewsToTempLocation(intersectingViews, occupied, direction, 18334abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen ignoreView, solution)) { 18344abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen return true; 18354abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen } 18364abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen 18374abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // Then we try the opposite direction 18384abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[0] *= -1; 18394abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[1] *= -1; 1840f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (pushViewsToTempLocation(intersectingViews, occupied, direction, 18414abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen ignoreView, solution)) { 18424abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen return true; 18434abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen } 18444abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // Switch the direction back 18454abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[0] *= -1; 18464abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[1] *= -1; 18474abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen 18484abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // Swap the components back 18494abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen temp = direction[1]; 18504abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[1] = direction[0]; 18514abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen direction[0] = temp; 18524abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen } 18534abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen return false; 18544abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen } 18554abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen 1856482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private boolean rearrangementExists(int cellX, int cellY, int spanX, int spanY, int[] direction, 18578baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen View ignoreView, ItemConfiguration solution) { 1858e3e03bcd313ba8060f2832b6a16dea6fd6d532eaWinson Chung // Return early if get invalid cell positions 1859e3e03bcd313ba8060f2832b6a16dea6fd6d532eaWinson Chung if (cellX < 0 || cellY < 0) return false; 1860482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 18618baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen mIntersectingViews.clear(); 1862482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mOccupiedRect.set(cellX, cellY, cellX + spanX, cellY + spanY); 1863482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 18648baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // Mark the desired location of the view currently being dragged. 1865482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (ignoreView != null) { 18668baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = solution.map.get(ignoreView); 186719f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (c != null) { 186819f3792523fe2d55ea791a9286398a6120920690Adam Cohen c.x = cellX; 186919f3792523fe2d55ea791a9286398a6120920690Adam Cohen c.y = cellY; 187019f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 1871482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1872482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen Rect r0 = new Rect(cellX, cellY, cellX + spanX, cellY + spanY); 1873482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen Rect r1 = new Rect(); 18748baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen for (View child: solution.map.keySet()) { 1875482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (child == ignoreView) continue; 18768baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = solution.map.get(child); 1877482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen LayoutParams lp = (LayoutParams) child.getLayoutParams(); 18788baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen r1.set(c.x, c.y, c.x + c.spanX, c.y + c.spanY); 1879482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (Rect.intersects(r0, r1)) { 1880482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (!lp.canReorder) { 1881482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return false; 1882482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1883482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mIntersectingViews.add(child); 1884482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1885482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 188647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 1887fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen solution.intersectingViews = new ArrayList<View>(mIntersectingViews); 1888fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen 18895f8afe6280eae34620067696173e71943e1a30a3Winson Chung // First we try to find a solution which respects the push mechanic. That is, 18904abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // we try to find a solution such that no displaced item travels through another item 18914abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // without also displacing that item. 18924abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen if (attemptPushInDirection(mIntersectingViews, mOccupiedRect, direction, ignoreView, 189319f3792523fe2d55ea791a9286398a6120920690Adam Cohen solution)) { 189447a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen return true; 189547a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen } 189647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 18974abc5bdfdfc7021d8519c0b7e1bffe0728ff1d9dAdam Cohen // Next we try moving the views as a block, but without requiring the push mechanic. 1898f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen if (addViewsToTempLocation(mIntersectingViews, mOccupiedRect, direction, ignoreView, 189919f3792523fe2d55ea791a9286398a6120920690Adam Cohen solution)) { 1900482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return true; 1901482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 190247a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen 1903482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // Ok, they couldn't move as a block, let's move them individually 1904482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (View v : mIntersectingViews) { 19058baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen if (!addViewToTempLocation(v, mOccupiedRect, direction, solution)) { 1906482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return false; 1907482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1908482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1909482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return true; 1910482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1911482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1912482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen /* 1913482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * Returns a pair (x, y), where x,y are in {-1, 0, 1} corresponding to vector between 1914482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * the provided point and the provided cell 1915482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen */ 191647a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen private void computeDirectionVector(float deltaX, float deltaY, int[] result) { 1917482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen double angle = Math.atan(((float) deltaY) / deltaX); 1918482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1919482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result[0] = 0; 1920482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result[1] = 0; 1921482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (Math.abs(Math.cos(angle)) > 0.5f) { 1922482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result[0] = (int) Math.signum(deltaX); 1923482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1924482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (Math.abs(Math.sin(angle)) > 0.5f) { 1925482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result[1] = (int) Math.signum(deltaY); 1926482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1927482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1928482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 19298baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen private void copyOccupiedArray(boolean[][] occupied) { 19308baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen for (int i = 0; i < mCountX; i++) { 19318baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen for (int j = 0; j < mCountY; j++) { 19328baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen occupied[i][j] = mOccupied[i][j]; 19338baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen } 19348baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen } 19358baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen } 19368baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen 1937f7a29e83f06909b378dba39c83a522375682710aSunny Goyal private ItemConfiguration findReorderSolution(int pixelX, int pixelY, int minSpanX, int minSpanY, 1938fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen int spanX, int spanY, int[] direction, View dragView, boolean decX, 1939fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen ItemConfiguration solution) { 19408baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // Copy the current state into the solution. This solution will be manipulated as necessary. 19418baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen copyCurrentStateToSolution(solution, false); 19428baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // Copy the current occupied array into the temporary occupied array. This array will be 19438baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen // manipulated as necessary to find a solution. 19448baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen copyOccupiedArray(mTmpOccupied); 1945482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1946482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // We find the nearest cell into which we would place the dragged item, assuming there's 1947482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // nothing in its way. 1948482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int result[] = new int[2]; 1949482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result = findNearestArea(pixelX, pixelY, spanX, spanY, result); 1950482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1951482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean success = false; 1952482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // First we try the exact nearest position of the item being dragged, 1953482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // we will then want to try to move this around to other neighbouring positions 19548baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen success = rearrangementExists(result[0], result[1], spanX, spanY, direction, dragView, 19558baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen solution); 1956482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1957482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (!success) { 1958482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // We try shrinking the widget down to size in an alternating pattern, shrink 1 in 1959482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // x, then 1 in y etc. 1960482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (spanX > minSpanX && (minSpanY == spanY || decX)) { 1961fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen return findReorderSolution(pixelX, pixelY, minSpanX, minSpanY, spanX - 1, spanY, 1962fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen direction, dragView, false, solution); 1963482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } else if (spanY > minSpanY) { 1964fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen return findReorderSolution(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY - 1, 1965fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen direction, dragView, true, solution); 1966482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1967482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.isSolution = false; 1968482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } else { 1969482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.isSolution = true; 1970482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewX = result[0]; 1971482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewY = result[1]; 1972482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewSpanX = spanX; 1973482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewSpanY = spanY; 1974482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1975482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return solution; 1976482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1977482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1978482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private void copyCurrentStateToSolution(ItemConfiguration solution, boolean temp) { 1979a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka int childCount = mShortcutsAndWidgets.getChildCount(); 1980482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < childCount; i++) { 1981a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka View child = mShortcutsAndWidgets.getChildAt(i); 1982482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen LayoutParams lp = (LayoutParams) child.getLayoutParams(); 19838baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c; 1984482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (temp) { 19858baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen c = new CellAndSpan(lp.tmpCellX, lp.tmpCellY, lp.cellHSpan, lp.cellVSpan); 1986482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } else { 19878baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen c = new CellAndSpan(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan); 1988482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1989f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen solution.add(child, c); 1990482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1991482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1992482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 1993482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private void copySolutionToTempState(ItemConfiguration solution, View dragView) { 1994482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < mCountX; i++) { 1995482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int j = 0; j < mCountY; j++) { 1996482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mTmpOccupied[i][j] = false; 1997482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1998482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 1999482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2000a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka int childCount = mShortcutsAndWidgets.getChildCount(); 2001482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < childCount; i++) { 2002a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka View child = mShortcutsAndWidgets.getChildAt(i); 2003482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (child == dragView) continue; 2004482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen LayoutParams lp = (LayoutParams) child.getLayoutParams(); 20058baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = solution.map.get(child); 20068baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen if (c != null) { 20078baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen lp.tmpCellX = c.x; 20088baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen lp.tmpCellY = c.y; 20098baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen lp.cellHSpan = c.spanX; 20108baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen lp.cellVSpan = c.spanY; 20118baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen markCellsForView(c.x, c.y, c.spanX, c.spanY, mTmpOccupied, true); 2012482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2013482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2014482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsForView(solution.dragViewX, solution.dragViewY, solution.dragViewSpanX, 2015482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewSpanY, mTmpOccupied, true); 2016482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2017482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2018482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private void animateItemsToSolution(ItemConfiguration solution, View dragView, boolean 2019482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen commitDragView) { 2020482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2021482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean[][] occupied = DESTRUCTIVE_REORDER ? mOccupied : mTmpOccupied; 2022482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < mCountX; i++) { 2023482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int j = 0; j < mCountY; j++) { 2024482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen occupied[i][j] = false; 2025482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2026482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2027482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2028a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka int childCount = mShortcutsAndWidgets.getChildCount(); 2029482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < childCount; i++) { 2030a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka View child = mShortcutsAndWidgets.getChildAt(i); 2031482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (child == dragView) continue; 20328baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen CellAndSpan c = solution.map.get(child); 20338baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen if (c != null) { 203419f3792523fe2d55ea791a9286398a6120920690Adam Cohen animateChildToPosition(child, c.x, c.y, REORDER_ANIMATION_DURATION, 0, 203519f3792523fe2d55ea791a9286398a6120920690Adam Cohen DESTRUCTIVE_REORDER, false); 20368baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen markCellsForView(c.x, c.y, c.spanX, c.spanY, occupied, true); 2037482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2038482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2039482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (commitDragView) { 2040482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsForView(solution.dragViewX, solution.dragViewY, solution.dragViewSpanX, 2041482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewSpanY, occupied, true); 2042482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2043482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2044482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2045fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen 2046fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen // This method starts or changes the reorder preview animations 2047fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen private void beginOrAdjustReorderPreviewAnimations(ItemConfiguration solution, 2048fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen View dragView, int delay, int mode) { 204919f3792523fe2d55ea791a9286398a6120920690Adam Cohen int childCount = mShortcutsAndWidgets.getChildCount(); 205019f3792523fe2d55ea791a9286398a6120920690Adam Cohen for (int i = 0; i < childCount; i++) { 205119f3792523fe2d55ea791a9286398a6120920690Adam Cohen View child = mShortcutsAndWidgets.getChildAt(i); 205219f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (child == dragView) continue; 205319f3792523fe2d55ea791a9286398a6120920690Adam Cohen CellAndSpan c = solution.map.get(child); 2054fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen boolean skip = mode == ReorderPreviewAnimation.MODE_HINT && solution.intersectingViews 2055fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen != null && !solution.intersectingViews.contains(child); 2056fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen 205719f3792523fe2d55ea791a9286398a6120920690Adam Cohen LayoutParams lp = (LayoutParams) child.getLayoutParams(); 2058fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen if (c != null && !skip) { 2059fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen ReorderPreviewAnimation rha = new ReorderPreviewAnimation(child, mode, lp.cellX, 2060fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen lp.cellY, c.x, c.y, c.spanX, c.spanY); 2061d024f9845a0974ab525baad085f316031cd5a742Adam Cohen rha.animate(); 206219f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 206319f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 206419f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 206519f3792523fe2d55ea791a9286398a6120920690Adam Cohen 2066fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen // Class which represents the reorder preview animations. These animations show that an item is 206719f3792523fe2d55ea791a9286398a6120920690Adam Cohen // in a temporary state, and hint at where the item will return to. 2068fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen class ReorderPreviewAnimation { 206919f3792523fe2d55ea791a9286398a6120920690Adam Cohen View child; 2070d024f9845a0974ab525baad085f316031cd5a742Adam Cohen float finalDeltaX; 2071d024f9845a0974ab525baad085f316031cd5a742Adam Cohen float finalDeltaY; 2072d024f9845a0974ab525baad085f316031cd5a742Adam Cohen float initDeltaX; 2073d024f9845a0974ab525baad085f316031cd5a742Adam Cohen float initDeltaY; 2074d024f9845a0974ab525baad085f316031cd5a742Adam Cohen float finalScale; 2075d024f9845a0974ab525baad085f316031cd5a742Adam Cohen float initScale; 2076fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen int mode; 2077fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen boolean repeating = false; 2078fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen private static final int PREVIEW_DURATION = 300; 2079fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen private static final int HINT_DURATION = Workspace.REORDER_TIMEOUT; 2080fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen 2081fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen public static final int MODE_HINT = 0; 2082fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen public static final int MODE_PREVIEW = 1; 2083fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen 2084e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen Animator a; 208519f3792523fe2d55ea791a9286398a6120920690Adam Cohen 2086fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen public ReorderPreviewAnimation(View child, int mode, int cellX0, int cellY0, int cellX1, 2087fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen int cellY1, int spanX, int spanY) { 208819f3792523fe2d55ea791a9286398a6120920690Adam Cohen regionToCenterPoint(cellX0, cellY0, spanX, spanY, mTmpPoint); 208919f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int x0 = mTmpPoint[0]; 209019f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int y0 = mTmpPoint[1]; 209119f3792523fe2d55ea791a9286398a6120920690Adam Cohen regionToCenterPoint(cellX1, cellY1, spanX, spanY, mTmpPoint); 209219f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int x1 = mTmpPoint[0]; 209319f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int y1 = mTmpPoint[1]; 209419f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int dX = x1 - x0; 209519f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int dY = y1 - y0; 2096d024f9845a0974ab525baad085f316031cd5a742Adam Cohen finalDeltaX = 0; 2097d024f9845a0974ab525baad085f316031cd5a742Adam Cohen finalDeltaY = 0; 2098fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen int dir = mode == MODE_HINT ? -1 : 1; 209919f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (dX == dY && dX == 0) { 210019f3792523fe2d55ea791a9286398a6120920690Adam Cohen } else { 210119f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (dY == 0) { 2102fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen finalDeltaX = - dir * Math.signum(dX) * mReorderPreviewAnimationMagnitude; 210319f3792523fe2d55ea791a9286398a6120920690Adam Cohen } else if (dX == 0) { 2104fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen finalDeltaY = - dir * Math.signum(dY) * mReorderPreviewAnimationMagnitude; 210519f3792523fe2d55ea791a9286398a6120920690Adam Cohen } else { 210619f3792523fe2d55ea791a9286398a6120920690Adam Cohen double angle = Math.atan( (float) (dY) / dX); 2107fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen finalDeltaX = (int) (- dir * Math.signum(dX) * 2108fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen Math.abs(Math.cos(angle) * mReorderPreviewAnimationMagnitude)); 2109fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen finalDeltaY = (int) (- dir * Math.signum(dY) * 2110fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen Math.abs(Math.sin(angle) * mReorderPreviewAnimationMagnitude)); 211119f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 211219f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 2113fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen this.mode = mode; 2114d024f9845a0974ab525baad085f316031cd5a742Adam Cohen initDeltaX = child.getTranslationX(); 2115d024f9845a0974ab525baad085f316031cd5a742Adam Cohen initDeltaY = child.getTranslationY(); 2116307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen finalScale = getChildrenScale() - 4.0f / child.getWidth(); 2117d024f9845a0974ab525baad085f316031cd5a742Adam Cohen initScale = child.getScaleX(); 211819f3792523fe2d55ea791a9286398a6120920690Adam Cohen this.child = child; 211919f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 212019f3792523fe2d55ea791a9286398a6120920690Adam Cohen 2121d024f9845a0974ab525baad085f316031cd5a742Adam Cohen void animate() { 212219f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (mShakeAnimators.containsKey(child)) { 2123fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen ReorderPreviewAnimation oldAnimation = mShakeAnimators.get(child); 2124d024f9845a0974ab525baad085f316031cd5a742Adam Cohen oldAnimation.cancel(); 212519f3792523fe2d55ea791a9286398a6120920690Adam Cohen mShakeAnimators.remove(child); 2126e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen if (finalDeltaX == 0 && finalDeltaY == 0) { 2127e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen completeAnimationImmediately(); 2128e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen return; 2129e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen } 213019f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 2131d024f9845a0974ab525baad085f316031cd5a742Adam Cohen if (finalDeltaX == 0 && finalDeltaY == 0) { 213219f3792523fe2d55ea791a9286398a6120920690Adam Cohen return; 213319f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 2134f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka ValueAnimator va = LauncherAnimUtils.ofFloat(child, 0f, 1f); 2135e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen a = va; 213619f3792523fe2d55ea791a9286398a6120920690Adam Cohen va.setRepeatMode(ValueAnimator.REVERSE); 213719f3792523fe2d55ea791a9286398a6120920690Adam Cohen va.setRepeatCount(ValueAnimator.INFINITE); 2138fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen va.setDuration(mode == MODE_HINT ? HINT_DURATION : PREVIEW_DURATION); 2139d024f9845a0974ab525baad085f316031cd5a742Adam Cohen va.setStartDelay((int) (Math.random() * 60)); 214019f3792523fe2d55ea791a9286398a6120920690Adam Cohen va.addUpdateListener(new AnimatorUpdateListener() { 214119f3792523fe2d55ea791a9286398a6120920690Adam Cohen @Override 214219f3792523fe2d55ea791a9286398a6120920690Adam Cohen public void onAnimationUpdate(ValueAnimator animation) { 214319f3792523fe2d55ea791a9286398a6120920690Adam Cohen float r = ((Float) animation.getAnimatedValue()).floatValue(); 2144fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen float r1 = (mode == MODE_HINT && repeating) ? 1.0f : r; 2145fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen float x = r1 * finalDeltaX + (1 - r1) * initDeltaX; 2146fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen float y = r1 * finalDeltaY + (1 - r1) * initDeltaY; 214719f3792523fe2d55ea791a9286398a6120920690Adam Cohen child.setTranslationX(x); 214819f3792523fe2d55ea791a9286398a6120920690Adam Cohen child.setTranslationY(y); 2149d024f9845a0974ab525baad085f316031cd5a742Adam Cohen float s = r * finalScale + (1 - r) * initScale; 215050e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely child.setScaleX(s); 215150e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely child.setScaleY(s); 215219f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 215319f3792523fe2d55ea791a9286398a6120920690Adam Cohen }); 215419f3792523fe2d55ea791a9286398a6120920690Adam Cohen va.addListener(new AnimatorListenerAdapter() { 215519f3792523fe2d55ea791a9286398a6120920690Adam Cohen public void onAnimationRepeat(Animator animation) { 215619f3792523fe2d55ea791a9286398a6120920690Adam Cohen // We make sure to end only after a full period 2157d024f9845a0974ab525baad085f316031cd5a742Adam Cohen initDeltaX = 0; 2158d024f9845a0974ab525baad085f316031cd5a742Adam Cohen initDeltaY = 0; 2159307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen initScale = getChildrenScale(); 2160fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen repeating = true; 216119f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 216219f3792523fe2d55ea791a9286398a6120920690Adam Cohen }); 216319f3792523fe2d55ea791a9286398a6120920690Adam Cohen mShakeAnimators.put(child, this); 216419f3792523fe2d55ea791a9286398a6120920690Adam Cohen va.start(); 216519f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 216619f3792523fe2d55ea791a9286398a6120920690Adam Cohen 2167d024f9845a0974ab525baad085f316031cd5a742Adam Cohen private void cancel() { 2168e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen if (a != null) { 2169e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen a.cancel(); 2170e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen } 217119f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 2172e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen 2173091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen @Thunk void completeAnimationImmediately() { 2174e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen if (a != null) { 2175e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen a.cancel(); 2176e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen } 217750e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely 21782ecf995e0d2d55eb71d03f7230ca87270872d1a3Michael Jurka AnimatorSet s = LauncherAnimUtils.createAnimatorSet(); 2179e7587d2f23f3ab9e133b40cd7fed4b030609f252Adam Cohen a = s; 218050e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely s.playTogether( 2181307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen LauncherAnimUtils.ofFloat(child, "scaleX", getChildrenScale()), 2182307fe23f125cbbd5512ad8d4660025f2ab68f30bAdam Cohen LauncherAnimUtils.ofFloat(child, "scaleY", getChildrenScale()), 21832ecf995e0d2d55eb71d03f7230ca87270872d1a3Michael Jurka LauncherAnimUtils.ofFloat(child, "translationX", 0f), 21842ecf995e0d2d55eb71d03f7230ca87270872d1a3Michael Jurka LauncherAnimUtils.ofFloat(child, "translationY", 0f) 218550e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely ); 218650e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely s.setDuration(REORDER_ANIMATION_DURATION); 218750e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely s.setInterpolator(new android.view.animation.DecelerateInterpolator(1.5f)); 218850e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely s.start(); 218950e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely } 219019f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 219119f3792523fe2d55ea791a9286398a6120920690Adam Cohen 2192fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen private void completeAndClearReorderPreviewAnimations() { 2193fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen for (ReorderPreviewAnimation a: mShakeAnimators.values()) { 219450e6e565bcf1f51023c2a14d31b17c8a550aac84Brandon Keely a.completeAnimationImmediately(); 219519f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 219619f3792523fe2d55ea791a9286398a6120920690Adam Cohen mShakeAnimators.clear(); 219719f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 219819f3792523fe2d55ea791a9286398a6120920690Adam Cohen 2199482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private void commitTempPlacement() { 2200482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < mCountX; i++) { 2201482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int j = 0; j < mCountY; j++) { 2202482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen mOccupied[i][j] = mTmpOccupied[i][j]; 2203482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2204482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2205a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka int childCount = mShortcutsAndWidgets.getChildCount(); 2206482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < childCount; i++) { 2207ea889a294be004f4b1c21e9b874f9e63abfb8bd6Adam Cohen View child = mShortcutsAndWidgets.getChildAt(i); 2208ea889a294be004f4b1c21e9b874f9e63abfb8bd6Adam Cohen LayoutParams lp = (LayoutParams) child.getLayoutParams(); 2209ea889a294be004f4b1c21e9b874f9e63abfb8bd6Adam Cohen ItemInfo info = (ItemInfo) child.getTag(); 22102acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen // We do a null check here because the item info can be null in the case of the 22112acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen // AllApps button in the hotseat. 22122acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen if (info != null) { 2213487f7dd3059621527eb439d7d51d34e00293f9b1Adam Cohen if (info.cellX != lp.tmpCellX || info.cellY != lp.tmpCellY || 2214487f7dd3059621527eb439d7d51d34e00293f9b1Adam Cohen info.spanX != lp.cellHSpan || info.spanY != lp.cellVSpan) { 2215487f7dd3059621527eb439d7d51d34e00293f9b1Adam Cohen info.requiresDbUpdate = true; 2216487f7dd3059621527eb439d7d51d34e00293f9b1Adam Cohen } 22172acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen info.cellX = lp.cellX = lp.tmpCellX; 22182acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen info.cellY = lp.cellY = lp.tmpCellY; 2219bebf042666cffe52039b875a549a582abd78a431Adam Cohen info.spanX = lp.cellHSpan; 2220bebf042666cffe52039b875a549a582abd78a431Adam Cohen info.spanY = lp.cellVSpan; 22212acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen } 2222482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 22232acce88b5fa316e7a314109f9957ad233a6c31a6Adam Cohen mLauncher.getWorkspace().updateItemLocationsInDatabase(this); 2224482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2225482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2226f7a29e83f06909b378dba39c83a522375682710aSunny Goyal private void setUseTempCoords(boolean useTempCoords) { 2227a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka int childCount = mShortcutsAndWidgets.getChildCount(); 2228482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen for (int i = 0; i < childCount; i++) { 2229a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka LayoutParams lp = (LayoutParams) mShortcutsAndWidgets.getChildAt(i).getLayoutParams(); 2230482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen lp.useTmpCoords = useTempCoords; 2231482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2232482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2233482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2234f7a29e83f06909b378dba39c83a522375682710aSunny Goyal private ItemConfiguration findConfigurationNoShuffle(int pixelX, int pixelY, int minSpanX, int minSpanY, 2235482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int spanX, int spanY, View dragView, ItemConfiguration solution) { 2236482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int[] result = new int[2]; 2237482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int[] resultSpan = new int[2]; 2238f7a29e83f06909b378dba39c83a522375682710aSunny Goyal findNearestVacantArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, result, 2239482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen resultSpan); 2240482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (result[0] >= 0 && result[1] >= 0) { 2241482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen copyCurrentStateToSolution(solution, false); 2242482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewX = result[0]; 2243482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewY = result[1]; 2244482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewSpanX = resultSpan[0]; 2245482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.dragViewSpanY = resultSpan[1]; 2246482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.isSolution = true; 2247482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } else { 2248482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen solution.isSolution = false; 2249482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2250482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return solution; 2251482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2252482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2253482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public void prepareChildForDrag(View child) { 2254482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen markCellsAsUnoccupiedForView(child); 2255482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2256482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 225719f3792523fe2d55ea791a9286398a6120920690Adam Cohen /* This seems like it should be obvious and straight-forward, but when the direction vector 225819f3792523fe2d55ea791a9286398a6120920690Adam Cohen needs to match with the notion of the dragView pushing other views, we have to employ 225919f3792523fe2d55ea791a9286398a6120920690Adam Cohen a slightly more subtle notion of the direction vector. The question is what two points is 226019f3792523fe2d55ea791a9286398a6120920690Adam Cohen the vector between? The center of the dragView and its desired destination? Not quite, as 226119f3792523fe2d55ea791a9286398a6120920690Adam Cohen this doesn't necessarily coincide with the interaction of the dragView and items occupying 226219f3792523fe2d55ea791a9286398a6120920690Adam Cohen those cells. Instead we use some heuristics to often lock the vector to up, down, left 226319f3792523fe2d55ea791a9286398a6120920690Adam Cohen or right, which helps make pushing feel right. 226419f3792523fe2d55ea791a9286398a6120920690Adam Cohen */ 226519f3792523fe2d55ea791a9286398a6120920690Adam Cohen private void getDirectionVectorForDrop(int dragViewCenterX, int dragViewCenterY, int spanX, 226619f3792523fe2d55ea791a9286398a6120920690Adam Cohen int spanY, View dragView, int[] resultDirection) { 226719f3792523fe2d55ea791a9286398a6120920690Adam Cohen int[] targetDestination = new int[2]; 226819f3792523fe2d55ea791a9286398a6120920690Adam Cohen 226919f3792523fe2d55ea791a9286398a6120920690Adam Cohen findNearestArea(dragViewCenterX, dragViewCenterY, spanX, spanY, targetDestination); 227019f3792523fe2d55ea791a9286398a6120920690Adam Cohen Rect dragRect = new Rect(); 227119f3792523fe2d55ea791a9286398a6120920690Adam Cohen regionToRect(targetDestination[0], targetDestination[1], spanX, spanY, dragRect); 227219f3792523fe2d55ea791a9286398a6120920690Adam Cohen dragRect.offset(dragViewCenterX - dragRect.centerX(), dragViewCenterY - dragRect.centerY()); 227319f3792523fe2d55ea791a9286398a6120920690Adam Cohen 227419f3792523fe2d55ea791a9286398a6120920690Adam Cohen Rect dropRegionRect = new Rect(); 227519f3792523fe2d55ea791a9286398a6120920690Adam Cohen getViewsIntersectingRegion(targetDestination[0], targetDestination[1], spanX, spanY, 227619f3792523fe2d55ea791a9286398a6120920690Adam Cohen dragView, dropRegionRect, mIntersectingViews); 227719f3792523fe2d55ea791a9286398a6120920690Adam Cohen 227819f3792523fe2d55ea791a9286398a6120920690Adam Cohen int dropRegionSpanX = dropRegionRect.width(); 227919f3792523fe2d55ea791a9286398a6120920690Adam Cohen int dropRegionSpanY = dropRegionRect.height(); 228019f3792523fe2d55ea791a9286398a6120920690Adam Cohen 228119f3792523fe2d55ea791a9286398a6120920690Adam Cohen regionToRect(dropRegionRect.left, dropRegionRect.top, dropRegionRect.width(), 228219f3792523fe2d55ea791a9286398a6120920690Adam Cohen dropRegionRect.height(), dropRegionRect); 228319f3792523fe2d55ea791a9286398a6120920690Adam Cohen 228419f3792523fe2d55ea791a9286398a6120920690Adam Cohen int deltaX = (dropRegionRect.centerX() - dragViewCenterX) / spanX; 228519f3792523fe2d55ea791a9286398a6120920690Adam Cohen int deltaY = (dropRegionRect.centerY() - dragViewCenterY) / spanY; 228619f3792523fe2d55ea791a9286398a6120920690Adam Cohen 228719f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (dropRegionSpanX == mCountX || spanX == mCountX) { 228819f3792523fe2d55ea791a9286398a6120920690Adam Cohen deltaX = 0; 228919f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 229019f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (dropRegionSpanY == mCountY || spanY == mCountY) { 229119f3792523fe2d55ea791a9286398a6120920690Adam Cohen deltaY = 0; 229219f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 229319f3792523fe2d55ea791a9286398a6120920690Adam Cohen 229419f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (deltaX == 0 && deltaY == 0) { 229519f3792523fe2d55ea791a9286398a6120920690Adam Cohen // No idea what to do, give a random direction. 229619f3792523fe2d55ea791a9286398a6120920690Adam Cohen resultDirection[0] = 1; 229719f3792523fe2d55ea791a9286398a6120920690Adam Cohen resultDirection[1] = 0; 229819f3792523fe2d55ea791a9286398a6120920690Adam Cohen } else { 229919f3792523fe2d55ea791a9286398a6120920690Adam Cohen computeDirectionVector(deltaX, deltaY, resultDirection); 230019f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 230119f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 230219f3792523fe2d55ea791a9286398a6120920690Adam Cohen 230319f3792523fe2d55ea791a9286398a6120920690Adam Cohen // For a given cell and span, fetch the set of views intersecting the region. 230419f3792523fe2d55ea791a9286398a6120920690Adam Cohen private void getViewsIntersectingRegion(int cellX, int cellY, int spanX, int spanY, 230519f3792523fe2d55ea791a9286398a6120920690Adam Cohen View dragView, Rect boundingRect, ArrayList<View> intersectingViews) { 230619f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (boundingRect != null) { 230719f3792523fe2d55ea791a9286398a6120920690Adam Cohen boundingRect.set(cellX, cellY, cellX + spanX, cellY + spanY); 230819f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 230919f3792523fe2d55ea791a9286398a6120920690Adam Cohen intersectingViews.clear(); 231019f3792523fe2d55ea791a9286398a6120920690Adam Cohen Rect r0 = new Rect(cellX, cellY, cellX + spanX, cellY + spanY); 231119f3792523fe2d55ea791a9286398a6120920690Adam Cohen Rect r1 = new Rect(); 231219f3792523fe2d55ea791a9286398a6120920690Adam Cohen final int count = mShortcutsAndWidgets.getChildCount(); 231319f3792523fe2d55ea791a9286398a6120920690Adam Cohen for (int i = 0; i < count; i++) { 231419f3792523fe2d55ea791a9286398a6120920690Adam Cohen View child = mShortcutsAndWidgets.getChildAt(i); 231519f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (child == dragView) continue; 231619f3792523fe2d55ea791a9286398a6120920690Adam Cohen LayoutParams lp = (LayoutParams) child.getLayoutParams(); 231719f3792523fe2d55ea791a9286398a6120920690Adam Cohen r1.set(lp.cellX, lp.cellY, lp.cellX + lp.cellHSpan, lp.cellY + lp.cellVSpan); 231819f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (Rect.intersects(r0, r1)) { 231919f3792523fe2d55ea791a9286398a6120920690Adam Cohen mIntersectingViews.add(child); 232019f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (boundingRect != null) { 232119f3792523fe2d55ea791a9286398a6120920690Adam Cohen boundingRect.union(r1); 232219f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 232319f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 232419f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 232519f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 232619f3792523fe2d55ea791a9286398a6120920690Adam Cohen 232719f3792523fe2d55ea791a9286398a6120920690Adam Cohen boolean isNearestDropLocationOccupied(int pixelX, int pixelY, int spanX, int spanY, 232819f3792523fe2d55ea791a9286398a6120920690Adam Cohen View dragView, int[] result) { 232919f3792523fe2d55ea791a9286398a6120920690Adam Cohen result = findNearestArea(pixelX, pixelY, spanX, spanY, result); 233019f3792523fe2d55ea791a9286398a6120920690Adam Cohen getViewsIntersectingRegion(result[0], result[1], spanX, spanY, dragView, null, 233119f3792523fe2d55ea791a9286398a6120920690Adam Cohen mIntersectingViews); 233219f3792523fe2d55ea791a9286398a6120920690Adam Cohen return !mIntersectingViews.isEmpty(); 233319f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 233419f3792523fe2d55ea791a9286398a6120920690Adam Cohen 233519f3792523fe2d55ea791a9286398a6120920690Adam Cohen void revertTempState() { 2336fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen completeAndClearReorderPreviewAnimations(); 2337fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen if (isItemPlacementDirty() && !DESTRUCTIVE_REORDER) { 2338fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen final int count = mShortcutsAndWidgets.getChildCount(); 2339fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen for (int i = 0; i < count; i++) { 2340fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen View child = mShortcutsAndWidgets.getChildAt(i); 2341fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen LayoutParams lp = (LayoutParams) child.getLayoutParams(); 2342fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen if (lp.tmpCellX != lp.cellX || lp.tmpCellY != lp.cellY) { 2343fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen lp.tmpCellX = lp.cellX; 2344fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen lp.tmpCellY = lp.cellY; 2345fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen animateChildToPosition(child, lp.cellX, lp.cellY, REORDER_ANIMATION_DURATION, 2346fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen 0, false, false); 2347fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen } 234819f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 2349fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen setItemPlacementDirty(false); 235019f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 235119f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 235219f3792523fe2d55ea791a9286398a6120920690Adam Cohen 2353bebf042666cffe52039b875a549a582abd78a431Adam Cohen boolean createAreaForResize(int cellX, int cellY, int spanX, int spanY, 2354bebf042666cffe52039b875a549a582abd78a431Adam Cohen View dragView, int[] direction, boolean commit) { 2355bebf042666cffe52039b875a549a582abd78a431Adam Cohen int[] pixelXY = new int[2]; 2356bebf042666cffe52039b875a549a582abd78a431Adam Cohen regionToCenterPoint(cellX, cellY, spanX, spanY, pixelXY); 2357bebf042666cffe52039b875a549a582abd78a431Adam Cohen 2358bebf042666cffe52039b875a549a582abd78a431Adam Cohen // First we determine if things have moved enough to cause a different layout 2359fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen ItemConfiguration swapSolution = findReorderSolution(pixelXY[0], pixelXY[1], spanX, spanY, 2360bebf042666cffe52039b875a549a582abd78a431Adam Cohen spanX, spanY, direction, dragView, true, new ItemConfiguration()); 2361bebf042666cffe52039b875a549a582abd78a431Adam Cohen 2362bebf042666cffe52039b875a549a582abd78a431Adam Cohen setUseTempCoords(true); 2363bebf042666cffe52039b875a549a582abd78a431Adam Cohen if (swapSolution != null && swapSolution.isSolution) { 2364bebf042666cffe52039b875a549a582abd78a431Adam Cohen // If we're just testing for a possible location (MODE_ACCEPT_DROP), we don't bother 2365bebf042666cffe52039b875a549a582abd78a431Adam Cohen // committing anything or animating anything as we just want to determine if a solution 2366bebf042666cffe52039b875a549a582abd78a431Adam Cohen // exists 2367bebf042666cffe52039b875a549a582abd78a431Adam Cohen copySolutionToTempState(swapSolution, dragView); 2368bebf042666cffe52039b875a549a582abd78a431Adam Cohen setItemPlacementDirty(true); 2369bebf042666cffe52039b875a549a582abd78a431Adam Cohen animateItemsToSolution(swapSolution, dragView, commit); 2370bebf042666cffe52039b875a549a582abd78a431Adam Cohen 2371bebf042666cffe52039b875a549a582abd78a431Adam Cohen if (commit) { 2372bebf042666cffe52039b875a549a582abd78a431Adam Cohen commitTempPlacement(); 2373fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen completeAndClearReorderPreviewAnimations(); 2374bebf042666cffe52039b875a549a582abd78a431Adam Cohen setItemPlacementDirty(false); 2375bebf042666cffe52039b875a549a582abd78a431Adam Cohen } else { 2376fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen beginOrAdjustReorderPreviewAnimations(swapSolution, dragView, 2377fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen REORDER_ANIMATION_DURATION, ReorderPreviewAnimation.MODE_PREVIEW); 2378bebf042666cffe52039b875a549a582abd78a431Adam Cohen } 2379bebf042666cffe52039b875a549a582abd78a431Adam Cohen mShortcutsAndWidgets.requestLayout(); 2380bebf042666cffe52039b875a549a582abd78a431Adam Cohen } 2381bebf042666cffe52039b875a549a582abd78a431Adam Cohen return swapSolution.isSolution; 2382bebf042666cffe52039b875a549a582abd78a431Adam Cohen } 2383bebf042666cffe52039b875a549a582abd78a431Adam Cohen 2384fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen int[] performReorder(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, int spanY, 2385482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen View dragView, int[] result, int resultSpan[], int mode) { 2386482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // First we determine if things have moved enough to cause a different layout 238747a876d443ddc65c8d9a0c95da58d892dbb1faeaAdam Cohen result = findNearestArea(pixelX, pixelY, spanX, spanY, result); 2388482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2389482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (resultSpan == null) { 2390482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen resultSpan = new int[2]; 2391482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2392482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 239319f3792523fe2d55ea791a9286398a6120920690Adam Cohen // When we are checking drop validity or actually dropping, we don't recompute the 239419f3792523fe2d55ea791a9286398a6120920690Adam Cohen // direction vector, since we want the solution to match the preview, and it's possible 239519f3792523fe2d55ea791a9286398a6120920690Adam Cohen // that the exact position of the item has changed to result in a new reordering outcome. 2396b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen if ((mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL || mode == MODE_ACCEPT_DROP) 2397b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen && mPreviousReorderDirection[0] != INVALID_DIRECTION) { 239819f3792523fe2d55ea791a9286398a6120920690Adam Cohen mDirectionVector[0] = mPreviousReorderDirection[0]; 239919f3792523fe2d55ea791a9286398a6120920690Adam Cohen mDirectionVector[1] = mPreviousReorderDirection[1]; 240019f3792523fe2d55ea791a9286398a6120920690Adam Cohen // We reset this vector after drop 2401b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen if (mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL) { 2402b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen mPreviousReorderDirection[0] = INVALID_DIRECTION; 2403b209e634a29a0cb5514fafb4e5882ea49ba1cfa7Adam Cohen mPreviousReorderDirection[1] = INVALID_DIRECTION; 240419f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 240519f3792523fe2d55ea791a9286398a6120920690Adam Cohen } else { 240619f3792523fe2d55ea791a9286398a6120920690Adam Cohen getDirectionVectorForDrop(pixelX, pixelY, spanX, spanY, dragView, mDirectionVector); 240719f3792523fe2d55ea791a9286398a6120920690Adam Cohen mPreviousReorderDirection[0] = mDirectionVector[0]; 240819f3792523fe2d55ea791a9286398a6120920690Adam Cohen mPreviousReorderDirection[1] = mDirectionVector[1]; 240919f3792523fe2d55ea791a9286398a6120920690Adam Cohen } 241019f3792523fe2d55ea791a9286398a6120920690Adam Cohen 2411fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen // Find a solution involving pushing / displacing any items in the way 2412fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen ItemConfiguration swapSolution = findReorderSolution(pixelX, pixelY, minSpanX, minSpanY, 2413482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen spanX, spanY, mDirectionVector, dragView, true, new ItemConfiguration()); 2414482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2415482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // We attempt the approach which doesn't shuffle views at all 2416482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen ItemConfiguration noShuffleSolution = findConfigurationNoShuffle(pixelX, pixelY, minSpanX, 2417482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen minSpanY, spanX, spanY, dragView, new ItemConfiguration()); 2418482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2419482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen ItemConfiguration finalSolution = null; 2420fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen 2421fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen // If the reorder solution requires resizing (shrinking) the item being dropped, we instead 2422fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen // favor a solution in which the item is not resized, but 2423482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (swapSolution.isSolution && swapSolution.area() >= noShuffleSolution.area()) { 2424482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen finalSolution = swapSolution; 2425482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } else if (noShuffleSolution.isSolution) { 2426482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen finalSolution = noShuffleSolution; 2427482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2428482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2429fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen if (mode == MODE_SHOW_REORDER_HINT) { 2430fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen if (finalSolution != null) { 2431fe69287b97d16c8941ab9463e4868fca45ad8152Adam Cohen beginOrAdjustReorderPreviewAnimations(finalSolution, dragView, 0, 2432fe69287b97d16c8941ab9463e4868fca45ad8152Adam Cohen ReorderPreviewAnimation.MODE_HINT); 2433fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen result[0] = finalSolution.dragViewX; 2434fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen result[1] = finalSolution.dragViewY; 2435fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen resultSpan[0] = finalSolution.dragViewSpanX; 2436fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen resultSpan[1] = finalSolution.dragViewSpanY; 2437fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen } else { 2438fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen result[0] = result[1] = resultSpan[0] = resultSpan[1] = -1; 2439fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen } 2440fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen return result; 2441fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen } 2442fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen 2443482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean foundSolution = true; 2444482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (!DESTRUCTIVE_REORDER) { 2445482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen setUseTempCoords(true); 2446482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2447482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2448482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (finalSolution != null) { 2449482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result[0] = finalSolution.dragViewX; 2450482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result[1] = finalSolution.dragViewY; 2451482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen resultSpan[0] = finalSolution.dragViewSpanX; 2452482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen resultSpan[1] = finalSolution.dragViewSpanY; 2453482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2454482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // If we're just testing for a possible location (MODE_ACCEPT_DROP), we don't bother 2455482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // committing anything or animating anything as we just want to determine if a solution 2456482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen // exists 2457482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (mode == MODE_DRAG_OVER || mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL) { 2458482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (!DESTRUCTIVE_REORDER) { 2459482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen copySolutionToTempState(finalSolution, dragView); 2460482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2461482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen setItemPlacementDirty(true); 2462482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen animateItemsToSolution(finalSolution, dragView, mode == MODE_ON_DROP); 2463482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 246419f3792523fe2d55ea791a9286398a6120920690Adam Cohen if (!DESTRUCTIVE_REORDER && 246519f3792523fe2d55ea791a9286398a6120920690Adam Cohen (mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL)) { 2466482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen commitTempPlacement(); 2467fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen completeAndClearReorderPreviewAnimations(); 246819f3792523fe2d55ea791a9286398a6120920690Adam Cohen setItemPlacementDirty(false); 246919f3792523fe2d55ea791a9286398a6120920690Adam Cohen } else { 2470fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen beginOrAdjustReorderPreviewAnimations(finalSolution, dragView, 2471fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen REORDER_ANIMATION_DURATION, ReorderPreviewAnimation.MODE_PREVIEW); 2472482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2473482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2474482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } else { 2475482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen foundSolution = false; 2476482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen result[0] = result[1] = resultSpan[0] = resultSpan[1] = -1; 2477482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2478482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2479482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if ((mode == MODE_ON_DROP || !foundSolution) && !DESTRUCTIVE_REORDER) { 2480482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen setUseTempCoords(false); 2481482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2482482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2483a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka mShortcutsAndWidgets.requestLayout(); 2484482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return result; 2485482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2486482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 248719f3792523fe2d55ea791a9286398a6120920690Adam Cohen void setItemPlacementDirty(boolean dirty) { 248819f3792523fe2d55ea791a9286398a6120920690Adam Cohen mItemPlacementDirty = dirty; 2489482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 249019f3792523fe2d55ea791a9286398a6120920690Adam Cohen boolean isItemPlacementDirty() { 249119f3792523fe2d55ea791a9286398a6120920690Adam Cohen return mItemPlacementDirty; 2492482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2493482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2494091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen @Thunk class ItemConfiguration { 24958baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen HashMap<View, CellAndSpan> map = new HashMap<View, CellAndSpan>(); 2496f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen private HashMap<View, CellAndSpan> savedMap = new HashMap<View, CellAndSpan>(); 2497f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen ArrayList<View> sortedViews = new ArrayList<View>(); 2498fa3c58f647e603760c0bd929166c0edee25675a9Adam Cohen ArrayList<View> intersectingViews; 2499482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean isSolution = false; 2500482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int dragViewX, dragViewY, dragViewSpanX, dragViewSpanY; 2501482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2502f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen void save() { 2503f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen // Copy current state into savedMap 2504f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen for (View v: map.keySet()) { 2505f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen map.get(v).copy(savedMap.get(v)); 2506f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 2507f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 2508f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 2509f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen void restore() { 2510f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen // Restore current state from savedMap 2511f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen for (View v: savedMap.keySet()) { 2512f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen savedMap.get(v).copy(map.get(v)); 2513f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 2514f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 2515f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 2516f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen void add(View v, CellAndSpan cs) { 2517f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen map.put(v, cs); 2518f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen savedMap.put(v, new CellAndSpan()); 2519f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen sortedViews.add(v); 2520f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 2521f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 2522482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen int area() { 2523482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen return dragViewSpanX * dragViewSpanY; 2524482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 25258baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen } 25268baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen 25278baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen private class CellAndSpan { 25288baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen int x, y; 25298baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen int spanX, spanY; 25308baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen 2531f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen public CellAndSpan() { 2532f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 2533f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 2534f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen public void copy(CellAndSpan copy) { 2535f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen copy.x = x; 2536f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen copy.y = y; 2537f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen copy.spanX = spanX; 2538f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen copy.spanY = spanY; 2539f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 2540f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 25418baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen public CellAndSpan(int x, int y, int spanX, int spanY) { 25428baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen this.x = x; 25438baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen this.y = y; 25448baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen this.spanX = spanX; 25458baab35b000d2dec9b33ea6a67988b6f0185b27eAdam Cohen this.spanY = spanY; 2546482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2547f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 2548f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen public String toString() { 2549f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen return "(" + x + ", " + y + ": " + spanX + ", " + spanY + ")"; 2550f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen } 2551f3900c287cd92f61863cbecab87d5513e48b7b09Adam Cohen 2552482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen } 2553482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2554df0353815c629fc678824b07a234b89a1ff94208Adam Cohen /** 2555df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * Find a starting cell position that will fit the given bounds nearest the requested 2556df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * cell location. Uses Euclidean distance to score multiple vacant areas. 2557df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * 2558df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param pixelX The X location at which you want to search for a vacant area. 2559df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param pixelY The Y location at which you want to search for a vacant area. 2560df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param spanX Horizontal span of the object. 2561df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param spanY Vertical span of the object. 2562df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param ignoreView Considers space occupied by this view as unoccupied 2563df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @param result Previously returned value to possibly recycle. 2564df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * @return The X, Y cell of a vacant area that can contain this object, 2565df0353815c629fc678824b07a234b89a1ff94208Adam Cohen * nearest the requested location. 2566df0353815c629fc678824b07a234b89a1ff94208Adam Cohen */ 2567f7a29e83f06909b378dba39c83a522375682710aSunny Goyal int[] findNearestArea(int pixelX, int pixelY, int spanX, int spanY, int[] result) { 2568f7a29e83f06909b378dba39c83a522375682710aSunny Goyal return findNearestArea(pixelX, pixelY, spanX, spanY, spanX, spanY, false, result, null); 2569df0353815c629fc678824b07a234b89a1ff94208Adam Cohen } 2570df0353815c629fc678824b07a234b89a1ff94208Adam Cohen 25710280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka boolean existsEmptyCell() { 25720280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka return findCellForSpan(null, 1, 1); 25730280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 25740280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 25750280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka /** 25760280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * Finds the upper-left coordinate of the first rectangle in the grid that can 25770280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * hold a cell of the specified dimensions. If intersectX and intersectY are not -1, 25780280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * then this method will only return coordinates for rectangles that contain the cell 25790280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * (intersectX, intersectY) 25800280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * 25810280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param cellXY The array that will contain the position of a vacant cell if such a cell 25820280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * can be found. 25830280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param spanX The horizontal span of the cell we want to find. 25840280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @param spanY The vertical span of the cell we want to find. 25850280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * 25860280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * @return True if a vacant cell of the specified dimension was found, false otherwise. 25870280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka */ 25883f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song public boolean findCellForSpan(int[] cellXY, int spanX, int spanY) { 258928750fba6a2d141eb9a1e566718c17236030b815Michael Jurka boolean foundCell = false; 2590f7a29e83f06909b378dba39c83a522375682710aSunny Goyal final int endX = mCountX - (spanX - 1); 2591f7a29e83f06909b378dba39c83a522375682710aSunny Goyal final int endY = mCountY - (spanY - 1); 2592f7a29e83f06909b378dba39c83a522375682710aSunny Goyal 2593f7a29e83f06909b378dba39c83a522375682710aSunny Goyal for (int y = 0; y < endY && !foundCell; y++) { 2594f7a29e83f06909b378dba39c83a522375682710aSunny Goyal inner: 2595f7a29e83f06909b378dba39c83a522375682710aSunny Goyal for (int x = 0; x < endX; x++) { 2596f7a29e83f06909b378dba39c83a522375682710aSunny Goyal for (int i = 0; i < spanX; i++) { 2597f7a29e83f06909b378dba39c83a522375682710aSunny Goyal for (int j = 0; j < spanY; j++) { 2598f7a29e83f06909b378dba39c83a522375682710aSunny Goyal if (mOccupied[x + i][y + j]) { 2599f7a29e83f06909b378dba39c83a522375682710aSunny Goyal // small optimization: we can skip to after the column we just found 2600f7a29e83f06909b378dba39c83a522375682710aSunny Goyal // an occupied cell 2601f7a29e83f06909b378dba39c83a522375682710aSunny Goyal x += i; 2602f7a29e83f06909b378dba39c83a522375682710aSunny Goyal continue inner; 26030280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 26040280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 26050280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 2606f7a29e83f06909b378dba39c83a522375682710aSunny Goyal if (cellXY != null) { 2607f7a29e83f06909b378dba39c83a522375682710aSunny Goyal cellXY[0] = x; 2608f7a29e83f06909b378dba39c83a522375682710aSunny Goyal cellXY[1] = y; 2609f7a29e83f06909b378dba39c83a522375682710aSunny Goyal } 2610f7a29e83f06909b378dba39c83a522375682710aSunny Goyal foundCell = true; 26110280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka break; 26120280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 26130280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 26140280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 261528750fba6a2d141eb9a1e566718c17236030b815Michael Jurka return foundCell; 26160280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 26170280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 261831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 2619c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung * A drag event has begun over this layout. 2620c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung * It may have begun over this layout (in which case onDragChild is called first), 2621c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung * or it may have begun on another layout. 2622c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung */ 2623c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung void onDragEnter() { 2624c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung mDragging = true; 2625c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung } 2626c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung 2627c07918d0053fc7d2a19d7b013565a5d2e7d4af51Winson Chung /** 26280280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka * Called when drag has left this CellLayout or has been completed (successfully or not) 26296569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy */ 26300280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka void onDragExit() { 26314be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // This can actually be called when we aren't in a drag, e.g. when adding a new 26324be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // item to this layout via the customize drawer. 26334be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato // Guard against that case. 26344be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato if (mDragging) { 26354be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato mDragging = false; 26364be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato } 263708ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy 263808ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy // Invalidate the drag data 2639d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen mDragCell[0] = mDragCell[1] = -1; 264008ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy mDragOutlineAnims[mDragOutlineCurrent].animateOut(); 264108ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy mDragOutlineCurrent = (mDragOutlineCurrent + 1) % mDragOutlineAnims.length; 264219f3792523fe2d55ea791a9286398a6120920690Adam Cohen revertTempState(); 264333945b21544bc98381df17726a3537c292d8c985Michael Jurka setIsDragOverlapping(false); 26446569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy } 26456569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy 26466569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy /** 2647aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * Mark a child as having been dropped. 2648de7658b5e02ae10010e44fcf8d9c5814f54d9eb0Patrick Dubroy * At the beginning of the drag operation, the child may have been on another 2649ce34a9768b01115def95f000a6a8f35870f10d3aPatrick Dubroy * screen, but it is re-parented before this method is called. 265031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 265131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param child The child that is being dropped 265231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 2653716b51e030f9c6ed34af2b947760e46a280c65a6Adam Cohen void onDropChild(View child) { 2654d94533d04a5f8f5485f106d10af60169857ea899Romain Guy if (child != null) { 2655d94533d04a5f8f5485f106d10af60169857ea899Romain Guy LayoutParams lp = (LayoutParams) child.getLayoutParams(); 265684f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy lp.dropped = true; 2657d94533d04a5f8f5485f106d10af60169857ea899Romain Guy child.requestLayout(); 2658d94533d04a5f8f5485f106d10af60169857ea899Romain Guy } 265931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 266031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 266131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 266231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Computes a bounding rectangle for a range of cells 2663aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * 266431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param cellX X coordinate of upper left corner expressed as a cell position 266531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param cellY Y coordinate of upper left corner expressed as a cell position 2666aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung * @param cellHSpan Width in cells 266731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param cellVSpan Height in cells 26686569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy * @param resultRect Rect into which to put the results 266931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 2670d41fbf5680750e34335bba6b38298186c144a4b7Adam Cohen public void cellToRect(int cellX, int cellY, int cellHSpan, int cellVSpan, Rect resultRect) { 267131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int cellWidth = mCellWidth; 267231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int cellHeight = mCellHeight; 267331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int widthGap = mWidthGap; 267431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int heightGap = mHeightGap; 2675aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 26764b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung final int hStartPadding = getPaddingLeft(); 26774b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung final int vStartPadding = getPaddingTop(); 2678aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 267931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int width = cellHSpan * cellWidth + ((cellHSpan - 1) * widthGap); 268031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int height = cellVSpan * cellHeight + ((cellVSpan - 1) * heightGap); 268131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 268231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int x = hStartPadding + cellX * (cellWidth + widthGap); 268331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int y = vStartPadding + cellY * (cellHeight + heightGap); 2684aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 26856569f2c80e179c2f8ed73dae6b01d971ec20f005Patrick Dubroy resultRect.set(x, y, x + width, y + height); 268631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 2687aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 26880280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka private void clearOccupiedCells() { 26890280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka for (int x = 0; x < mCountX; x++) { 26900280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka for (int y = 0; y < mCountY; y++) { 26910280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka mOccupied[x][y] = false; 269231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 269331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 26940280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 269531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 2696d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen public void markCellsAsOccupiedForView(View view) { 2697a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka if (view == null || view.getParent() != mShortcutsAndWidgets) return; 26980280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka LayoutParams lp = (LayoutParams) view.getLayoutParams(); 2699f7a29e83f06909b378dba39c83a522375682710aSunny Goyal markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, mOccupied, true); 27000280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 27010280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 2702d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen public void markCellsAsUnoccupiedForView(View view) { 2703a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka if (view == null || view.getParent() != mShortcutsAndWidgets) return; 27040280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka LayoutParams lp = (LayoutParams) view.getLayoutParams(); 2705f7a29e83f06909b378dba39c83a522375682710aSunny Goyal markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, mOccupied, false); 27060280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka } 27070280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka 2708482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen private void markCellsForView(int cellX, int cellY, int spanX, int spanY, boolean[][] occupied, 2709482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen boolean value) { 2710482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen if (cellX < 0 || cellY < 0) return; 27110280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka for (int x = cellX; x < cellX + spanX && x < mCountX; x++) { 27120280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka for (int y = cellY; y < cellY + spanY && y < mCountY; y++) { 2713482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen occupied[x][y] = value; 271431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 271531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 271631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 271731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 27182801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen public int getDesiredWidth() { 27198b805b17158886035b38261eb611d8641701ae43Michael Jurka return getPaddingLeft() + getPaddingRight() + (mCountX * mCellWidth) + 27202801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen (Math.max((mCountX - 1), 0) * mWidthGap); 27212801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen } 27222801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen 27232801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen public int getDesiredHeight() { 27248b805b17158886035b38261eb611d8641701ae43Michael Jurka return getPaddingTop() + getPaddingBottom() + (mCountY * mCellHeight) + 27252801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen (Math.max((mCountY - 1), 0) * mHeightGap); 27262801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen } 27272801cafe62653131fdc9da402e5c44e5ffd0bf47Adam Cohen 272866d72178af91d455700875635473be942bc90e54Michael Jurka public boolean isOccupied(int x, int y) { 272966d72178af91d455700875635473be942bc90e54Michael Jurka if (x < mCountX && y < mCountY) { 273066d72178af91d455700875635473be942bc90e54Michael Jurka return mOccupied[x][y]; 273166d72178af91d455700875635473be942bc90e54Michael Jurka } else { 273266d72178af91d455700875635473be942bc90e54Michael Jurka throw new RuntimeException("Position exceeds the bound of this CellLayout"); 273366d72178af91d455700875635473be942bc90e54Michael Jurka } 273466d72178af91d455700875635473be942bc90e54Michael Jurka } 273566d72178af91d455700875635473be942bc90e54Michael Jurka 273631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 273731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) { 273831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return new CellLayout.LayoutParams(getContext(), attrs); 273931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 274031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 274131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 274231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { 274331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return p instanceof CellLayout.LayoutParams; 274431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 274531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 274631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 274731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { 274831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return new CellLayout.LayoutParams(p); 274931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 275031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 275131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public static class LayoutParams extends ViewGroup.MarginLayoutParams { 275231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 275331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Horizontal location of the item in the grid. 275431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 275531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @ViewDebug.ExportedProperty 275631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public int cellX; 275731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 275831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 275931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Vertical location of the item in the grid. 276031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 276131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @ViewDebug.ExportedProperty 276231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public int cellY; 276331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 276431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 2765482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * Temporary horizontal location of the item in the grid during reorder 2766482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen */ 2767482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public int tmpCellX; 2768482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2769482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen /** 2770482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * Temporary vertical location of the item in the grid during reorder 2771482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen */ 2772482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public int tmpCellY; 2773482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2774482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen /** 2775482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * Indicates that the temporary coordinates should be used to layout the items 2776482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen */ 2777482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public boolean useTmpCoords; 2778482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 2779482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen /** 278031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Number of cells spanned horizontally by the item. 278131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 278231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @ViewDebug.ExportedProperty 278331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public int cellHSpan; 278431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 278531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 278631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Number of cells spanned vertically by the item. 278731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 278831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @ViewDebug.ExportedProperty 278931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public int cellVSpan; 2790aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 27911b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen /** 27921b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen * Indicates whether the item will set its x, y, width and height parameters freely, 27931b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen * or whether these will be computed based on cellX, cellY, cellHSpan and cellVSpan. 27941b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen */ 2795d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen public boolean isLockedToGrid = true; 2796d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen 2797482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen /** 2798ec40b2b90c649be3b513af2ba174db56b54b64f6Adam Cohen * Indicates that this item should use the full extents of its parent. 2799ec40b2b90c649be3b513af2ba174db56b54b64f6Adam Cohen */ 2800ec40b2b90c649be3b513af2ba174db56b54b64f6Adam Cohen public boolean isFullscreen = false; 2801ec40b2b90c649be3b513af2ba174db56b54b64f6Adam Cohen 2802ec40b2b90c649be3b513af2ba174db56b54b64f6Adam Cohen /** 2803482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * Indicates whether this item can be reordered. Always true except in the case of the 2804482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen * the AllApps button. 2805482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen */ 2806482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen public boolean canReorder = true; 2807482ed823afb4c7452e037ce8add7ea425fc83da2Adam Cohen 280831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // X coordinate of the view in the layout. 280931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @ViewDebug.ExportedProperty 281031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int x; 281131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // Y coordinate of the view in the layout. 281231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @ViewDebug.ExportedProperty 281331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int y; 281431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 281584f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy boolean dropped; 2816fcb9e7144e58614f5ae0e9b272fb7ce040848c67Romain Guy 281731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public LayoutParams(Context c, AttributeSet attrs) { 281831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project super(c, attrs); 281931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellHSpan = 1; 282031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellVSpan = 1; 282131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 282231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 282331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public LayoutParams(ViewGroup.LayoutParams source) { 282431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project super(source); 282531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellHSpan = 1; 282631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellVSpan = 1; 282731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 2828aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 2829aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung public LayoutParams(LayoutParams source) { 2830aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung super(source); 2831aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung this.cellX = source.cellX; 2832aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung this.cellY = source.cellY; 2833aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung this.cellHSpan = source.cellHSpan; 2834aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung this.cellVSpan = source.cellVSpan; 2835aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung } 2836aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung 283731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public LayoutParams(int cellX, int cellY, int cellHSpan, int cellVSpan) { 28388f19cdd62f6e2be05e3890916eabd11317ae1bc2Romain Guy super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); 283931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this.cellX = cellX; 284031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this.cellY = cellY; 284131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this.cellHSpan = cellHSpan; 284231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this.cellVSpan = cellVSpan; 284331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 284431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 28452374abfda3e53f84e005df8923170308e4df8c03Adam Cohen public void setup(int cellWidth, int cellHeight, int widthGap, int heightGap, 28462374abfda3e53f84e005df8923170308e4df8c03Adam Cohen boolean invertHorizontally, int colCount) { 2847d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen if (isLockedToGrid) { 2848d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen final int myCellHSpan = cellHSpan; 2849d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen final int myCellVSpan = cellVSpan; 28502374abfda3e53f84e005df8923170308e4df8c03Adam Cohen int myCellX = useTmpCoords ? tmpCellX : cellX; 28512374abfda3e53f84e005df8923170308e4df8c03Adam Cohen int myCellY = useTmpCoords ? tmpCellY : cellY; 28522374abfda3e53f84e005df8923170308e4df8c03Adam Cohen 28532374abfda3e53f84e005df8923170308e4df8c03Adam Cohen if (invertHorizontally) { 28542374abfda3e53f84e005df8923170308e4df8c03Adam Cohen myCellX = colCount - myCellX - cellHSpan; 28552374abfda3e53f84e005df8923170308e4df8c03Adam Cohen } 28561b607ed454ed22c2fd855cb3e428376520fb2388Adam Cohen 2857d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen width = myCellHSpan * cellWidth + ((myCellHSpan - 1) * widthGap) - 2858d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen leftMargin - rightMargin; 2859d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen height = myCellVSpan * cellHeight + ((myCellVSpan - 1) * heightGap) - 2860d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen topMargin - bottomMargin; 2861eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung x = (int) (myCellX * (cellWidth + widthGap) + leftMargin); 2862eecf02da58adef5486bf0c9ff7127ea891f457a4Winson Chung y = (int) (myCellY * (cellHeight + heightGap) + topMargin); 2863d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen } 2864d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen } 2865d4844c3e731b00547a31f23a00f8bd4a271e2b62Adam Cohen 2866aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung public String toString() { 2867aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung return "(" + this.cellX + ", " + this.cellY + ")"; 2868aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung } 28697f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 28707f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public void setWidth(int width) { 28717f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen this.width = width; 28727f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 28737f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 28747f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public int getWidth() { 28757f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen return width; 28767f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 28777f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 28787f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public void setHeight(int height) { 28797f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen this.height = height; 28807f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 28817f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 28827f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public int getHeight() { 28837f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen return height; 28847f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 28857f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 28867f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public void setX(int x) { 28877f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen this.x = x; 28887f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 28897f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 28907f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public int getX() { 28917f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen return x; 28927f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 28937f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 28947f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public void setY(int y) { 28957f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen this.y = y; 28967f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 28977f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen 28987f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen public int getY() { 28997f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen return y; 29007f4eabe3709a72b416569136e4a095431c493c8bAdam Cohen } 290131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 290231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 29030280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // This class stores info for two purposes: 29040280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // 1. When dragging items (mDragInfo in Workspace), we store the View, its cellX & cellY, 29050280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // its spanX, spanY, and the screen it is on 29060280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // 2. When long clicking on an empty cell in a CellLayout, we save information about the 29070280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // cellX and cellY coordinates and which page was clicked. We then set this as a tag on 29080280c3be4d9f8fc6fdf015b7ecd276eb26f76f2dMichael Jurka // the CellLayout that was long clicked 290983a8f042adda926489494dff217c15ab696139b4Sunny Goyal public static final class CellInfo { 291031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project View cell; 2911a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka int cellX = -1; 2912a63c452f5bd491ba9b28c332ccedc6c6c7e2f3ccMichael Jurka int cellY = -1; 291331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int spanX; 291431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int spanY; 2915dcd297f05a866e07090d6e2af8fb4b15f28cb555Adam Cohen long screenId; 29163d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung long container; 291731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 291883a8f042adda926489494dff217c15ab696139b4Sunny Goyal public CellInfo(View v, ItemInfo info) { 2919e0aaa0d3de0eedf5501fee762e0d8279a9e3bc3cAdam Cohen cell = v; 2920e0aaa0d3de0eedf5501fee762e0d8279a9e3bc3cAdam Cohen cellX = info.cellX; 2921e0aaa0d3de0eedf5501fee762e0d8279a9e3bc3cAdam Cohen cellY = info.cellY; 2922e0aaa0d3de0eedf5501fee762e0d8279a9e3bc3cAdam Cohen spanX = info.spanX; 2923e0aaa0d3de0eedf5501fee762e0d8279a9e3bc3cAdam Cohen spanY = info.spanY; 2924e0aaa0d3de0eedf5501fee762e0d8279a9e3bc3cAdam Cohen screenId = info.screenId; 2925e0aaa0d3de0eedf5501fee762e0d8279a9e3bc3cAdam Cohen container = info.container; 2926e0aaa0d3de0eedf5501fee762e0d8279a9e3bc3cAdam Cohen } 2927e0aaa0d3de0eedf5501fee762e0d8279a9e3bc3cAdam Cohen 292831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 292931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public String toString() { 2930aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung return "Cell[view=" + (cell == null ? "null" : cell.getClass()) 2931aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chung + ", x=" + cellX + ", y=" + cellY + "]"; 293231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 293331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 2934d771c96e5d156ffde5d35ee13ce053de60dc3163Michael Jurka 2935a911672f45900fc0ed746e0d84c43c6e5ad89b6aSunny Goyal public boolean findVacantCell(int spanX, int spanY, int[] outXY) { 2936a911672f45900fc0ed746e0d84c43c6e5ad89b6aSunny Goyal return Utilities.findVacantCell(outXY, spanX, spanY, mCountX, mCountY, mOccupied); 2937a911672f45900fc0ed746e0d84c43c6e5ad89b6aSunny Goyal } 29389ca9c1316da8382c1f663973072731033b5e533aSunny Goyal 29399ca9c1316da8382c1f663973072731033b5e533aSunny Goyal public boolean isRegionVacant(int x, int y, int spanX, int spanY) { 29409ca9c1316da8382c1f663973072731033b5e533aSunny Goyal int x2 = x + spanX - 1; 29419ca9c1316da8382c1f663973072731033b5e533aSunny Goyal int y2 = y + spanY - 1; 29429ca9c1316da8382c1f663973072731033b5e533aSunny Goyal if (x < 0 || y < 0 || x2 >= mCountX || y2 >= mCountY) { 29439ca9c1316da8382c1f663973072731033b5e533aSunny Goyal return false; 29449ca9c1316da8382c1f663973072731033b5e533aSunny Goyal } 29459ca9c1316da8382c1f663973072731033b5e533aSunny Goyal for (int i = x; i <= x2; i++) { 29469ca9c1316da8382c1f663973072731033b5e533aSunny Goyal for (int j = y; j <= y2; j++) { 29479ca9c1316da8382c1f663973072731033b5e533aSunny Goyal if (mOccupied[i][j]) { 29489ca9c1316da8382c1f663973072731033b5e533aSunny Goyal return false; 29499ca9c1316da8382c1f663973072731033b5e533aSunny Goyal } 29509ca9c1316da8382c1f663973072731033b5e533aSunny Goyal } 29519ca9c1316da8382c1f663973072731033b5e533aSunny Goyal } 29529ca9c1316da8382c1f663973072731033b5e533aSunny Goyal 29539ca9c1316da8382c1f663973072731033b5e533aSunny Goyal return true; 29549ca9c1316da8382c1f663973072731033b5e533aSunny Goyal } 295531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project} 2956