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