CellLayout.java revision d94533d04a5f8f5485f106d10af60169857ea899
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; 2131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.graphics.Rect; 2231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.graphics.RectF; 2331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.util.AttributeSet; 2431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.ContextMenu; 2531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.MotionEvent; 2631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.View; 2731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.ViewDebug; 2831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.view.ViewGroup; 2931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 3031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport java.util.ArrayList; 3131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 3231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectpublic class CellLayout extends ViewGroup { 3331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private boolean mPortrait; 3431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 3531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private int mCellWidth; 3631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private int mCellHeight; 3731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 3831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private int mLongAxisStartPadding; 3931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private int mLongAxisEndPadding; 4031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 4131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private int mShortAxisStartPadding; 4231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private int mShortAxisEndPadding; 4331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 4431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private int mShortAxisCells; 4531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private int mLongAxisCells; 4631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 4731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private int mWidthGap; 4831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private int mHeightGap; 4931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 5031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private final Rect mRect = new Rect(); 5131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private final CellInfo mCellInfo = new CellInfo(); 5231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 5331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int[] mCellXY = new int[2]; 5431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 5531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project boolean[][] mOccupied; 5631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 5731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private RectF mDragRect = new RectF(); 5831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 5931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private boolean mDirtyTag; 6031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 6131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public CellLayout(Context context) { 6231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this(context, null); 6331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 6431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 6531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public CellLayout(Context context, AttributeSet attrs) { 6631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this(context, attrs, 0); 6731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 6831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 6931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public CellLayout(Context context, AttributeSet attrs, int defStyle) { 7031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project super(context, attrs, defStyle); 7131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CellLayout, defStyle, 0); 7231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 7331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mCellWidth = a.getDimensionPixelSize(R.styleable.CellLayout_cellWidth, 10); 7431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mCellHeight = a.getDimensionPixelSize(R.styleable.CellLayout_cellHeight, 10); 7531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 7631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mLongAxisStartPadding = 7731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project a.getDimensionPixelSize(R.styleable.CellLayout_longAxisStartPadding, 10); 7831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mLongAxisEndPadding = 7931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project a.getDimensionPixelSize(R.styleable.CellLayout_longAxisEndPadding, 10); 8031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mShortAxisStartPadding = 8131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project a.getDimensionPixelSize(R.styleable.CellLayout_shortAxisStartPadding, 10); 8231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mShortAxisEndPadding = 8331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project a.getDimensionPixelSize(R.styleable.CellLayout_shortAxisEndPadding, 10); 8431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 8531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mShortAxisCells = a.getInt(R.styleable.CellLayout_shortAxisCells, 4); 8631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mLongAxisCells = a.getInt(R.styleable.CellLayout_longAxisCells, 4); 8731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 8831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project a.recycle(); 8931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 9031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project setAlwaysDrawnWithCacheEnabled(false); 9131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 9231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (mOccupied == null) { 9331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (mPortrait) { 9431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mOccupied = new boolean[mShortAxisCells][mLongAxisCells]; 9531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } else { 9631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mOccupied = new boolean[mLongAxisCells][mShortAxisCells]; 9731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 9831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 9931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 10031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 10183f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey @Override 10283f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey public void cancelLongPress() { 10383f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey super.cancelLongPress(); 10483f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey 10583f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey // Cancel long press for all children 10683f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey final int count = getChildCount(); 10783f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey for (int i = 0; i < count; i++) { 10883f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey final View child = getChildAt(i); 10983f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey child.cancelLongPress(); 11083f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey } 11183f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey } 11283f111d129fcb8c50b35da789f0d75604b9c0864Jeff Sharkey 11331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int getCountX() { 11431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return mPortrait ? mShortAxisCells : mLongAxisCells; 11531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 11631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 11731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int getCountY() { 11831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return mPortrait ? mLongAxisCells : mShortAxisCells; 11931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 12031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 12131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 12231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public void addView(View child, int index, ViewGroup.LayoutParams params) { 12331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // Generate an id for each view, this assumes we have at most 256x256 cells 12431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // per workspace screen 12531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final LayoutParams cellParams = (LayoutParams) params; 12631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project child.setId(((getId() & 0xFF) << 16) | 12731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project (cellParams.cellX & 0xFF) << 8 | (cellParams.cellY & 0xFF)); 12831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 12931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project super.addView(child, index, params); 13031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 13131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 13231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 13331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public void requestChildFocus(View child, View focused) { 13431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project super.requestChildFocus(child, focused); 13531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (child != null) { 13631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project Rect r = new Rect(); 13731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project child.getDrawingRect(r); 13831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project requestRectangleOnScreen(r); 13931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 14031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 14131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 14231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 14331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected void onAttachedToWindow() { 14431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project super.onAttachedToWindow(); 14531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mCellInfo.screen = ((ViewGroup) getParent()).indexOfChild(this); 14631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 14731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 14831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 14931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public boolean onInterceptTouchEvent(MotionEvent ev) { 15031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int action = ev.getAction(); 15131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final CellInfo cellInfo = mCellInfo; 15231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 15331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (action == MotionEvent.ACTION_DOWN) { 15431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final Rect frame = mRect; 15531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int x = (int) ev.getX() + mScrollX; 15631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int y = (int) ev.getY() + mScrollY; 15731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int count = getChildCount(); 15831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 15931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project boolean found = false; 16031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int i = count - 1; i >= 0; i--) { 16131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final View child = getChildAt(i); 16231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 16331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if ((child.getVisibility()) == VISIBLE || child.getAnimation() != null) { 16431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project child.getHitRect(frame); 16531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (frame.contains(x, y)) { 16631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 16731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.cell = child; 16831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.cellX = lp.cellX; 16931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.cellY = lp.cellY; 17031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.spanX = lp.cellHSpan; 17131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.spanY = lp.cellVSpan; 17231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.valid = true; 17331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project found = true; 17431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mDirtyTag = false; 17531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project break; 17631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 17731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 17831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 17931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 18031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (!found) { 18131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int cellXY[] = mCellXY; 18231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project pointToCellExact(x, y, cellXY); 18331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 18431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final boolean portrait = mPortrait; 18531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int xCount = portrait ? mShortAxisCells : mLongAxisCells; 18631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int yCount = portrait ? mLongAxisCells : mShortAxisCells; 18731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 18831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final boolean[][] occupied = mOccupied; 18970864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey findOccupiedCells(xCount, yCount, occupied, null); 19031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 19131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.cell = null; 19231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.cellX = cellXY[0]; 19331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.cellY = cellXY[1]; 19431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.spanX = 1; 19531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.spanY = 1; 19631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.valid = cellXY[0] >= 0 && cellXY[1] >= 0 && cellXY[0] < xCount && 19731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellXY[1] < yCount && !occupied[cellXY[0]][cellXY[1]]; 19831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 19931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // Instead of finding the interesting vacant cells here, wait until a 20031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // caller invokes getTag() to retrieve the result. Finding the vacant 20131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // cells is a bit expensive and can generate many new objects, it's 20231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // therefore better to defer it until we know we actually need it. 20331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 20431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mDirtyTag = true; 20531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 20631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project setTag(cellInfo); 20731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } else if (action == MotionEvent.ACTION_UP) { 20831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.cell = null; 20931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.cellX = -1; 21031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.cellY = -1; 21131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.spanX = 0; 21231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.spanY = 0; 21331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.valid = false; 21431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mDirtyTag = false; 21531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project setTag(cellInfo); 21631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 21731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 21831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return false; 21931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 22031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 22131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 22231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public CellInfo getTag() { 22331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final CellInfo info = (CellInfo) super.getTag(); 22431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (mDirtyTag && info.valid) { 22531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final boolean portrait = mPortrait; 22631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int xCount = portrait ? mShortAxisCells : mLongAxisCells; 22731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int yCount = portrait ? mLongAxisCells : mShortAxisCells; 22831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 22931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final boolean[][] occupied = mOccupied; 23070864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey findOccupiedCells(xCount, yCount, occupied, null); 23131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 23231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project findIntersectingVacantCells(info, info.cellX, info.cellY, xCount, yCount, occupied); 23331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 23431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mDirtyTag = false; 23531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 23631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return info; 23731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 23831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 23931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private static void findIntersectingVacantCells(CellInfo cellInfo, int x, int y, 24031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int xCount, int yCount, boolean[][] occupied) { 24131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 24231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.maxVacantSpanX = Integer.MIN_VALUE; 24331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.maxVacantSpanXSpanY = Integer.MIN_VALUE; 24431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.maxVacantSpanY = Integer.MIN_VALUE; 24531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.maxVacantSpanYSpanX = Integer.MIN_VALUE; 24631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.clearVacantCells(); 24731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 24831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (occupied[x][y]) { 24931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return; 25031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 25131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 25231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.current.set(x, y, x, y); 25331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 25431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project findVacantCell(cellInfo.current, xCount, yCount, occupied, cellInfo); 25531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 25631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 25731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private static void findVacantCell(Rect current, int xCount, int yCount, boolean[][] occupied, 25831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project CellInfo cellInfo) { 25931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 26031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project addVacantCell(current, cellInfo); 26131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 26231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (current.left > 0) { 26331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (isColumnEmpty(current.left - 1, current.top, current.bottom, occupied)) { 26431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project current.left--; 26531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project findVacantCell(current, xCount, yCount, occupied, cellInfo); 26631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project current.left++; 26731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 26831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 26931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 27031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (current.right < xCount - 1) { 27131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (isColumnEmpty(current.right + 1, current.top, current.bottom, occupied)) { 27231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project current.right++; 27331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project findVacantCell(current, xCount, yCount, occupied, cellInfo); 27431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project current.right--; 27531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 27631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 27731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 27831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (current.top > 0) { 27931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (isRowEmpty(current.top - 1, current.left, current.right, occupied)) { 28031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project current.top--; 28131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project findVacantCell(current, xCount, yCount, occupied, cellInfo); 28231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project current.top++; 28331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 28431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 28531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 28631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (current.bottom < yCount - 1) { 28731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (isRowEmpty(current.bottom + 1, current.left, current.right, occupied)) { 28831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project current.bottom++; 28931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project findVacantCell(current, xCount, yCount, occupied, cellInfo); 29031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project current.bottom--; 29131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 29231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 29331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 29431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 29531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private static void addVacantCell(Rect current, CellInfo cellInfo) { 29631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project CellInfo.VacantCell cell = CellInfo.VacantCell.acquire(); 29731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cell.cellX = current.left; 29831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cell.cellY = current.top; 29931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cell.spanX = current.right - current.left + 1; 30031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cell.spanY = current.bottom - current.top + 1; 30131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (cell.spanX > cellInfo.maxVacantSpanX) { 30231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.maxVacantSpanX = cell.spanX; 30331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.maxVacantSpanXSpanY = cell.spanY; 30431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 30531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (cell.spanY > cellInfo.maxVacantSpanY) { 30631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.maxVacantSpanY = cell.spanY; 30731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.maxVacantSpanYSpanX = cell.spanX; 30831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 30931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.vacantCells.add(cell); 31031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 31131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 31231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private static boolean isColumnEmpty(int x, int top, int bottom, boolean[][] occupied) { 31331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int y = top; y <= bottom; y++) { 31431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (occupied[x][y]) { 31531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return false; 31631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 31731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 31831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return true; 31931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 32031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 32131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private static boolean isRowEmpty(int y, int left, int right, boolean[][] occupied) { 32231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int x = left; x <= right; x++) { 32331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (occupied[x][y]) { 32431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return false; 32531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 32631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 32731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return true; 32831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 32931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 33070864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey CellInfo findAllVacantCells(boolean[] occupiedCells, View ignoreView) { 33131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final boolean portrait = mPortrait; 33231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int xCount = portrait ? mShortAxisCells : mLongAxisCells; 33331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int yCount = portrait ? mLongAxisCells : mShortAxisCells; 33431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 33531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project boolean[][] occupied = mOccupied; 33631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 33731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (occupiedCells != null) { 33831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int y = 0; y < yCount; y++) { 33931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int x = 0; x < xCount; x++) { 34031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project occupied[x][y] = occupiedCells[y * xCount + x]; 34131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 34231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 34331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } else { 34470864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey findOccupiedCells(xCount, yCount, occupied, ignoreView); 34531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 34631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 34731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project CellInfo cellInfo = new CellInfo(); 34831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 34931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.cellX = -1; 35031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.cellY = -1; 35131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.spanY = 0; 35231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.spanX = 0; 35331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.maxVacantSpanX = Integer.MIN_VALUE; 35431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.maxVacantSpanXSpanY = Integer.MIN_VALUE; 35531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.maxVacantSpanY = Integer.MIN_VALUE; 35631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.maxVacantSpanYSpanX = Integer.MIN_VALUE; 35731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.screen = mCellInfo.screen; 35831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 35931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project Rect current = cellInfo.current; 36031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 36131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int x = 0; x < xCount; x++) { 36231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int y = 0; y < yCount; y++) { 36331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (!occupied[x][y]) { 36431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project current.set(x, y, x, y); 36531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project findVacantCell(current, xCount, yCount, occupied, cellInfo); 36631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project occupied[x][y] = true; 36731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 36831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 36931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 37031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 37131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellInfo.valid = cellInfo.vacantCells.size() > 0; 37231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 37331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // Assume the caller will perform their own cell searching, otherwise we 37431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // risk causing an unnecessary rebuild after findCellForSpan() 37531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 37631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return cellInfo; 37731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 37831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 37931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 38031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Given a point, return the cell that strictly encloses that point 38131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param x X coordinate of the point 38231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param y Y coordinate of the point 38331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param result Array of 2 ints to hold the x and y coordinate of the cell 38431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 38531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project void pointToCellExact(int x, int y, int[] result) { 38631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final boolean portrait = mPortrait; 38731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 38831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int hStartPadding = portrait ? mShortAxisStartPadding : mLongAxisStartPadding; 38931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int vStartPadding = portrait ? mLongAxisStartPadding : mShortAxisStartPadding; 39031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 39131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project result[0] = (x - hStartPadding) / (mCellWidth + mWidthGap); 39231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project result[1] = (y - vStartPadding) / (mCellHeight + mHeightGap); 39331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 39431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int xAxis = portrait ? mShortAxisCells : mLongAxisCells; 39531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int yAxis = portrait ? mLongAxisCells : mShortAxisCells; 39631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 39731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (result[0] < 0) result[0] = 0; 39831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (result[0] >= xAxis) result[0] = xAxis - 1; 39931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (result[1] < 0) result[1] = 0; 40031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (result[1] >= yAxis) result[1] = yAxis - 1; 40131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 40231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 40331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 40431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Given a point, return the cell that most closely encloses that point 40531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param x X coordinate of the point 40631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param y Y coordinate of the point 40731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param result Array of 2 ints to hold the x and y coordinate of the cell 40831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 40931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project void pointToCellRounded(int x, int y, int[] result) { 41031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project pointToCellExact(x + (mCellWidth / 2), y + (mCellHeight / 2), result); 41131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 41231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 41331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 41431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Given a cell coordinate, return the point that represents the upper left corner of that cell 41531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 41631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param cellX X coordinate of the cell 41731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param cellY Y coordinate of the cell 41831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 41931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param result Array of 2 ints to hold the x and y coordinate of the point 42031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 42131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project void cellToPoint(int cellX, int cellY, int[] result) { 42231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final boolean portrait = mPortrait; 42331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 42431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int hStartPadding = portrait ? mShortAxisStartPadding : mLongAxisStartPadding; 42531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int vStartPadding = portrait ? mLongAxisStartPadding : mShortAxisStartPadding; 42631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 42731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 42831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project result[0] = hStartPadding + cellX * (mCellWidth + mWidthGap); 42931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project result[1] = vStartPadding + cellY * (mCellHeight + mHeightGap); 43031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 43131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 43231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 43331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 43431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // TODO: currently ignoring padding 43531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 43631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec); 43731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec); 43831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 43931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec); 44031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec); 44131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 44231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (widthSpecMode == MeasureSpec.UNSPECIFIED || heightSpecMode == MeasureSpec.UNSPECIFIED) { 44331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project throw new RuntimeException("CellLayout cannot have UNSPECIFIED dimensions"); 44431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 44531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 44631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int shortAxisCells = mShortAxisCells; 44731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int longAxisCells = mLongAxisCells; 44831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int longAxisStartPadding = mLongAxisStartPadding; 44931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int longAxisEndPadding = mLongAxisEndPadding; 45031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int shortAxisStartPadding = mShortAxisStartPadding; 45131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int shortAxisEndPadding = mShortAxisEndPadding; 45231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int cellWidth = mCellWidth; 45331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int cellHeight = mCellHeight; 45431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 45531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mPortrait = heightSpecSize > widthSpecSize; 45631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 45731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int numShortGaps = shortAxisCells - 1; 45831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int numLongGaps = longAxisCells - 1; 45931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 46031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (mPortrait) { 46131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int vSpaceLeft = heightSpecSize - longAxisStartPadding - longAxisEndPadding 46231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project - (cellHeight * longAxisCells); 46331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mHeightGap = vSpaceLeft / numLongGaps; 46431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 46531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int hSpaceLeft = widthSpecSize - shortAxisStartPadding - shortAxisEndPadding 46631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project - (cellWidth * shortAxisCells); 46731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (numShortGaps > 0) { 46831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mWidthGap = hSpaceLeft / numShortGaps; 46931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } else { 47031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mWidthGap = 0; 47131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 47231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } else { 47331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int hSpaceLeft = widthSpecSize - longAxisStartPadding - longAxisEndPadding 47431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project - (cellWidth * longAxisCells); 47531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mWidthGap = hSpaceLeft / numLongGaps; 47631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 47731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int vSpaceLeft = heightSpecSize - shortAxisStartPadding - shortAxisEndPadding 47831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project - (cellHeight * shortAxisCells); 47931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (numShortGaps > 0) { 48031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mHeightGap = vSpaceLeft / numShortGaps; 48131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } else { 48231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mHeightGap = 0; 48331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 48431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 48531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 48631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int count = getChildCount(); 48731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 48831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int i = 0; i < count; i++) { 48931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project View child = getChildAt(i); 49031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project LayoutParams lp = (LayoutParams) child.getLayoutParams(); 49131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 49231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (mPortrait) { 49331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project lp.setup(cellWidth, cellHeight, mWidthGap, mHeightGap, shortAxisStartPadding, 49431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project longAxisStartPadding); 49531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } else { 49631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project lp.setup(cellWidth, cellHeight, mWidthGap, mHeightGap, longAxisStartPadding, 49731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project shortAxisStartPadding); 49831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 49931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 50031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(lp.width, MeasureSpec.EXACTLY); 50131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int childheightMeasureSpec = 50231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY); 50331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project child.measure(childWidthMeasureSpec, childheightMeasureSpec); 50431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 50531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 50631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project setMeasuredDimension(widthSpecSize, heightSpecSize); 50731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 50831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 50931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 51031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected void onLayout(boolean changed, int l, int t, int r, int b) { 51131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int count = getChildCount(); 51231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 51331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int i = 0; i < count; i++) { 51431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project View child = getChildAt(i); 51531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (child.getVisibility() != GONE) { 51631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 51731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams(); 51831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 51931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int childLeft = lp.x; 52031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int childTop = lp.y; 52131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project child.layout(childLeft, childTop, childLeft + lp.width, childTop + lp.height); 52231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 52331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 52431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 52531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 52631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 52731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected void setChildrenDrawingCacheEnabled(boolean enabled) { 52831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int count = getChildCount(); 52931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int i = 0; i < count; i++) { 53031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final View view = getChildAt(i); 53131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project view.setDrawingCacheEnabled(enabled); 53231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // Update the drawing caches 533806b0f3fbf02171c691b1f9d48e51a47760565b3Romain Guy view.buildDrawingCache(true); 53431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 53531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 53631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 53731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 53831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected void setChildrenDrawnWithCacheEnabled(boolean enabled) { 53931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project super.setChildrenDrawnWithCacheEnabled(enabled); 54031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 54131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 54231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 54370864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * Find a vacant area that will fit the given bounds nearest the requested 54470864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * cell location. Uses Euclidean distance to score multiple vacant areas. 54570864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * 54651afc022fa76c79f0d1ece470ddc126c08fea8a4Romain Guy * @param pixelX The X location at which you want to search for a vacant area. 54751afc022fa76c79f0d1ece470ddc126c08fea8a4Romain Guy * @param pixelY The Y location at which you want to search for a vacant area. 54870864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * @param spanX Horizontal span of the object. 54970864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * @param spanY Vertical span of the object. 55070864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * @param vacantCells Pre-computed set of vacant cells to search. 55170864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * @param recycle Previously returned value to possibly recycle. 55270864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * @return The X, Y cell of a vacant area that can contain this object, 55370864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * nearest the requested location. 55431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 55570864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey int[] findNearestVacantArea(int pixelX, int pixelY, int spanX, int spanY, 55670864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey CellInfo vacantCells, int[] recycle) { 55770864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey 55870864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey // Keep track of best-scoring drop area 55970864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey final int[] bestXY = recycle != null ? recycle : new int[2]; 56070864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey final int[] cellXY = mCellXY; 56170864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey double bestDistance = Double.MAX_VALUE; 56270864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey 56370864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey // Bail early if vacant cells aren't valid 56470864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey if (!vacantCells.valid) { 56570864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey return null; 56631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 56731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 56870864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey // Look across all vacant cells for best fit 56970864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey final int size = vacantCells.vacantCells.size(); 57070864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey for (int i = 0; i < size; i++) { 57170864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey final CellInfo.VacantCell cell = vacantCells.vacantCells.get(i); 57270864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey 57370864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey // Reject if vacant cell isn't our exact size 57470864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey if (cell.spanX != spanX || cell.spanY != spanY) { 57531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project continue; 57631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 57770864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey 57870864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey // Score is center distance from requested pixel 57970864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey cellToPoint(cell.cellX, cell.cellY, cellXY); 58070864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey 58170864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey double distance = Math.sqrt(Math.pow(cellXY[0] - pixelX, 2) + 58270864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey Math.pow(cellXY[1] - pixelY, 2)); 58370864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey if (distance <= bestDistance) { 58470864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey bestDistance = distance; 58570864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey bestXY[0] = cell.cellX; 58670864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey bestXY[1] = cell.cellY; 58731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 58831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 58931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 59070864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey // Return null if no suitable location found 59170864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey if (bestDistance < Double.MAX_VALUE) { 59270864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey return bestXY; 59370864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey } else { 59470864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey return null; 59570864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey } 59631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 59770864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey 59831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 59931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Drop a child at the specified position 60031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 60131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param child The child that is being dropped 60270864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey * @param targetXY Destination area to move to 60331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 60470864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey void onDropChild(View child, int[] targetXY) { 605d94533d04a5f8f5485f106d10af60169857ea899Romain Guy if (child != null) { 606d94533d04a5f8f5485f106d10af60169857ea899Romain Guy LayoutParams lp = (LayoutParams) child.getLayoutParams(); 607d94533d04a5f8f5485f106d10af60169857ea899Romain Guy lp.cellX = targetXY[0]; 608d94533d04a5f8f5485f106d10af60169857ea899Romain Guy lp.cellY = targetXY[1]; 609d94533d04a5f8f5485f106d10af60169857ea899Romain Guy lp.isDragging = false; 610d94533d04a5f8f5485f106d10af60169857ea899Romain Guy mDragRect.setEmpty(); 611d94533d04a5f8f5485f106d10af60169857ea899Romain Guy child.requestLayout(); 612d94533d04a5f8f5485f106d10af60169857ea899Romain Guy invalidate(); 613d94533d04a5f8f5485f106d10af60169857ea899Romain Guy } 61431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 61531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 61631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project void onDropAborted(View child) { 61731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (child != null) { 61831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project ((LayoutParams) child.getLayoutParams()).isDragging = false; 61931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project invalidate(); 62031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 62131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mDragRect.setEmpty(); 62231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 62331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 62431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 62531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Start dragging the specified child 62631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 62731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param child The child that is being dragged 62831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 62931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project void onDragChild(View child) { 63031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project LayoutParams lp = (LayoutParams) child.getLayoutParams(); 63131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project lp.isDragging = true; 63231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project mDragRect.setEmpty(); 63331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 63431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 63531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 63631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Drag a child over the specified position 63731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 63831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param child The child that is being dropped 63931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param cellX The child's new x cell location 64031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param cellY The child's new y cell location 64131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 64231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project void onDragOverChild(View child, int cellX, int cellY) { 64331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int[] cellXY = mCellXY; 64431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project pointToCellRounded(cellX, cellY, cellXY); 64531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project LayoutParams lp = (LayoutParams) child.getLayoutParams(); 64631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellToRect(cellXY[0], cellXY[1], lp.cellHSpan, lp.cellVSpan, mDragRect); 64731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project invalidate(); 64831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 64931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 65031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 65131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Computes a bounding rectangle for a range of cells 65231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 65331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param cellX X coordinate of upper left corner expressed as a cell position 65431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param cellY Y coordinate of upper left corner expressed as a cell position 65531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param cellHSpan Width in cells 65631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param cellVSpan Height in cells 65731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param dragRect Rectnagle into which to put the results 65831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 65931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public void cellToRect(int cellX, int cellY, int cellHSpan, int cellVSpan, RectF dragRect) { 66031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final boolean portrait = mPortrait; 66131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int cellWidth = mCellWidth; 66231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int cellHeight = mCellHeight; 66331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int widthGap = mWidthGap; 66431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int heightGap = mHeightGap; 66531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 66631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int hStartPadding = portrait ? mShortAxisStartPadding : mLongAxisStartPadding; 66731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int vStartPadding = portrait ? mLongAxisStartPadding : mShortAxisStartPadding; 66831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 66931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int width = cellHSpan * cellWidth + ((cellHSpan - 1) * widthGap); 67031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int height = cellVSpan * cellHeight + ((cellVSpan - 1) * heightGap); 67131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 67231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int x = hStartPadding + cellX * (cellWidth + widthGap); 67331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int y = vStartPadding + cellY * (cellHeight + heightGap); 67431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 67531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project dragRect.set(x, y, x + width, y + height); 67631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 67731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 67831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 67931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Computes the required horizontal and vertical cell spans to always 68031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * fit the given rectangle. 68131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 68231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param width Width in pixels 68331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param height Height in pixels 68431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 68531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public int[] rectToCell(int width, int height) { 68631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // Always assume we're working with the smallest span to make sure we 68731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // reserve enough space in both orientations. 68831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int actualWidth = mCellWidth + mWidthGap; 68931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int actualHeight = mCellHeight + mHeightGap; 69031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int smallerSize = Math.min(actualWidth, actualHeight); 69131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 69231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // Always round up to next largest cell 69331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int spanX = (width + smallerSize) / smallerSize; 69431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int spanY = (height + smallerSize) / smallerSize; 69531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return new int[] { spanX, spanY }; 69631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 69731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 69831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 69931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Find the first vacant cell, if there is one. 70031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 70131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param vacant Holds the x and y coordinate of the vacant cell 70231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param spanX Horizontal cell span. 70331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param spanY Vertical cell span. 70431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 70531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @return True if a vacant cell was found 70631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 70731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public boolean getVacantCell(int[] vacant, int spanX, int spanY) { 70831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final boolean portrait = mPortrait; 70931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int xCount = portrait ? mShortAxisCells : mLongAxisCells; 71031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int yCount = portrait ? mLongAxisCells : mShortAxisCells; 71131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final boolean[][] occupied = mOccupied; 71231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 71370864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey findOccupiedCells(xCount, yCount, occupied, null); 71431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 71531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return findVacantCell(vacant, spanX, spanY, xCount, yCount, occupied); 71631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 71731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 71831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project static boolean findVacantCell(int[] vacant, int spanX, int spanY, 71931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int xCount, int yCount, boolean[][] occupied) { 72031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 72131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int x = 0; x < xCount; x++) { 72231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int y = 0; y < yCount; y++) { 72331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project boolean available = !occupied[x][y]; 72431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectout: for (int i = x; i < x + spanX - 1 && x < xCount; i++) { 72531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int j = y; j < y + spanY - 1 && y < yCount; j++) { 72631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project available = available && !occupied[i][j]; 72731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (!available) break out; 72831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 72931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 73031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 73131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (available) { 73231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project vacant[0] = x; 73331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project vacant[1] = y; 73431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return true; 73531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 73631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 73731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 73831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 73931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return false; 74031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 74131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 74231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project boolean[] getOccupiedCells() { 74331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final boolean portrait = mPortrait; 74431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int xCount = portrait ? mShortAxisCells : mLongAxisCells; 74531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int yCount = portrait ? mLongAxisCells : mShortAxisCells; 74631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final boolean[][] occupied = mOccupied; 74731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 74870864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey findOccupiedCells(xCount, yCount, occupied, null); 74931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 75031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final boolean[] flat = new boolean[xCount * yCount]; 75131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int y = 0; y < yCount; y++) { 75231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int x = 0; x < xCount; x++) { 75331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project flat[y * xCount + x] = occupied[x][y]; 75431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 75531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 75631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 75731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return flat; 75831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 75931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 76070864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey private void findOccupiedCells(int xCount, int yCount, boolean[][] occupied, View ignoreView) { 76131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int x = 0; x < xCount; x++) { 76231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int y = 0; y < yCount; y++) { 76331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project occupied[x][y] = false; 76431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 76531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 76631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 76731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int count = getChildCount(); 76831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int i = 0; i < count; i++) { 76931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project View child = getChildAt(i); 77070864289fba6daf07b8de98524cdfb765a62552dJeff Sharkey if (child instanceof Folder || child.equals(ignoreView)) { 77131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project continue; 77231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 77331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project LayoutParams lp = (LayoutParams) child.getLayoutParams(); 77431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 77531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int x = lp.cellX; x < lp.cellX + lp.cellHSpan && x < xCount; x++) { 77631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int y = lp.cellY; y < lp.cellY + lp.cellVSpan && y < yCount; y++) { 77731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project occupied[x][y] = true; 77831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 77931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 78031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 78131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 78231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 78331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 78431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) { 78531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return new CellLayout.LayoutParams(getContext(), attrs); 78631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 78731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 78831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 78931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { 79031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return p instanceof CellLayout.LayoutParams; 79131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 79231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 79331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 79431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { 79531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return new CellLayout.LayoutParams(p); 79631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 79731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 79831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public static class LayoutParams extends ViewGroup.MarginLayoutParams { 79931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 80031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Horizontal location of the item in the grid. 80131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 80231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @ViewDebug.ExportedProperty 80331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public int cellX; 80431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 80531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 80631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Vertical location of the item in the grid. 80731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 80831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @ViewDebug.ExportedProperty 80931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public int cellY; 81031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 81131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 81231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Number of cells spanned horizontally by the item. 81331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 81431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @ViewDebug.ExportedProperty 81531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public int cellHSpan; 81631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 81731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 81831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Number of cells spanned vertically by the item. 81931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 82031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @ViewDebug.ExportedProperty 82131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public int cellVSpan; 82231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 82331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 82431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Is this item currently being dragged 82531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 82631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public boolean isDragging; 82731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 82831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // X coordinate of the view in the layout. 82931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @ViewDebug.ExportedProperty 83031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int x; 83131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // Y coordinate of the view in the layout. 83231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @ViewDebug.ExportedProperty 83331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int y; 83431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 83531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public LayoutParams(Context c, AttributeSet attrs) { 83631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project super(c, attrs); 83731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellHSpan = 1; 83831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellVSpan = 1; 83931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 84031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 84131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public LayoutParams(ViewGroup.LayoutParams source) { 84231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project super(source); 84331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellHSpan = 1; 84431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellVSpan = 1; 84531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 84631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 84731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public LayoutParams(int cellX, int cellY, int cellHSpan, int cellVSpan) { 84831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project super(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT); 84931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this.cellX = cellX; 85031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this.cellY = cellY; 85131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this.cellHSpan = cellHSpan; 85231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this.cellVSpan = cellVSpan; 85331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 85431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 85531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public void setup(int cellWidth, int cellHeight, int widthGap, int heightGap, 85631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int hStartPadding, int vStartPadding) { 85731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 85831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int myCellHSpan = cellHSpan; 85931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int myCellVSpan = cellVSpan; 86031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int myCellX = cellX; 86131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int myCellY = cellY; 86231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 86331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project width = myCellHSpan * cellWidth + ((myCellHSpan - 1) * widthGap) - 86431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project leftMargin - rightMargin; 86531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project height = myCellVSpan * cellHeight + ((myCellVSpan - 1) * heightGap) - 86631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project topMargin - bottomMargin; 86731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 86831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project x = hStartPadding + myCellX * (cellWidth + widthGap) + leftMargin; 86931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project y = vStartPadding + myCellY * (cellHeight + heightGap) + topMargin; 87031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 87131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 87231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 87331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project static final class CellInfo implements ContextMenu.ContextMenuInfo { 87431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 87531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * See View.AttachInfo.InvalidateInfo for futher explanations about 87631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * the recycling mechanism. In this case, we recycle the vacant cells 87731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * instances because up to several hundreds can be instanciated when 87831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * the user long presses an empty cell. 87931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 88031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project static final class VacantCell { 88131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int cellX; 88231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int cellY; 88331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int spanX; 88431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int spanY; 88531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 88631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // We can create up to 523 vacant cells on a 4x4 grid, 100 seems 88731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // like a reasonable compromise given the size of a VacantCell and 88831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // the fact that the user is not likely to touch an empty 4x4 grid 88931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // very often 89031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private static final int POOL_LIMIT = 100; 89131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private static final Object sLock = new Object(); 89231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 89331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private static int sAcquiredCount = 0; 89431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private static VacantCell sRoot; 89531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 89631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private VacantCell next; 89731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 89831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project static VacantCell acquire() { 89931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project synchronized (sLock) { 90031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (sRoot == null) { 90131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return new VacantCell(); 90231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 90331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 90431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project VacantCell info = sRoot; 90531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project sRoot = info.next; 90631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project sAcquiredCount--; 90731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 90831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return info; 90931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 91031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 91131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 91231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project void release() { 91331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project synchronized (sLock) { 91431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (sAcquiredCount < POOL_LIMIT) { 91531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project sAcquiredCount++; 91631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project next = sRoot; 91731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project sRoot = this; 91831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 91931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 92031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 92131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 92231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 92331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public String toString() { 92431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return "VacantCell[x=" + cellX + ", y=" + cellY + ", spanX=" + spanX + 92531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project ", spanY=" + spanY + "]"; 92631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 92731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 92831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 92931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project View cell; 93031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int cellX; 93131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int cellY; 93231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int spanX; 93331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int spanY; 93431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int screen; 93531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project boolean valid; 93631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 93731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final ArrayList<VacantCell> vacantCells = new ArrayList<VacantCell>(VacantCell.POOL_LIMIT); 93831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int maxVacantSpanX; 93931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int maxVacantSpanXSpanY; 94031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int maxVacantSpanY; 94131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int maxVacantSpanYSpanX; 94231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final Rect current = new Rect(); 94331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 9444c58c485d8c02f8ca7e8b4d93140440f6a3a5131Romain Guy void clearVacantCells() { 94531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final ArrayList<VacantCell> list = vacantCells; 94631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int count = list.size(); 94731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 94831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int i = 0; i < count; i++) list.get(i).release(); 94931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 95031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project list.clear(); 95131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 95231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 95331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project void findVacantCellsFromOccupied(boolean[] occupied, int xCount, int yCount) { 95431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (cellX < 0 || cellY < 0) { 95531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project maxVacantSpanX = maxVacantSpanXSpanY = Integer.MIN_VALUE; 95631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project maxVacantSpanY = maxVacantSpanYSpanX = Integer.MIN_VALUE; 95731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project clearVacantCells(); 95831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return; 95931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 96031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 96131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final boolean[][] unflattened = new boolean[xCount][yCount]; 96231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int y = 0; y < yCount; y++) { 96331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int x = 0; x < xCount; x++) { 96431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project unflattened[x][y] = occupied[y * xCount + x]; 96531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 96631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 96731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project CellLayout.findIntersectingVacantCells(this, cellX, cellY, xCount, yCount, unflattened); 96831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 96931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 97031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 97131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * This method can be called only once! Calling #findVacantCellsFromOccupied will 97231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * restore the ability to call this method. 97331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 97431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Finds the upper-left coordinate of the first rectangle in the grid that can 97531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * hold a cell of the specified dimensions. 97631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 97731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param cellXY The array that will contain the position of a vacant cell if such a cell 97831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * can be found. 97931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param spanX The horizontal span of the cell we want to find. 98031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @param spanY The vertical span of the cell we want to find. 98131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 98231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * @return True if a vacant cell of the specified dimension was found, false otherwise. 98331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 98431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project boolean findCellForSpan(int[] cellXY, int spanX, int spanY) { 9854c58c485d8c02f8ca7e8b4d93140440f6a3a5131Romain Guy return findCellForSpan(cellXY, spanX, spanY, true); 9864c58c485d8c02f8ca7e8b4d93140440f6a3a5131Romain Guy } 9874c58c485d8c02f8ca7e8b4d93140440f6a3a5131Romain Guy 9884c58c485d8c02f8ca7e8b4d93140440f6a3a5131Romain Guy boolean findCellForSpan(int[] cellXY, int spanX, int spanY, boolean clear) { 98931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final ArrayList<VacantCell> list = vacantCells; 99031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project final int count = list.size(); 99131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 99231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project boolean found = false; 99331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 99431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (this.spanX >= spanX && this.spanY >= spanY) { 99531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellXY[0] = cellX; 99631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellXY[1] = cellY; 99731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project found = true; 99831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 99931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 100031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // Look for an exact match first 100131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int i = 0; i < count; i++) { 100231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project VacantCell cell = list.get(i); 100331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (cell.spanX == spanX && cell.spanY == spanY) { 100431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellXY[0] = cell.cellX; 100531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellXY[1] = cell.cellY; 100631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project found = true; 100731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project break; 100831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 100931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 101031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 101131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project // Look for the first cell large enough 101231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int i = 0; i < count; i++) { 101331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project VacantCell cell = list.get(i); 101431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (cell.spanX >= spanX && cell.spanY >= spanY) { 101531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellXY[0] = cell.cellX; 101631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project cellXY[1] = cell.cellY; 101731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project found = true; 101831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project break; 101931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 102031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 102131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 10224c58c485d8c02f8ca7e8b4d93140440f6a3a5131Romain Guy if (clear) clearVacantCells(); 102331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 102431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return found; 102531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 102631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 102731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 102831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public String toString() { 102931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return "Cell[view=" + (cell == null ? "null" : cell.getClass()) + ", x=" + cellX + 103031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project ", y=" + cellY + "]"; 103131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 103231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 103331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project} 103431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 103531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 1036