19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2006 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage com.android.internal.view.menu;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.internal.view.menu.MenuBuilder.ItemInvoker;
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.Resources;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.TypedArray;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Canvas;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Rect;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.drawable.Drawable;
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Parcel;
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Parcelable;
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.AttributeSet;
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.KeyEvent;
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.View;
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.ViewConfiguration;
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.ViewGroup;
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.LayoutInflater;
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList;
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The icon menu view is an icon-based menu usually with a subset of all the menu items.
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * It is opened as the default menu, and shows either the first five or all six of the menu items
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * with text and icon.  In the situation of there being more than six items, the first five items
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * will be accompanied with a 'More' button that opens an {@link ExpandedMenuView} which lists
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * all the menu items.
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#IconMenuView_rowHeight
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#IconMenuView_maxRows
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#IconMenuView_maxItemsPerRow
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @hide
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic final class IconMenuView extends ViewGroup implements ItemInvoker, MenuView, Runnable {
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int ITEM_CAPTION_CYCLE_DELAY = 1000;
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private MenuBuilder mMenu;
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Height of each row */
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mRowHeight;
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Maximum number of rows to be shown */
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mMaxRows;
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Maximum number of items to show in the icon menu. */
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mMaxItems;
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Maximum number of items per row */
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mMaxItemsPerRow;
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Actual number of items (the 'More' view does not count as an item) shown */
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mNumActualItemsShown;
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Divider that is drawn between all rows */
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private Drawable mHorizontalDivider;
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Height of the horizontal divider */
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mHorizontalDividerHeight;
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Set of horizontal divider positions where the horizontal divider will be drawn */
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private ArrayList<Rect> mHorizontalDividerRects;
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Divider that is drawn between all columns */
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private Drawable mVerticalDivider;
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Width of the vertical divider */
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mVerticalDividerWidth;
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Set of vertical divider positions where the vertical divider will be drawn */
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private ArrayList<Rect> mVerticalDividerRects;
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Icon for the 'More' button */
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private Drawable mMoreIcon;
83696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Background of each item (should contain the selected and focused states) */
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private Drawable mItemBackground;
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Default animations for this menu */
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mAnimations;
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Whether this IconMenuView has stale children and needs to update them.
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Set true by {@link #markStaleChildren()} and reset to false by
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * {@link #onMeasure(int, int)}
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mHasStaleChildren;
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Longpress on MENU (while this is shown) switches to shortcut caption
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * mode. When the user releases the longpress, we do not want to pass the
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * key-up event up since that will dismiss the menu.
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mMenuBeingLongpressed = false;
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * While {@link #mMenuBeingLongpressed}, we toggle the children's caption
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * mode between each's title and its shortcut. This is the last caption mode
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * we broadcasted to children.
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mLastChildrenCaptionMode;
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The layout to use for menu items. Each index is the row number (0 is the
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * top-most). Each value contains the number of items in that row.
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The length of this array should not be used to get the number of rows in
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * the current layout, instead use {@link #mLayoutNumRows}.
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int[] mLayout;
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The number of rows in the current layout.
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mLayoutNumRows;
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Instantiates the IconMenuView that is linked with the provided MenuBuilder.
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public IconMenuView(Context context, AttributeSet attrs) {
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super(context, attrs);
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        TypedArray a =
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.IconMenuView, 0, 0);
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mRowHeight = a.getDimensionPixelSize(com.android.internal.R.styleable.IconMenuView_rowHeight, 64);
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mMaxRows = a.getInt(com.android.internal.R.styleable.IconMenuView_maxRows, 2);
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mMaxItems = a.getInt(com.android.internal.R.styleable.IconMenuView_maxItems, 6);
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mMaxItemsPerRow = a.getInt(com.android.internal.R.styleable.IconMenuView_maxItemsPerRow, 3);
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mMoreIcon = a.getDrawable(com.android.internal.R.styleable.IconMenuView_moreIcon);
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        a.recycle();
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.MenuView, 0, 0);
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mItemBackground = a.getDrawable(com.android.internal.R.styleable.MenuView_itemBackground);
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mHorizontalDivider = a.getDrawable(com.android.internal.R.styleable.MenuView_horizontalDivider);
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mHorizontalDividerRects = new ArrayList<Rect>();
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mVerticalDivider =  a.getDrawable(com.android.internal.R.styleable.MenuView_verticalDivider);
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mVerticalDividerRects = new ArrayList<Rect>();
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mAnimations = a.getResourceId(com.android.internal.R.styleable.MenuView_windowAnimationStyle, 0);
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        a.recycle();
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mHorizontalDivider != null) {
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mHorizontalDividerHeight = mHorizontalDivider.getIntrinsicHeight();
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Make sure to have some height for the divider
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mHorizontalDividerHeight == -1) mHorizontalDividerHeight = 1;
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mVerticalDivider != null) {
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mVerticalDividerWidth = mVerticalDivider.getIntrinsicWidth();
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Make sure to have some width for the divider
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mVerticalDividerWidth == -1) mVerticalDividerWidth = 1;
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mLayout = new int[mMaxRows];
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // This view will be drawing the dividers
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        setWillNotDraw(false);
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // This is so we'll receive the MENU key in touch mode
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        setFocusableInTouchMode(true);
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // This is so our children can still be arrow-key focused
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
172696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    int getMaxItems() {
173696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        return mMaxItems;
174696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    }
175696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Figures out the layout for the menu items.
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param width The available width for the icon menu.
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void layoutItems(int width) {
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int numItems = getChildCount();
18322cb2f46fdbb9a904ac394f488278fb47e2d4734Adam Powell        if (numItems == 0) {
18422cb2f46fdbb9a904ac394f488278fb47e2d4734Adam Powell            mLayoutNumRows = 0;
18522cb2f46fdbb9a904ac394f488278fb47e2d4734Adam Powell            return;
18622cb2f46fdbb9a904ac394f488278fb47e2d4734Adam Powell        }
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Start with the least possible number of rows
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int curNumRows =
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Math.min((int) Math.ceil(numItems / (float) mMaxItemsPerRow), mMaxRows);
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /*
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Increase the number of rows until we find a configuration that fits
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * all of the items' titles. Worst case, we use mMaxRows.
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (; curNumRows <= mMaxRows; curNumRows++) {
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            layoutItemsUsingGravity(curNumRows, numItems);
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (curNumRows >= numItems) {
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Can't have more rows than items
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (doItemsFit()) {
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // All the items fit, so this is a good configuration
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Figures out the layout for the menu items by equally distributing, and
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * adding any excess items equally to lower rows.
2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param numRows The total number of rows for the menu view
2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param numItems The total number of items (across all rows) contained in
2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            the menu view
2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return int[] Where the value of index i contains the number of items for row i
2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void layoutItemsUsingGravity(int numRows, int numItems) {
2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int numBaseItemsPerRow = numItems / numRows;
2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int numLeftoverItems = numItems % numRows;
2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * The bottom rows will each get a leftover item. Rows (indexed at 0)
2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * that are >= this get a leftover item. Note: if there are 0 leftover
2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * items, no rows will get them since this value will be greater than
2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * the last row.
2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int rowsThatGetALeftoverItem = numRows - numLeftoverItems;
2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int[] layout = mLayout;
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < numRows; i++) {
2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            layout[i] = numBaseItemsPerRow;
2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Fill the bottom rows with a leftover item each
2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (i >= rowsThatGetALeftoverItem) {
2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                layout[i]++;
2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mLayoutNumRows = numRows;
2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Checks whether each item's title is fully visible using the current
2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * layout.
2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return True if the items fit (each item's text is fully visible), false
2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         otherwise.
2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean doItemsFit() {
2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int itemPos = 0;
2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int[] layout = mLayout;
2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int numRows = mLayoutNumRows;
2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int row = 0; row < numRows; row++) {
2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int numItemsOnRow = layout[row];
2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            /*
2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * If there is only one item on this row, increasing the
2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * number of rows won't help.
2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             */
2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (numItemsOnRow == 1) {
2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                itemPos++;
2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                continue;
2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int itemsOnRowCounter = numItemsOnRow; itemsOnRowCounter > 0;
2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    itemsOnRowCounter--) {
2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                View child = getChildAt(itemPos++);
2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                LayoutParams lp = (LayoutParams) child.getLayoutParams();
2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (lp.maxNumItemsOnRow < numItemsOnRow) {
2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return false;
2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
281696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    Drawable getItemBackgroundDrawable() {
282696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        return mItemBackground.getConstantState().newDrawable(getContext().getResources());
2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Creates the item view for the 'More' button which is used to switch to
2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * the expanded menu view. This button is a special case since it does not
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * have a MenuItemData backing it.
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The IconMenuItemView for the 'More' button
2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
291696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    IconMenuItemView createMoreItemView() {
292696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        Context context = getContext();
293696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        LayoutInflater inflater = LayoutInflater.from(context);
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final IconMenuItemView itemView = (IconMenuItemView) inflater.inflate(
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                com.android.internal.R.layout.icon_menu_item_layout, null);
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
298696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        Resources r = context.getResources();
2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        itemView.initialize(r.getText(com.android.internal.R.string.more_item_label), mMoreIcon);
3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Set up a click listener on the view since there will be no invocation sequence
3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // due to the lack of a MenuItemData this view
3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        itemView.setOnClickListener(new OnClickListener() {
3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            public void onClick(View v) {
305696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                // Switches the menu to expanded mode. Requires support from
306696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                // the menu's active callback.
307696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell                mMenu.changeMenuMode();
3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        });
3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return itemView;
3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
315696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    public void initialize(MenuBuilder menu) {
3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mMenu = menu;
3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The positioning algorithm that gets called from onMeasure.  It
3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * just computes positions for each child, and then stores them in the child's layout params.
3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param menuWidth The width of this menu to assume for positioning
3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param menuHeight The height of this menu to assume for positioning
3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void positionChildren(int menuWidth, int menuHeight) {
3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Clear the containers for the positions where the dividers should be drawn
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mHorizontalDivider != null) mHorizontalDividerRects.clear();
3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mVerticalDivider != null) mVerticalDividerRects.clear();
3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Get the minimum number of rows needed
3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int numRows = mLayoutNumRows;
3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int numRowsMinus1 = numRows - 1;
3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int numItemsForRow[] = mLayout;
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // The item position across all rows
3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int itemPos = 0;
3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        View child;
3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        IconMenuView.LayoutParams childLayoutParams = null;
3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Use float for this to get precise positions (uniform item widths
3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // instead of last one taking any slack), and then convert to ints at last opportunity
3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        float itemLeft;
3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        float itemTop = 0;
3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Since each row can have a different number of items, this will be computed per row
3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        float itemWidth;
3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Subtract the space needed for the horizontal dividers
3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final float itemHeight = (menuHeight - mHorizontalDividerHeight * (numRows - 1))
3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                / (float)numRows;
3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int row = 0; row < numRows; row++) {
3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Start at the left
3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            itemLeft = 0;
3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Subtract the space needed for the vertical dividers, and divide by the number of items
3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            itemWidth = (menuWidth - mVerticalDividerWidth * (numItemsForRow[row] - 1))
3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    / (float)numItemsForRow[row];
3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int itemPosOnRow = 0; itemPosOnRow < numItemsForRow[row]; itemPosOnRow++) {
3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Tell the child to be exactly this size
3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                child = getChildAt(itemPos);
3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                child.measure(MeasureSpec.makeMeasureSpec((int) itemWidth, MeasureSpec.EXACTLY),
3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        MeasureSpec.makeMeasureSpec((int) itemHeight, MeasureSpec.EXACTLY));
3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Remember the child's position for layout
3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                childLayoutParams = (IconMenuView.LayoutParams) child.getLayoutParams();
3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                childLayoutParams.left = (int) itemLeft;
3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                childLayoutParams.right = (int) (itemLeft + itemWidth);
3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                childLayoutParams.top = (int) itemTop;
3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                childLayoutParams.bottom = (int) (itemTop + itemHeight);
3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Increment by item width
3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                itemLeft += itemWidth;
3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                itemPos++;
3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Add a vertical divider to draw
3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mVerticalDivider != null) {
3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mVerticalDividerRects.add(new Rect((int) itemLeft,
3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            (int) itemTop, (int) (itemLeft + mVerticalDividerWidth),
3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            (int) (itemTop + itemHeight)));
3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Increment by divider width (even if we're not computing
3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // dividers, since we need to leave room for them when
3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // calculating item positions)
3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                itemLeft += mVerticalDividerWidth;
3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Last child on each row should extend to very right edge
3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (childLayoutParams != null) {
3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                childLayoutParams.right = menuWidth;
3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            itemTop += itemHeight;
3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Add a horizontal divider to draw
3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if ((mHorizontalDivider != null) && (row < numRowsMinus1)) {
3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mHorizontalDividerRects.add(new Rect(0, (int) itemTop, menuWidth,
3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        (int) (itemTop + mHorizontalDividerHeight)));
3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                itemTop += mHorizontalDividerHeight;
4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int measuredWidth = resolveSize(Integer.MAX_VALUE, widthMeasureSpec);
4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        calculateItemFittingMetadata(measuredWidth);
4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        layoutItems(measuredWidth);
4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Get the desired height of the icon menu view (last row of items does
4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // not have a divider below)
41322cb2f46fdbb9a904ac394f488278fb47e2d4734Adam Powell        final int layoutNumRows = mLayoutNumRows;
4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int desiredHeight = (mRowHeight + mHorizontalDividerHeight) *
41522cb2f46fdbb9a904ac394f488278fb47e2d4734Adam Powell                layoutNumRows - mHorizontalDividerHeight;
4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Maximum possible width and desired height
4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        setMeasuredDimension(measuredWidth,
4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                resolveSize(desiredHeight, heightMeasureSpec));
4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Position the children
42222cb2f46fdbb9a904ac394f488278fb47e2d4734Adam Powell        if (layoutNumRows > 0) {
423189ee18d6c6483ad63cc864267328259e2e00b95Dianne Hackborn            positionChildren(getMeasuredWidth(), getMeasuredHeight());
42422cb2f46fdbb9a904ac394f488278fb47e2d4734Adam Powell        }
4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void onLayout(boolean changed, int l, int t, int r, int b) {
4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        View child;
4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        IconMenuView.LayoutParams childLayoutParams;
4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = getChildCount() - 1; i >= 0; i--) {
4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            child = getChildAt(i);
4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            childLayoutParams = (IconMenuView.LayoutParams)child
4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    .getLayoutParams();
4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Layout children according to positions set during the measure
4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            child.layout(childLayoutParams.left, childLayoutParams.top, childLayoutParams.right,
4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    childLayoutParams.bottom);
4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void onDraw(Canvas canvas) {
446809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy        Drawable drawable = mHorizontalDivider;
447809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy        if (drawable != null) {
4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // If we have a horizontal divider to draw, draw it at the remembered positions
449809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy            final ArrayList<Rect> rects = mHorizontalDividerRects;
450809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy            for (int i = rects.size() - 1; i >= 0; i--) {
451809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy                drawable.setBounds(rects.get(i));
452809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy                drawable.draw(canvas);
4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
455809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy
456809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy        drawable = mVerticalDivider;
457809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy        if (drawable != null) {
4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // If we have a vertical divider to draw, draw it at the remembered positions
459809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy            final ArrayList<Rect> rects = mVerticalDividerRects;
460809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy            for (int i = rects.size() - 1; i >= 0; i--) {
461809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy                drawable.setBounds(rects.get(i));
462809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy                drawable.draw(canvas);
4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean invokeItem(MenuItemImpl item) {
4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mMenu.performItemAction(item, 0);
4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
472809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy    public LayoutParams generateLayoutParams(AttributeSet attrs) {
4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return new IconMenuView.LayoutParams(getContext(), attrs);
4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
477809a7f6080312f3e12f1a3a30eacf0e0c7627305Romain Guy    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Override to allow type-checking of LayoutParams.
4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return p instanceof IconMenuView.LayoutParams;
4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Marks as having stale children.
4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    void markStaleChildren() {
4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mHasStaleChildren) {
4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mHasStaleChildren = true;
4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            requestLayout();
4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The number of actual items shown (those that are backed by an
4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         {@link MenuView.ItemView} implementation--eg: excludes More
4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         item).
4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int getNumActualItemsShown() {
4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mNumActualItemsShown;
4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
501696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    void setNumActualItemsShown(int count) {
502696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell        mNumActualItemsShown = count;
503696cba573e651b0e4f18a4718627c8ccecb3bda0Adam Powell    }
5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getWindowAnimations() {
5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mAnimations;
5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns the number of items per row.
5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>
5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * This should only be used for testing.
5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The length of the array is the number of rows. A value at a
5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         position is the number of items in that row.
5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @hide
5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int[] getLayout() {
5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mLayout;
5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns the number of rows in the layout.
5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>
5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * This should only be used for testing.
5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The length of the array is the number of rows. A value at a
5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         position is the number of items in that row.
5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @hide
5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getLayoutNumRows() {
5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mLayoutNumRows;
5339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean dispatchKeyEvent(KeyEvent event) {
5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (event.getKeyCode() == KeyEvent.KEYCODE_MENU) {
5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) {
5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                removeCallbacks(this);
5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                postDelayed(this, ViewConfiguration.getLongPressTimeout());
5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (event.getAction() == KeyEvent.ACTION_UP) {
5439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mMenuBeingLongpressed) {
5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // It was in cycle mode, so reset it (will also remove us
5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // from being called back)
5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    setCycleShortcutCaptionMode(false);
5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return true;
5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Just remove us from being called back
5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    removeCallbacks(this);
5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Fall through to normal processing too
5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return super.dispatchKeyEvent(event);
5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
5629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void onAttachedToWindow() {
5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super.onAttachedToWindow();
5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        requestFocus();
5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void onDetachedFromWindow() {
5709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        setCycleShortcutCaptionMode(false);
5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super.onDetachedFromWindow();
5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void onWindowFocusChanged(boolean hasWindowFocus) {
5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!hasWindowFocus) {
5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setCycleShortcutCaptionMode(false);
5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super.onWindowFocusChanged(hasWindowFocus);
5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Sets the shortcut caption mode for IconMenuView. This mode will
5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * continuously cycle between a child's shortcut and its title.
5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param cycleShortcutAndNormal Whether to go into cycling shortcut mode,
5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *        or to go back to normal.
5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void setCycleShortcutCaptionMode(boolean cycleShortcutAndNormal) {
5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!cycleShortcutAndNormal) {
5949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            /*
5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * We're setting back to title, so remove any callbacks for setting
5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * to shortcut
5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             */
5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            removeCallbacks(this);
5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setChildrenCaptionMode(false);
6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mMenuBeingLongpressed = false;
6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Set it the first time (the cycle will be started in run()).
6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setChildrenCaptionMode(true);
6069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
6119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * When this method is invoked if the menu is currently not being
6129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * longpressed, it means that the longpress has just been reached (so we set
6139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * longpress flag, and start cycling). If it is being longpressed, we cycle
6149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * to the next mode.
6159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
6169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void run() {
6179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mMenuBeingLongpressed) {
6199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Cycle to other caption mode on the children
6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setChildrenCaptionMode(!mLastChildrenCaptionMode);
6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Switch ourselves to continuously cycle the items captions
6269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mMenuBeingLongpressed = true;
6279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setCycleShortcutCaptionMode(true);
6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // We should run again soon to cycle to the other caption mode
6319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        postDelayed(this, ITEM_CAPTION_CYCLE_DELAY);
6329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
6359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Iterates children and sets the desired shortcut mode. Only
6369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * {@link #setCycleShortcutCaptionMode(boolean)} and {@link #run()} should call
6379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * this.
6389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
6399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param shortcut Whether to show shortcut or the title.
6409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
6419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void setChildrenCaptionMode(boolean shortcut) {
6429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Set the last caption mode pushed to children
6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mLastChildrenCaptionMode = shortcut;
6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = getChildCount() - 1; i >= 0; i--) {
6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ((IconMenuItemView) getChildAt(i)).setCaptionMode(shortcut);
6489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * For each item, calculates the most dense row that fully shows the item's
6539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * title.
6549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
6559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param width The available width of the icon menu.
6569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void calculateItemFittingMetadata(int width) {
6589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int maxNumItemsPerRow = mMaxItemsPerRow;
6599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int numItems = getChildCount();
6609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < numItems; i++) {
6619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            LayoutParams lp = (LayoutParams) getChildAt(i).getLayoutParams();
6629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Start with 1, since that case does not get covered in the loop below
6639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            lp.maxNumItemsOnRow = 1;
6649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int curNumItemsPerRow = maxNumItemsPerRow; curNumItemsPerRow > 0;
6659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    curNumItemsPerRow--) {
6669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Check whether this item can fit into a row containing curNumItemsPerRow
6679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (lp.desiredWidth < width / curNumItemsPerRow) {
6689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // It can, mark this value as the most dense row it can fit into
6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    lp.maxNumItemsOnRow = curNumItemsPerRow;
6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
6719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected Parcelable onSaveInstanceState() {
6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Parcelable superState = super.onSaveInstanceState();
6799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        View focusedView = getFocusedChild();
6819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = getChildCount() - 1; i >= 0; i--) {
6839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (getChildAt(i) == focusedView) {
6849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return new SavedState(superState, i);
6859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return new SavedState(superState, -1);
6899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
6929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void onRestoreInstanceState(Parcelable state) {
6939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        SavedState ss = (SavedState) state;
6949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super.onRestoreInstanceState(ss.getSuperState());
6959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (ss.focusedPosition >= getChildCount()) {
6979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
6989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        View v = getChildAt(ss.focusedPosition);
7019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (v != null) {
7029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            v.requestFocus();
7039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static class SavedState extends BaseSavedState {
7079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int focusedPosition;
7089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
7109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Constructor called from {@link IconMenuView#onSaveInstanceState()}
7119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
7129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public SavedState(Parcelable superState, int focusedPosition) {
7139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super(superState);
7149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            this.focusedPosition = focusedPosition;
7159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
7189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Constructor called from {@link #CREATOR}
7199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
7209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private SavedState(Parcel in) {
7219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super(in);
7229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            focusedPosition = in.readInt();
7239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
7269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void writeToParcel(Parcel dest, int flags) {
7279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super.writeToParcel(dest, flags);
7289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            dest.writeInt(focusedPosition);
7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public static final Parcelable.Creator<SavedState> CREATOR = new Parcelable.Creator<SavedState>() {
7329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            public SavedState createFromParcel(Parcel in) {
7339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return new SavedState(in);
7349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            public SavedState[] newArray(int size) {
7379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return new SavedState[size];
7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        };
7409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
7449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Layout parameters specific to IconMenuView (stores the left, top, right, bottom from the
7459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * measure pass).
7469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
7479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static class LayoutParams extends ViewGroup.MarginLayoutParams
7489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    {
7499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int left, top, right, bottom;
7509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int desiredWidth;
7519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int maxNumItemsOnRow;
7529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public LayoutParams(Context c, AttributeSet attrs) {
7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super(c, attrs);
7559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public LayoutParams(int width, int height) {
7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super(width, height);
7599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
762