CellLayout.java revision 8f19cdd62f6e2be05e3890916eabd11317ae1bc2
131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project/* 231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project 331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * you may not use this file except in compliance with the License. 631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * You may obtain a copy of the License at 731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 1031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 1131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 1231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * See the License for the specific language governing permissions and 1431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * limitations under the License. 1531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 1631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 17a5902524d4403885eb4c50360bf3465c6be796efJoe Onoratopackage com.android.launcher2; 1831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 1931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.content.Context; 2031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.content.res.TypedArray; 2179e56263dbcbe85dc434df372bc6e6730aa13477Joe Onoratoimport android.content.res.Resources; 2231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.graphics.Rect; 2331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.graphics.RectF; 24a6abce8464b57ce91e8f083951ad263370fc2da8Romain Guyimport android.graphics.Canvas; 2531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.util.AttributeSet; 2631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.ContextMenu; 2731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.MotionEvent; 2831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.View; 2931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.ViewDebug; 3031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.ViewGroup; 3184f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guyimport android.app.WallpaperManager; 3231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 3331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport java.util.ArrayList; 3431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 3531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectpublic class CellLayout extends ViewGroup { 3631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private boolean mPortrait; 3731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 3831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private int mCellWidth; 3931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private int mCellHeight; 4031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 4131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private int mLongAxisStartPadding; 4231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private int mLongAxisEndPadding; 4331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 4431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private int mShortAxisStartPadding; 4531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private int mShortAxisEndPadding; 4631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 4731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private int mShortAxisCells; 4831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private int mLongAxisCells; 4931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 5031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private int mWidthGap; 5131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private int mHeightGap; 5231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 5331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private final Rect mRect = new Rect(); 5431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private final CellInfo mCellInfo = new CellInfo(); 5531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 5631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int[] mCellXY = new int[2]; 5731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project boolean[][] mOccupied; 5831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 5931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private RectF mDragRect = new RectF(); 6031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 6131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private boolean mDirtyTag; 62f8bbd34d7d4705b49db202be92b920196bc7ea38Mike Cleron private boolean mLastDownOnOccupiedCell = false; 6384f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy 6484f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy private final WallpaperManager mWallpaperManager; 6531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 6631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public CellLayout(Context context) { 6731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this(context, null); 6831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 6931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 7031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public CellLayout(Context context, AttributeSet attrs) { 7131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this(context, attrs, 0); 7231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 7331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 7431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public CellLayout(Context context, AttributeSet attrs, int defStyle) { 7531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project super(context, attrs, defStyle); 7631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CellLayout, defStyle, 0); 7731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 7831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mCellWidth = a.getDimensionPixelSize(R.styleable.CellLayout_cellWidth, 10); 7931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mCellHeight = a.getDimensionPixelSize(R.styleable.CellLayout_cellHeight, 10); 8031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 8131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mLongAxisStartPadding = 8231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project a.getDimensionPixelSize(R.styleable.CellLayout_longAxisStartPadding, 10); 8331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mLongAxisEndPadding = 8431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project a.getDimensionPixelSize(R.styleable.CellLayout_longAxisEndPadding, 10); 8531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mShortAxisStartPadding = 8631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project a.getDimensionPixelSize(R.styleable.CellLayout_shortAxisStartPadding, 10); 8731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mShortAxisEndPadding = 8831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project a.getDimensionPixelSize(R.styleable.CellLayout_shortAxisEndPadding, 10); 8931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 9031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mShortAxisCells = a.getInt(R.styleable.CellLayout_shortAxisCells, 4); 9131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mLongAxisCells = a.getInt(R.styleable.CellLayout_longAxisCells, 4); 9231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 9331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project a.recycle(); 9431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 9531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project setAlwaysDrawnWithCacheEnabled(false); 9631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 9731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (mOccupied == null) { 9831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (mPortrait) { 9931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mOccupied = new boolean[mShortAxisCells][mLongAxisCells]; 10031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } else { 10131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mOccupied = new boolean[mLongAxisCells][mShortAxisCells]; 10231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 10331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 10484f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy 10584f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy mWallpaperManager = WallpaperManager.getInstance(getContext()); 106a6abce8464b57ce91e8f083951ad263370fc2da8Romain Guy } 107a6abce8464b57ce91e8f083951ad263370fc2da8Romain Guy 108a6abce8464b57ce91e8f083951ad263370fc2da8Romain Guy @Override 109a6abce8464b57ce91e8f083951ad263370fc2da8Romain Guy public void dispatchDraw(Canvas canvas) { 110a6abce8464b57ce91e8f083951ad263370fc2da8Romain Guy super.dispatchDraw(canvas); 11131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 11231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 11383f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey @Override 11483f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey public void cancelLongPress() { 11583f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey super.cancelLongPress(); 11683f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey 11783f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey // Cancel long press for all children 11883f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey final int count = getChildCount(); 11983f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey for (int i = 0; i < count; i++) { 12083f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey final View child = getChildAt(i); 12183f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey child.cancelLongPress(); 12283f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey } 12383f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey } 12483f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey 12531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int getCountX() { 12631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return mPortrait ? mShortAxisCells : mLongAxisCells; 12731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 12831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 12931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int getCountY() { 13031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return mPortrait ? mLongAxisCells : mShortAxisCells; 13131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 13231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 13331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 13431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public void addView(View child, int index, ViewGroup.LayoutParams params) { 13531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // Generate an id for each view, this assumes we have at most 256x256 cells 13631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // per workspace screen 13731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final LayoutParams cellParams = (LayoutParams) params; 138fcb9e7144e58614f5ae0e9b272fb7ce040848c67Romain Guy cellParams.regenerateId = true; 13931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 14031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project super.addView(child, index, params); 14131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 14231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 14331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 14431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public void requestChildFocus(View child, View focused) { 14531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project super.requestChildFocus(child, focused); 14631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (child != null) { 14731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project Rect r = new Rect(); 14831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project child.getDrawingRect(r); 14931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project requestRectangleOnScreen(r); 15031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 15131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 15231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 15331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 15431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected void onAttachedToWindow() { 15531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project super.onAttachedToWindow(); 15631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mCellInfo.screen = ((ViewGroup) getParent()).indexOfChild(this); 15731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 15831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 15931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 16031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public boolean onInterceptTouchEvent(MotionEvent ev) { 16131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int action = ev.getAction(); 16231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final CellInfo cellInfo = mCellInfo; 16331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 16431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (action == MotionEvent.ACTION_DOWN) { 16531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final Rect frame = mRect; 16631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int x = (int) ev.getX() + mScrollX; 16731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int y = (int) ev.getY() + mScrollY; 16831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int count = getChildCount(); 16931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 17031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project boolean found = false; 17131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int i = count - 1; i >= 0; i--) { 17231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final View child = getChildAt(i); 17331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 17431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if ((child.getVisibility()) == VISIBLE || child.getAnimation() != null) { 17531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project child.getHitRect(frame); 17631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (frame.contains(x, y)) { 17731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 17831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.cell = child; 17931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.cellX = lp.cellX; 18031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.cellY = lp.cellY; 18131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.spanX = lp.cellHSpan; 18231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.spanY = lp.cellVSpan; 18331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.valid = true; 18431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project found = true; 18531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mDirtyTag = false; 18631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project break; 18731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 18831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 18931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 190f8bbd34d7d4705b49db202be92b920196bc7ea38Mike Cleron 191f8bbd34d7d4705b49db202be92b920196bc7ea38Mike Cleron mLastDownOnOccupiedCell = found; 19231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 19331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (!found) { 19431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int cellXY[] = mCellXY; 19531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project pointToCellExact(x, y, cellXY); 19631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 19731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final boolean portrait = mPortrait; 19831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int xCount = portrait ? mShortAxisCells : mLongAxisCells; 19931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int yCount = portrait ? mLongAxisCells : mShortAxisCells; 20031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 20131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final boolean[][] occupied = mOccupied; 20270864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey findOccupiedCells(xCount, yCount, occupied, null); 20331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 20431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.cell = null; 20531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.cellX = cellXY[0]; 20631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.cellY = cellXY[1]; 20731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.spanX = 1; 20831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.spanY = 1; 20931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.valid = cellXY[0] >= 0 && cellXY[1] >= 0 && cellXY[0] < xCount && 21031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellXY[1] < yCount && !occupied[cellXY[0]][cellXY[1]]; 21131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 21231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // Instead of finding the interesting vacant cells here, wait until a 21331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // caller invokes getTag() to retrieve the result. Finding the vacant 21431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // cells is a bit expensive and can generate many new objects, it's 21531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // therefore better to defer it until we know we actually need it. 21631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 21731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mDirtyTag = true; 21831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 21931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project setTag(cellInfo); 22031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } else if (action == MotionEvent.ACTION_UP) { 22131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.cell = null; 22231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.cellX = -1; 22331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.cellY = -1; 22431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.spanX = 0; 22531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.spanY = 0; 22631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.valid = false; 22731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mDirtyTag = false; 22831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project setTag(cellInfo); 22931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 23031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 23131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return false; 23231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 23331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 23431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 23531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public CellInfo getTag() { 23631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final CellInfo info = (CellInfo) super.getTag(); 23731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (mDirtyTag && info.valid) { 23831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final boolean portrait = mPortrait; 23931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int xCount = portrait ? mShortAxisCells : mLongAxisCells; 24031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int yCount = portrait ? mLongAxisCells : mShortAxisCells; 24131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 24231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final boolean[][] occupied = mOccupied; 24370864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey findOccupiedCells(xCount, yCount, occupied, null); 24431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 24531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project findIntersectingVacantCells(info, info.cellX, info.cellY, xCount, yCount, occupied); 24631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 24731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mDirtyTag = false; 24831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 24931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return info; 25031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 25131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 25231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private static void findIntersectingVacantCells(CellInfo cellInfo, int x, int y, 25331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int xCount, int yCount, boolean[][] occupied) { 25431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 25531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.maxVacantSpanX = Integer.MIN_VALUE; 25631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.maxVacantSpanXSpanY = Integer.MIN_VALUE; 25731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.maxVacantSpanY = Integer.MIN_VALUE; 25831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.maxVacantSpanYSpanX = Integer.MIN_VALUE; 25931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.clearVacantCells(); 26031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 26131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (occupied[x][y]) { 26231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return; 26331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 26431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 26531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.current.set(x, y, x, y); 26631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 26731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project findVacantCell(cellInfo.current, xCount, yCount, occupied, cellInfo); 26831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 26931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 27031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private static void findVacantCell(Rect current, int xCount, int yCount, boolean[][] occupied, 27131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project CellInfo cellInfo) { 27231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 27331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project addVacantCell(current, cellInfo); 27431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 27531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (current.left > 0) { 27631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (isColumnEmpty(current.left - 1, current.top, current.bottom, occupied)) { 27731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project current.left--; 27831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project findVacantCell(current, xCount, yCount, occupied, cellInfo); 27931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project current.left++; 28031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 28131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 28231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 28331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (current.right < xCount - 1) { 28431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (isColumnEmpty(current.right + 1, current.top, current.bottom, occupied)) { 28531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project current.right++; 28631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project findVacantCell(current, xCount, yCount, occupied, cellInfo); 28731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project current.right--; 28831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 28931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 29031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 29131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (current.top > 0) { 29231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (isRowEmpty(current.top - 1, current.left, current.right, occupied)) { 29331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project current.top--; 29431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project findVacantCell(current, xCount, yCount, occupied, cellInfo); 29531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project current.top++; 29631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 29731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 29831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 29931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (current.bottom < yCount - 1) { 30031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (isRowEmpty(current.bottom + 1, current.left, current.right, occupied)) { 30131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project current.bottom++; 30231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project findVacantCell(current, xCount, yCount, occupied, cellInfo); 30331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project current.bottom--; 30431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 30531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 30631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 30731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 30831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private static void addVacantCell(Rect current, CellInfo cellInfo) { 30931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project CellInfo.VacantCell cell = CellInfo.VacantCell.acquire(); 31031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cell.cellX = current.left; 31131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cell.cellY = current.top; 31231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cell.spanX = current.right - current.left + 1; 31331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cell.spanY = current.bottom - current.top + 1; 31431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (cell.spanX > cellInfo.maxVacantSpanX) { 31531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.maxVacantSpanX = cell.spanX; 31631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.maxVacantSpanXSpanY = cell.spanY; 31731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 31831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (cell.spanY > cellInfo.maxVacantSpanY) { 31931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.maxVacantSpanY = cell.spanY; 32031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.maxVacantSpanYSpanX = cell.spanX; 32131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 32231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.vacantCells.add(cell); 32331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 32431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 32531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private static boolean isColumnEmpty(int x, int top, int bottom, boolean[][] occupied) { 32631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int y = top; y <= bottom; y++) { 32731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (occupied[x][y]) { 32831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return false; 32931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 33031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 33131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return true; 33231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 33331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 33431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private static boolean isRowEmpty(int y, int left, int right, boolean[][] occupied) { 33531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int x = left; x <= right; x++) { 33631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (occupied[x][y]) { 33731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return false; 33831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 33931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 34031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return true; 34131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 34231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 34370864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey CellInfo findAllVacantCells(boolean[] occupiedCells, View ignoreView) { 34431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final boolean portrait = mPortrait; 34531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int xCount = portrait ? mShortAxisCells : mLongAxisCells; 34631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int yCount = portrait ? mLongAxisCells : mShortAxisCells; 34731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 34831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project boolean[][] occupied = mOccupied; 34931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 35031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (occupiedCells != null) { 35131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int y = 0; y < yCount; y++) { 35231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int x = 0; x < xCount; x++) { 35331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project occupied[x][y] = occupiedCells[y * xCount + x]; 35431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 35531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 35631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } else { 35770864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey findOccupiedCells(xCount, yCount, occupied, ignoreView); 35831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 35931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 36031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project CellInfo cellInfo = new CellInfo(); 36131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 36231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.cellX = -1; 36331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.cellY = -1; 36431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.spanY = 0; 36531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.spanX = 0; 36631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.maxVacantSpanX = Integer.MIN_VALUE; 36731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.maxVacantSpanXSpanY = Integer.MIN_VALUE; 36831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.maxVacantSpanY = Integer.MIN_VALUE; 36931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.maxVacantSpanYSpanX = Integer.MIN_VALUE; 37031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.screen = mCellInfo.screen; 37131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 37231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project Rect current = cellInfo.current; 37331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 37431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int x = 0; x < xCount; x++) { 37531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int y = 0; y < yCount; y++) { 37631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (!occupied[x][y]) { 37731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project current.set(x, y, x, y); 37831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project findVacantCell(current, xCount, yCount, occupied, cellInfo); 37931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project occupied[x][y] = true; 38031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 38131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 38231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 38331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 38431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.valid = cellInfo.vacantCells.size() > 0; 38531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 38631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // Assume the caller will perform their own cell searching, otherwise we 38731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // risk causing an unnecessary rebuild after findCellForSpan() 38831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 38931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return cellInfo; 39031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 39131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 39231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 39331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Given a point, return the cell that strictly encloses that point 39431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param x X coordinate of the point 39531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param y Y coordinate of the point 39631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param result Array of 2 ints to hold the x and y coordinate of the cell 39731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 39831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project void pointToCellExact(int x, int y, int[] result) { 39931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final boolean portrait = mPortrait; 40031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 40131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int hStartPadding = portrait ? mShortAxisStartPadding : mLongAxisStartPadding; 40231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int vStartPadding = portrait ? mLongAxisStartPadding : mShortAxisStartPadding; 40331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 40431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project result[0] = (x - hStartPadding) / (mCellWidth + mWidthGap); 40531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project result[1] = (y - vStartPadding) / (mCellHeight + mHeightGap); 40631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 40731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int xAxis = portrait ? mShortAxisCells : mLongAxisCells; 40831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int yAxis = portrait ? mLongAxisCells : mShortAxisCells; 40931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 41031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (result[0] < 0) result[0] = 0; 41131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (result[0] >= xAxis) result[0] = xAxis - 1; 41231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (result[1] < 0) result[1] = 0; 41331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (result[1] >= yAxis) result[1] = yAxis - 1; 41431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 41531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 41631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 41731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Given a point, return the cell that most closely encloses that point 41831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param x X coordinate of the point 41931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param y Y coordinate of the point 42031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param result Array of 2 ints to hold the x and y coordinate of the cell 42131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 42231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project void pointToCellRounded(int x, int y, int[] result) { 42331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project pointToCellExact(x + (mCellWidth / 2), y + (mCellHeight / 2), result); 42431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 42531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 42631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 42731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Given a cell coordinate, return the point that represents the upper left corner of that cell 42831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 42931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param cellX X coordinate of the cell 43031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param cellY Y coordinate of the cell 43131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 43231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param result Array of 2 ints to hold the x and y coordinate of the point 43331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 43431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project void cellToPoint(int cellX, int cellY, int[] result) { 43531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final boolean portrait = mPortrait; 43631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 43731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int hStartPadding = portrait ? mShortAxisStartPadding : mLongAxisStartPadding; 43831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int vStartPadding = portrait ? mLongAxisStartPadding : mShortAxisStartPadding; 43931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 44031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 44131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project result[0] = hStartPadding + cellX * (mCellWidth + mWidthGap); 44231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project result[1] = vStartPadding + cellY * (mCellHeight + mHeightGap); 44331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 44431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 44584f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy int getCellWidth() { 44684f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy return mCellWidth; 44784f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy } 44884f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy 44984f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy int getCellHeight() { 45084f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy return mCellHeight; 45184f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy } 45284f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy 4531a304a1198f2f48be8c6a763b3ce511bd28af811Romain Guy int getLeftPadding() { 4541a304a1198f2f48be8c6a763b3ce511bd28af811Romain Guy return mPortrait ? mShortAxisStartPadding : mLongAxisStartPadding; 4551a304a1198f2f48be8c6a763b3ce511bd28af811Romain Guy } 4561a304a1198f2f48be8c6a763b3ce511bd28af811Romain Guy 4571a304a1198f2f48be8c6a763b3ce511bd28af811Romain Guy int getTopPadding() { 4581a304a1198f2f48be8c6a763b3ce511bd28af811Romain Guy return mPortrait ? mLongAxisStartPadding : mShortAxisStartPadding; 4591a304a1198f2f48be8c6a763b3ce511bd28af811Romain Guy } 4601a304a1198f2f48be8c6a763b3ce511bd28af811Romain Guy 4611a304a1198f2f48be8c6a763b3ce511bd28af811Romain Guy int getRightPadding() { 4621a304a1198f2f48be8c6a763b3ce511bd28af811Romain Guy return mPortrait ? mShortAxisEndPadding : mLongAxisEndPadding; 4631a304a1198f2f48be8c6a763b3ce511bd28af811Romain Guy } 4641a304a1198f2f48be8c6a763b3ce511bd28af811Romain Guy 4651a304a1198f2f48be8c6a763b3ce511bd28af811Romain Guy int getBottomPadding() { 4661a304a1198f2f48be8c6a763b3ce511bd28af811Romain Guy return mPortrait ? mLongAxisEndPadding : mShortAxisEndPadding; 4671a304a1198f2f48be8c6a763b3ce511bd28af811Romain Guy } 4681a304a1198f2f48be8c6a763b3ce511bd28af811Romain Guy 46931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 47031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 47131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // TODO: currently ignoring padding 47231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 47331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec); 47431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec); 47531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 47631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec); 47731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec); 47831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 47931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (widthSpecMode == MeasureSpec.UNSPECIFIED || heightSpecMode == MeasureSpec.UNSPECIFIED) { 48031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project throw new RuntimeException("CellLayout cannot have UNSPECIFIED dimensions"); 48131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 48231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 48331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int shortAxisCells = mShortAxisCells; 48431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int longAxisCells = mLongAxisCells; 48531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int longAxisStartPadding = mLongAxisStartPadding; 48631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int longAxisEndPadding = mLongAxisEndPadding; 48731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int shortAxisStartPadding = mShortAxisStartPadding; 48831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int shortAxisEndPadding = mShortAxisEndPadding; 48931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int cellWidth = mCellWidth; 49031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int cellHeight = mCellHeight; 49131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 49231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mPortrait = heightSpecSize > widthSpecSize; 49331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 49431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int numShortGaps = shortAxisCells - 1; 49531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int numLongGaps = longAxisCells - 1; 49631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 49731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (mPortrait) { 49831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int vSpaceLeft = heightSpecSize - longAxisStartPadding - longAxisEndPadding 49931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project - (cellHeight * longAxisCells); 50031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mHeightGap = vSpaceLeft / numLongGaps; 50131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 50231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int hSpaceLeft = widthSpecSize - shortAxisStartPadding - shortAxisEndPadding 50331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project - (cellWidth * shortAxisCells); 50431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (numShortGaps > 0) { 50531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mWidthGap = hSpaceLeft / numShortGaps; 50631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } else { 50731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mWidthGap = 0; 50831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 50931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } else { 51031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int hSpaceLeft = widthSpecSize - longAxisStartPadding - longAxisEndPadding 51131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project - (cellWidth * longAxisCells); 51231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mWidthGap = hSpaceLeft / numLongGaps; 51331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 51431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int vSpaceLeft = heightSpecSize - shortAxisStartPadding - shortAxisEndPadding 51531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project - (cellHeight * shortAxisCells); 51631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (numShortGaps > 0) { 51731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mHeightGap = vSpaceLeft / numShortGaps; 51831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } else { 51931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mHeightGap = 0; 52031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 52131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 52231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 52331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int count = getChildCount(); 52431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 52531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int i = 0; i < count; i++) { 52631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project View child = getChildAt(i); 52731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project LayoutParams lp = (LayoutParams) child.getLayoutParams(); 52831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 52931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (mPortrait) { 53031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project lp.setup(cellWidth, cellHeight, mWidthGap, mHeightGap, shortAxisStartPadding, 53131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project longAxisStartPadding); 53231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } else { 53331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project lp.setup(cellWidth, cellHeight, mWidthGap, mHeightGap, longAxisStartPadding, 53431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project shortAxisStartPadding); 53531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 536fcb9e7144e58614f5ae0e9b272fb7ce040848c67Romain Guy 537fcb9e7144e58614f5ae0e9b272fb7ce040848c67Romain Guy if (lp.regenerateId) { 538fcb9e7144e58614f5ae0e9b272fb7ce040848c67Romain Guy child.setId(((getId() & 0xFF) << 16) | (lp.cellX & 0xFF) << 8 | (lp.cellY & 0xFF)); 539fcb9e7144e58614f5ae0e9b272fb7ce040848c67Romain Guy lp.regenerateId = false; 540fcb9e7144e58614f5ae0e9b272fb7ce040848c67Romain Guy } 54131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 54231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(lp.width, MeasureSpec.EXACTLY); 54331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int childheightMeasureSpec = 54431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY); 54531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project child.measure(childWidthMeasureSpec, childheightMeasureSpec); 54631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 54731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 54831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project setMeasuredDimension(widthSpecSize, heightSpecSize); 54931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 55031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 55131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 55231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected void onLayout(boolean changed, int l, int t, int r, int b) { 55331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int count = getChildCount(); 55431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 55531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int i = 0; i < count; i++) { 55631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project View child = getChildAt(i); 55731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (child.getVisibility() != GONE) { 55831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 55931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams(); 56031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 56131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int childLeft = lp.x; 56231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int childTop = lp.y; 56331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project child.layout(childLeft, childTop, childLeft + lp.width, childTop + lp.height); 56484f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy 56584f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy if (lp.dropped) { 56684f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy lp.dropped = false; 56784f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy 56884f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy mWallpaperManager.sendWallpaperCommand(getWindowToken(), "android.home.drop", 56984f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy childLeft + lp.width / 2, childTop + lp.height / 2, 0, null); 57084f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy } 57131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 57231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 57331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 57431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 57531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 57631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected void setChildrenDrawingCacheEnabled(boolean enabled) { 57731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int count = getChildCount(); 57831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int i = 0; i < count; i++) { 57931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final View view = getChildAt(i); 58031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project view.setDrawingCacheEnabled(enabled); 58131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // Update the drawing caches 582806b0f3fbf02171c691b1f9d48e51a47760565b3Romain Guy view.buildDrawingCache(true); 58331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 58431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 58531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 58631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 58731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected void setChildrenDrawnWithCacheEnabled(boolean enabled) { 58831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project super.setChildrenDrawnWithCacheEnabled(enabled); 58931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 59031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 59131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 59270864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * Find a vacant area that will fit the given bounds nearest the requested 59370864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * cell location. Uses Euclidean distance to score multiple vacant areas. 59470864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * 59551afc022fa76c79f0d1ece470ddc126c08fea8a4Romain Guy * @param pixelX The X location at which you want to search for a vacant area. 59651afc022fa76c79f0d1ece470ddc126c08fea8a4Romain Guy * @param pixelY The Y location at which you want to search for a vacant area. 59770864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * @param spanX Horizontal span of the object. 59870864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * @param spanY Vertical span of the object. 59970864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * @param vacantCells Pre-computed set of vacant cells to search. 60070864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * @param recycle Previously returned value to possibly recycle. 60170864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * @return The X, Y cell of a vacant area that can contain this object, 60270864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * nearest the requested location. 60331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 60470864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey int[] findNearestVacantArea(int pixelX, int pixelY, int spanX, int spanY, 60570864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey CellInfo vacantCells, int[] recycle) { 60670864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey 60770864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey // Keep track of best-scoring drop area 60870864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey final int[] bestXY = recycle != null ? recycle : new int[2]; 60970864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey final int[] cellXY = mCellXY; 61070864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey double bestDistance = Double.MAX_VALUE; 61170864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey 61270864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey // Bail early if vacant cells aren't valid 61370864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey if (!vacantCells.valid) { 61470864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey return null; 61531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 61631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 61770864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey // Look across all vacant cells for best fit 61870864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey final int size = vacantCells.vacantCells.size(); 61970864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey for (int i = 0; i < size; i++) { 62070864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey final CellInfo.VacantCell cell = vacantCells.vacantCells.get(i); 62170864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey 62270864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey // Reject if vacant cell isn't our exact size 62370864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey if (cell.spanX != spanX || cell.spanY != spanY) { 62431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project continue; 62531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 62670864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey 62770864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey // Score is center distance from requested pixel 62870864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey cellToPoint(cell.cellX, cell.cellY, cellXY); 62970864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey 63070864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey double distance = Math.sqrt(Math.pow(cellXY[0] - pixelX, 2) + 63170864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey Math.pow(cellXY[1] - pixelY, 2)); 63270864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey if (distance <= bestDistance) { 63370864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey bestDistance = distance; 63470864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey bestXY[0] = cell.cellX; 63570864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey bestXY[1] = cell.cellY; 63631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 63731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 63831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 63970864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey // Return null if no suitable location found 64070864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey if (bestDistance < Double.MAX_VALUE) { 64170864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey return bestXY; 64270864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey } else { 64370864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey return null; 64470864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey } 64531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 64670864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey 64731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 64831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Drop a child at the specified position 64931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 65031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param child The child that is being dropped 65170864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * @param targetXY Destination area to move to 65231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 65370864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey void onDropChild(View child, int[] targetXY) { 654d94533d04a5f8f5485f106d10af60169857ea899Romain Guy if (child != null) { 655d94533d04a5f8f5485f106d10af60169857ea899Romain Guy LayoutParams lp = (LayoutParams) child.getLayoutParams(); 656d94533d04a5f8f5485f106d10af60169857ea899Romain Guy lp.cellX = targetXY[0]; 657d94533d04a5f8f5485f106d10af60169857ea899Romain Guy lp.cellY = targetXY[1]; 658d94533d04a5f8f5485f106d10af60169857ea899Romain Guy lp.isDragging = false; 65984f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy lp.dropped = true; 660d94533d04a5f8f5485f106d10af60169857ea899Romain Guy mDragRect.setEmpty(); 661d94533d04a5f8f5485f106d10af60169857ea899Romain Guy child.requestLayout(); 662d94533d04a5f8f5485f106d10af60169857ea899Romain Guy invalidate(); 663d94533d04a5f8f5485f106d10af60169857ea899Romain Guy } 66431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 66531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 66631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project void onDropAborted(View child) { 66731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (child != null) { 66831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project ((LayoutParams) child.getLayoutParams()).isDragging = false; 66931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project invalidate(); 67031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 67131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mDragRect.setEmpty(); 67231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 67331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 67431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 67531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Start dragging the specified child 67631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 67731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param child The child that is being dragged 67831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 67931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project void onDragChild(View child) { 68031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project LayoutParams lp = (LayoutParams) child.getLayoutParams(); 68131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project lp.isDragging = true; 68231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mDragRect.setEmpty(); 68331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 68431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 68531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 68631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Drag a child over the specified position 68731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 68831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param child The child that is being dropped 68931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param cellX The child's new x cell location 69031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param cellY The child's new y cell location 69131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 69231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project void onDragOverChild(View child, int cellX, int cellY) { 69331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int[] cellXY = mCellXY; 69431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project pointToCellRounded(cellX, cellY, cellXY); 69531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project LayoutParams lp = (LayoutParams) child.getLayoutParams(); 69631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellToRect(cellXY[0], cellXY[1], lp.cellHSpan, lp.cellVSpan, mDragRect); 69731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project invalidate(); 69831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 69931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 70031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 70131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Computes a bounding rectangle for a range of cells 70231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 70331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param cellX X coordinate of upper left corner expressed as a cell position 70431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param cellY Y coordinate of upper left corner expressed as a cell position 70531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param cellHSpan Width in cells 70631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param cellVSpan Height in cells 70731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param dragRect Rectnagle into which to put the results 70831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 70931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public void cellToRect(int cellX, int cellY, int cellHSpan, int cellVSpan, RectF dragRect) { 71031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final boolean portrait = mPortrait; 71131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int cellWidth = mCellWidth; 71231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int cellHeight = mCellHeight; 71331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int widthGap = mWidthGap; 71431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int heightGap = mHeightGap; 71531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 71631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int hStartPadding = portrait ? mShortAxisStartPadding : mLongAxisStartPadding; 71731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int vStartPadding = portrait ? mLongAxisStartPadding : mShortAxisStartPadding; 71831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 71931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int width = cellHSpan * cellWidth + ((cellHSpan - 1) * widthGap); 72031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int height = cellVSpan * cellHeight + ((cellVSpan - 1) * heightGap); 72131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 72231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int x = hStartPadding + cellX * (cellWidth + widthGap); 72331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int y = vStartPadding + cellY * (cellHeight + heightGap); 72431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 72531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project dragRect.set(x, y, x + width, y + height); 72631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 72731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 72831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 72931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Computes the required horizontal and vertical cell spans to always 73031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * fit the given rectangle. 73131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 73231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param width Width in pixels 73331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param height Height in pixels 73431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 73531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public int[] rectToCell(int width, int height) { 73631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // Always assume we're working with the smallest span to make sure we 73731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // reserve enough space in both orientations. 73879e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato final Resources resources = getResources(); 73979e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato int actualWidth = resources.getDimensionPixelSize(R.dimen.workspace_cell_width); 74079e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato int actualHeight = resources.getDimensionPixelSize(R.dimen.workspace_cell_height); 74131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int smallerSize = Math.min(actualWidth, actualHeight); 74279e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato 74331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // Always round up to next largest cell 74431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int spanX = (width + smallerSize) / smallerSize; 74531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int spanY = (height + smallerSize) / smallerSize; 74679e56263dbcbe85dc434df372bc6e6730aa13477Joe Onorato 74731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return new int[] { spanX, spanY }; 74831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 74931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 75031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 75131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Find the first vacant cell, if there is one. 75231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 75331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param vacant Holds the x and y coordinate of the vacant cell 75431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param spanX Horizontal cell span. 75531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param spanY Vertical cell span. 75631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 75731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @return True if a vacant cell was found 75831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 75931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public boolean getVacantCell(int[] vacant, int spanX, int spanY) { 76031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final boolean portrait = mPortrait; 76131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int xCount = portrait ? mShortAxisCells : mLongAxisCells; 76231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int yCount = portrait ? mLongAxisCells : mShortAxisCells; 76331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final boolean[][] occupied = mOccupied; 76431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 76570864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey findOccupiedCells(xCount, yCount, occupied, null); 76631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 76731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return findVacantCell(vacant, spanX, spanY, xCount, yCount, occupied); 76831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 76931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 77031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project static boolean findVacantCell(int[] vacant, int spanX, int spanY, 77131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int xCount, int yCount, boolean[][] occupied) { 77231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 77331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int x = 0; x < xCount; x++) { 77431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int y = 0; y < yCount; y++) { 77531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project boolean available = !occupied[x][y]; 77631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectout: for (int i = x; i < x + spanX - 1 && x < xCount; i++) { 77731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int j = y; j < y + spanY - 1 && y < yCount; j++) { 77831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project available = available && !occupied[i][j]; 77931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (!available) break out; 78031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 78131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 78231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 78331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (available) { 78431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project vacant[0] = x; 78531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project vacant[1] = y; 78631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return true; 78731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 78831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 78931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 79031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 79131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return false; 79231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 79331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 79431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project boolean[] getOccupiedCells() { 79531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final boolean portrait = mPortrait; 79631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int xCount = portrait ? mShortAxisCells : mLongAxisCells; 79731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int yCount = portrait ? mLongAxisCells : mShortAxisCells; 79831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final boolean[][] occupied = mOccupied; 79931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 80070864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey findOccupiedCells(xCount, yCount, occupied, null); 80131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 80231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final boolean[] flat = new boolean[xCount * yCount]; 80331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int y = 0; y < yCount; y++) { 80431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int x = 0; x < xCount; x++) { 80531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project flat[y * xCount + x] = occupied[x][y]; 80631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 80731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 80831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 80931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return flat; 81031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 81131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 81270864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey private void findOccupiedCells(int xCount, int yCount, boolean[][] occupied, View ignoreView) { 81331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int x = 0; x < xCount; x++) { 81431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int y = 0; y < yCount; y++) { 81531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project occupied[x][y] = false; 81631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 81731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 81831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 81931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int count = getChildCount(); 82031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int i = 0; i < count; i++) { 82131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project View child = getChildAt(i); 82270864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey if (child instanceof Folder || child.equals(ignoreView)) { 82331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project continue; 82431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 82531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project LayoutParams lp = (LayoutParams) child.getLayoutParams(); 82631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 82731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int x = lp.cellX; x < lp.cellX + lp.cellHSpan && x < xCount; x++) { 82831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int y = lp.cellY; y < lp.cellY + lp.cellVSpan && y < yCount; y++) { 82931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project occupied[x][y] = true; 83031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 83131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 83231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 83331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 83431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 83531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 83631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) { 83731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return new CellLayout.LayoutParams(getContext(), attrs); 83831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 83931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 84031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 84131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { 84231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return p instanceof CellLayout.LayoutParams; 84331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 84431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 84531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 84631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { 84731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return new CellLayout.LayoutParams(p); 84831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 84931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 85031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public static class LayoutParams extends ViewGroup.MarginLayoutParams { 85131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 85231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Horizontal location of the item in the grid. 85331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 85431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @ViewDebug.ExportedProperty 85531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public int cellX; 85631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 85731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 85831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Vertical location of the item in the grid. 85931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 86031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @ViewDebug.ExportedProperty 86131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public int cellY; 86231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 86331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 86431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Number of cells spanned horizontally by the item. 86531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 86631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @ViewDebug.ExportedProperty 86731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public int cellHSpan; 86831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 86931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 87031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Number of cells spanned vertically by the item. 87131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 87231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @ViewDebug.ExportedProperty 87331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public int cellVSpan; 87431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 87531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 87631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Is this item currently being dragged 87731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 87831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public boolean isDragging; 87931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 88031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // X coordinate of the view in the layout. 88131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @ViewDebug.ExportedProperty 88231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int x; 88331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // Y coordinate of the view in the layout. 88431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @ViewDebug.ExportedProperty 88531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int y; 88631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 887fcb9e7144e58614f5ae0e9b272fb7ce040848c67Romain Guy boolean regenerateId; 88884f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy 88984f296c106cb1c7b6d3ae6c6d5508a17f1324e29Romain Guy boolean dropped; 890fcb9e7144e58614f5ae0e9b272fb7ce040848c67Romain Guy 89131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public LayoutParams(Context c, AttributeSet attrs) { 89231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project super(c, attrs); 89331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellHSpan = 1; 89431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellVSpan = 1; 89531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 89631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 89731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public LayoutParams(ViewGroup.LayoutParams source) { 89831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project super(source); 89931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellHSpan = 1; 90031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellVSpan = 1; 90131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 90231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 90331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public LayoutParams(int cellX, int cellY, int cellHSpan, int cellVSpan) { 9048f19cdd62f6e2be05e3890916eabd11317ae1bc2Romain Guy super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); 90531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this.cellX = cellX; 90631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this.cellY = cellY; 90731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this.cellHSpan = cellHSpan; 90831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this.cellVSpan = cellVSpan; 90931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 91031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 91131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public void setup(int cellWidth, int cellHeight, int widthGap, int heightGap, 91231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int hStartPadding, int vStartPadding) { 91331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 91431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int myCellHSpan = cellHSpan; 91531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int myCellVSpan = cellVSpan; 91631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int myCellX = cellX; 91731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int myCellY = cellY; 91831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 91931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project width = myCellHSpan * cellWidth + ((myCellHSpan - 1) * widthGap) - 92031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project leftMargin - rightMargin; 92131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project height = myCellVSpan * cellHeight + ((myCellVSpan - 1) * heightGap) - 92231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project topMargin - bottomMargin; 92331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 92431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project x = hStartPadding + myCellX * (cellWidth + widthGap) + leftMargin; 92531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project y = vStartPadding + myCellY * (cellHeight + heightGap) + topMargin; 92631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 92731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 92831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 92931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project static final class CellInfo implements ContextMenu.ContextMenuInfo { 93031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 93131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * See View.AttachInfo.InvalidateInfo for futher explanations about 93231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * the recycling mechanism. In this case, we recycle the vacant cells 93331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * instances because up to several hundreds can be instanciated when 93431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * the user long presses an empty cell. 93531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 93631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project static final class VacantCell { 93731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int cellX; 93831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int cellY; 93931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int spanX; 94031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int spanY; 94131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 94231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // We can create up to 523 vacant cells on a 4x4 grid, 100 seems 94331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // like a reasonable compromise given the size of a VacantCell and 94431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // the fact that the user is not likely to touch an empty 4x4 grid 94531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // very often 94631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private static final int POOL_LIMIT = 100; 94731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private static final Object sLock = new Object(); 94831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 94931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private static int sAcquiredCount = 0; 95031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private static VacantCell sRoot; 95131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 95231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private VacantCell next; 95331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 95431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project static VacantCell acquire() { 95531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project synchronized (sLock) { 95631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (sRoot == null) { 95731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return new VacantCell(); 95831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 95931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 96031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project VacantCell info = sRoot; 96131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project sRoot = info.next; 96231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project sAcquiredCount--; 96331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 96431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return info; 96531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 96631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 96731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 96831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project void release() { 96931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project synchronized (sLock) { 97031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (sAcquiredCount < POOL_LIMIT) { 97131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project sAcquiredCount++; 97231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project next = sRoot; 97331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project sRoot = this; 97431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 97531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 97631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 97731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 97831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 97931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public String toString() { 98031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return "VacantCell[x=" + cellX + ", y=" + cellY + ", spanX=" + spanX + 98131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project ", spanY=" + spanY + "]"; 98231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 98331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 98431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 98531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project View cell; 98631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int cellX; 98731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int cellY; 98831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int spanX; 98931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int spanY; 99031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int screen; 99131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project boolean valid; 99231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 99331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final ArrayList<VacantCell> vacantCells = new ArrayList<VacantCell>(VacantCell.POOL_LIMIT); 99431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int maxVacantSpanX; 99531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int maxVacantSpanXSpanY; 99631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int maxVacantSpanY; 99731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int maxVacantSpanYSpanX; 99831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final Rect current = new Rect(); 99931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 10004c58c485d8c02f8ca7e8b4d93140440f6a3a5131Romain Guy void clearVacantCells() { 100131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final ArrayList<VacantCell> list = vacantCells; 100231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int count = list.size(); 100331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 100431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int i = 0; i < count; i++) list.get(i).release(); 100531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 100631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project list.clear(); 100731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 100831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 100931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project void findVacantCellsFromOccupied(boolean[] occupied, int xCount, int yCount) { 101031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (cellX < 0 || cellY < 0) { 101131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project maxVacantSpanX = maxVacantSpanXSpanY = Integer.MIN_VALUE; 101231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project maxVacantSpanY = maxVacantSpanYSpanX = Integer.MIN_VALUE; 101331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project clearVacantCells(); 101431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return; 101531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 101631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 101731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final boolean[][] unflattened = new boolean[xCount][yCount]; 101831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int y = 0; y < yCount; y++) { 101931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int x = 0; x < xCount; x++) { 102031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project unflattened[x][y] = occupied[y * xCount + x]; 102131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 102231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 102331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project CellLayout.findIntersectingVacantCells(this, cellX, cellY, xCount, yCount, unflattened); 102431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 102531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 102631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 102731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * This method can be called only once! Calling #findVacantCellsFromOccupied will 102831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * restore the ability to call this method. 102931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 103031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Finds the upper-left coordinate of the first rectangle in the grid that can 103131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * hold a cell of the specified dimensions. 103231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 103331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param cellXY The array that will contain the position of a vacant cell if such a cell 103431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * can be found. 103531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param spanX The horizontal span of the cell we want to find. 103631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param spanY The vertical span of the cell we want to find. 103731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 103831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @return True if a vacant cell of the specified dimension was found, false otherwise. 103931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 104031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project boolean findCellForSpan(int[] cellXY, int spanX, int spanY) { 10414c58c485d8c02f8ca7e8b4d93140440f6a3a5131Romain Guy return findCellForSpan(cellXY, spanX, spanY, true); 10424c58c485d8c02f8ca7e8b4d93140440f6a3a5131Romain Guy } 10434c58c485d8c02f8ca7e8b4d93140440f6a3a5131Romain Guy 10444c58c485d8c02f8ca7e8b4d93140440f6a3a5131Romain Guy boolean findCellForSpan(int[] cellXY, int spanX, int spanY, boolean clear) { 104531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final ArrayList<VacantCell> list = vacantCells; 104631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int count = list.size(); 104731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 104831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project boolean found = false; 104931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 105031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (this.spanX >= spanX && this.spanY >= spanY) { 105131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellXY[0] = cellX; 105231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellXY[1] = cellY; 105331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project found = true; 105431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 105531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 105631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // Look for an exact match first 105731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int i = 0; i < count; i++) { 105831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project VacantCell cell = list.get(i); 105931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (cell.spanX == spanX && cell.spanY == spanY) { 106031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellXY[0] = cell.cellX; 106131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellXY[1] = cell.cellY; 106231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project found = true; 106331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project break; 106431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 106531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 106631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 106731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // Look for the first cell large enough 106831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int i = 0; i < count; i++) { 106931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project VacantCell cell = list.get(i); 107031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (cell.spanX >= spanX && cell.spanY >= spanY) { 107131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellXY[0] = cell.cellX; 107231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellXY[1] = cell.cellY; 107331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project found = true; 107431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project break; 107531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 107631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 107731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 10784c58c485d8c02f8ca7e8b4d93140440f6a3a5131Romain Guy if (clear) clearVacantCells(); 107931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 108031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return found; 108131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 108231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 108331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 108431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public String toString() { 108531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return "Cell[view=" + (cell == null ? "null" : cell.getClass()) + ", x=" + cellX + 108631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project ", y=" + cellY + "]"; 108731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 108831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 1089f8bbd34d7d4705b49db202be92b920196bc7ea38Mike Cleron 1090f8bbd34d7d4705b49db202be92b920196bc7ea38Mike Cleron public boolean lastDownOnOccupiedCell() { 1091f8bbd34d7d4705b49db202be92b920196bc7ea38Mike Cleron return mLastDownOnOccupiedCell; 1092f8bbd34d7d4705b49db202be92b920196bc7ea38Mike Cleron } 109331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project} 109431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 109531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 1096