NavigationMenuPresenter.java revision 66698bb15ba0f873aa1c2290cc50d6bb839a474a
131a49efe2adb59e31611f6871895a3243d835127Yuichi Araki/*
231a49efe2adb59e31611f6871895a3243d835127Yuichi Araki * Copyright (C) 2015 The Android Open Source Project
331a49efe2adb59e31611f6871895a3243d835127Yuichi Araki *
431a49efe2adb59e31611f6871895a3243d835127Yuichi Araki * Licensed under the Apache License, Version 2.0 (the "License");
531a49efe2adb59e31611f6871895a3243d835127Yuichi Araki * you may not use this file except in compliance with the License.
631a49efe2adb59e31611f6871895a3243d835127Yuichi Araki * You may obtain a copy of the License at
731a49efe2adb59e31611f6871895a3243d835127Yuichi Araki *
831a49efe2adb59e31611f6871895a3243d835127Yuichi Araki *      http://www.apache.org/licenses/LICENSE-2.0
931a49efe2adb59e31611f6871895a3243d835127Yuichi Araki *
1031a49efe2adb59e31611f6871895a3243d835127Yuichi Araki * Unless required by applicable law or agreed to in writing, software
1131a49efe2adb59e31611f6871895a3243d835127Yuichi Araki * distributed under the License is distributed on an "AS IS" BASIS,
1231a49efe2adb59e31611f6871895a3243d835127Yuichi Araki * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1331a49efe2adb59e31611f6871895a3243d835127Yuichi Araki * See the License for the specific language governing permissions and
1431a49efe2adb59e31611f6871895a3243d835127Yuichi Araki * limitations under the License.
1531a49efe2adb59e31611f6871895a3243d835127Yuichi Araki */
1631a49efe2adb59e31611f6871895a3243d835127Yuichi Araki
1731a49efe2adb59e31611f6871895a3243d835127Yuichi Arakipackage android.support.design.internal;
1831a49efe2adb59e31611f6871895a3243d835127Yuichi Araki
1931a49efe2adb59e31611f6871895a3243d835127Yuichi Arakiimport android.content.Context;
20d3ee2c7d22c0cb204ea9077fa9e64511266d6799Yuichi Arakiimport android.content.res.ColorStateList;
2160abdeb39630c4c74a4c401e221f0c968caa26f5Yuichi Arakiimport android.content.res.Resources;
228bc6f4dfa590d8cd872a9894804a4c80d01a5d87Yuichi Arakiimport android.graphics.drawable.ColorDrawable;
23a63940ca14cd3ad9620e94f709930bb968525c57Chris Banesimport android.graphics.drawable.Drawable;
2401090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Arakiimport android.os.Bundle;
2531a49efe2adb59e31611f6871895a3243d835127Yuichi Arakiimport android.os.Parcelable;
267c89489dcb1e7cc454da4375c387caf20201acb7Chris Banesimport android.support.annotation.LayoutRes;
2701090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Arakiimport android.support.annotation.NonNull;
28d3ee2c7d22c0cb204ea9077fa9e64511266d6799Yuichi Arakiimport android.support.annotation.Nullable;
29153fa9a03422419cd56b7d17def1ae907fc7b5cfChris Banesimport android.support.annotation.StyleRes;
3031a49efe2adb59e31611f6871895a3243d835127Yuichi Arakiimport android.support.design.R;
3166698bb15ba0f873aa1c2290cc50d6bb839a474aChris Banesimport android.support.v7.view.menu.MenuBuilder;
3266698bb15ba0f873aa1c2290cc50d6bb839a474aChris Banesimport android.support.v7.view.menu.MenuItemImpl;
3366698bb15ba0f873aa1c2290cc50d6bb839a474aChris Banesimport android.support.v7.view.menu.MenuPresenter;
3466698bb15ba0f873aa1c2290cc50d6bb839a474aChris Banesimport android.support.v7.view.menu.MenuView;
3566698bb15ba0f873aa1c2290cc50d6bb839a474aChris Banesimport android.support.v7.view.menu.SubMenuBuilder;
3664bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Arakiimport android.support.v7.widget.RecyclerView;
3701090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Arakiimport android.util.SparseArray;
3831a49efe2adb59e31611f6871895a3243d835127Yuichi Arakiimport android.view.LayoutInflater;
3901090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Arakiimport android.view.MenuItem;
4001090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Arakiimport android.view.SubMenu;
4131a49efe2adb59e31611f6871895a3243d835127Yuichi Arakiimport android.view.View;
4231a49efe2adb59e31611f6871895a3243d835127Yuichi Arakiimport android.view.ViewGroup;
437c89489dcb1e7cc454da4375c387caf20201acb7Chris Banesimport android.widget.LinearLayout;
4401090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Arakiimport android.widget.TextView;
4501090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki
4601090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Arakiimport java.util.ArrayList;
4731a49efe2adb59e31611f6871895a3243d835127Yuichi Araki
4831a49efe2adb59e31611f6871895a3243d835127Yuichi Araki/**
4931a49efe2adb59e31611f6871895a3243d835127Yuichi Araki * @hide
5031a49efe2adb59e31611f6871895a3243d835127Yuichi Araki */
5164bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Arakipublic class NavigationMenuPresenter implements MenuPresenter {
5231a49efe2adb59e31611f6871895a3243d835127Yuichi Araki
5301090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki    private static final String STATE_HIERARCHY = "android:menu:list";
5476bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki    private static final String STATE_ADAPTER = "android:menu:adapter";
5501090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki
5631a49efe2adb59e31611f6871895a3243d835127Yuichi Araki    private NavigationMenuView mMenuView;
577c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes    private LinearLayout mHeaderLayout;
5831a49efe2adb59e31611f6871895a3243d835127Yuichi Araki
5931a49efe2adb59e31611f6871895a3243d835127Yuichi Araki    private Callback mCallback;
6031a49efe2adb59e31611f6871895a3243d835127Yuichi Araki    private MenuBuilder mMenu;
6131a49efe2adb59e31611f6871895a3243d835127Yuichi Araki    private int mId;
6231a49efe2adb59e31611f6871895a3243d835127Yuichi Araki
6331a49efe2adb59e31611f6871895a3243d835127Yuichi Araki    private NavigationMenuAdapter mAdapter;
6431a49efe2adb59e31611f6871895a3243d835127Yuichi Araki    private LayoutInflater mLayoutInflater;
6531a49efe2adb59e31611f6871895a3243d835127Yuichi Araki
66153fa9a03422419cd56b7d17def1ae907fc7b5cfChris Banes    private int mTextAppearance;
67153fa9a03422419cd56b7d17def1ae907fc7b5cfChris Banes    private boolean mTextAppearanceSet;
68a63940ca14cd3ad9620e94f709930bb968525c57Chris Banes    private ColorStateList mTextColor;
69a63940ca14cd3ad9620e94f709930bb968525c57Chris Banes    private ColorStateList mIconTintList;
70a63940ca14cd3ad9620e94f709930bb968525c57Chris Banes    private Drawable mItemBackground;
71d3ee2c7d22c0cb204ea9077fa9e64511266d6799Yuichi Araki
7201090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki    /**
7301090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki     * Padding to be inserted at the top of the list to avoid the first menu item
7401090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki     * from being placed underneath the status bar.
7501090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki     */
7601090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki    private int mPaddingTopDefault;
7701090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki
7860abdeb39630c4c74a4c401e221f0c968caa26f5Yuichi Araki    /**
7960abdeb39630c4c74a4c401e221f0c968caa26f5Yuichi Araki     * Padding for separators between items
8060abdeb39630c4c74a4c401e221f0c968caa26f5Yuichi Araki     */
8160abdeb39630c4c74a4c401e221f0c968caa26f5Yuichi Araki    private int mPaddingSeparator;
8260abdeb39630c4c74a4c401e221f0c968caa26f5Yuichi Araki
8331a49efe2adb59e31611f6871895a3243d835127Yuichi Araki    @Override
8431a49efe2adb59e31611f6871895a3243d835127Yuichi Araki    public void initForMenu(Context context, MenuBuilder menu) {
8531a49efe2adb59e31611f6871895a3243d835127Yuichi Araki        mLayoutInflater = LayoutInflater.from(context);
8631a49efe2adb59e31611f6871895a3243d835127Yuichi Araki        mMenu = menu;
8760abdeb39630c4c74a4c401e221f0c968caa26f5Yuichi Araki        Resources res = context.getResources();
88a577676a64e5353b8ec927117151aa6be84adf66Chris Banes        mPaddingTopDefault = res.getDimensionPixelOffset(
89a577676a64e5353b8ec927117151aa6be84adf66Chris Banes                R.dimen.design_navigation_padding_top_default);
9060abdeb39630c4c74a4c401e221f0c968caa26f5Yuichi Araki        mPaddingSeparator = res.getDimensionPixelOffset(
91a577676a64e5353b8ec927117151aa6be84adf66Chris Banes                R.dimen.design_navigation_separator_vertical_padding);
9231a49efe2adb59e31611f6871895a3243d835127Yuichi Araki    }
9331a49efe2adb59e31611f6871895a3243d835127Yuichi Araki
9431a49efe2adb59e31611f6871895a3243d835127Yuichi Araki    @Override
9531a49efe2adb59e31611f6871895a3243d835127Yuichi Araki    public MenuView getMenuView(ViewGroup root) {
9631a49efe2adb59e31611f6871895a3243d835127Yuichi Araki        if (mMenuView == null) {
9731a49efe2adb59e31611f6871895a3243d835127Yuichi Araki            mMenuView = (NavigationMenuView) mLayoutInflater.inflate(
98a5081dfb26b3664d97d5fe09b9b6a9c9667e0e9fYuichi Araki                    R.layout.design_navigation_menu, root, false);
9931a49efe2adb59e31611f6871895a3243d835127Yuichi Araki            if (mAdapter == null) {
10031a49efe2adb59e31611f6871895a3243d835127Yuichi Araki                mAdapter = new NavigationMenuAdapter();
10131a49efe2adb59e31611f6871895a3243d835127Yuichi Araki            }
1027c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes            mHeaderLayout = (LinearLayout) mLayoutInflater
1037c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes                    .inflate(R.layout.design_navigation_item_header,
1047c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes                            mMenuView, false);
10531a49efe2adb59e31611f6871895a3243d835127Yuichi Araki            mMenuView.setAdapter(mAdapter);
10631a49efe2adb59e31611f6871895a3243d835127Yuichi Araki        }
10731a49efe2adb59e31611f6871895a3243d835127Yuichi Araki        return mMenuView;
10831a49efe2adb59e31611f6871895a3243d835127Yuichi Araki    }
10931a49efe2adb59e31611f6871895a3243d835127Yuichi Araki
11031a49efe2adb59e31611f6871895a3243d835127Yuichi Araki    @Override
11131a49efe2adb59e31611f6871895a3243d835127Yuichi Araki    public void updateMenuView(boolean cleared) {
11231a49efe2adb59e31611f6871895a3243d835127Yuichi Araki        if (mAdapter != null) {
11364bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki            mAdapter.update();
11431a49efe2adb59e31611f6871895a3243d835127Yuichi Araki        }
11531a49efe2adb59e31611f6871895a3243d835127Yuichi Araki    }
11631a49efe2adb59e31611f6871895a3243d835127Yuichi Araki
11731a49efe2adb59e31611f6871895a3243d835127Yuichi Araki    @Override
11831a49efe2adb59e31611f6871895a3243d835127Yuichi Araki    public void setCallback(Callback cb) {
11931a49efe2adb59e31611f6871895a3243d835127Yuichi Araki        mCallback = cb;
12031a49efe2adb59e31611f6871895a3243d835127Yuichi Araki    }
12131a49efe2adb59e31611f6871895a3243d835127Yuichi Araki
12231a49efe2adb59e31611f6871895a3243d835127Yuichi Araki    @Override
12331a49efe2adb59e31611f6871895a3243d835127Yuichi Araki    public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
12431a49efe2adb59e31611f6871895a3243d835127Yuichi Araki        return false;
12531a49efe2adb59e31611f6871895a3243d835127Yuichi Araki    }
12631a49efe2adb59e31611f6871895a3243d835127Yuichi Araki
12731a49efe2adb59e31611f6871895a3243d835127Yuichi Araki    @Override
12831a49efe2adb59e31611f6871895a3243d835127Yuichi Araki    public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
12931a49efe2adb59e31611f6871895a3243d835127Yuichi Araki        if (mCallback != null) {
13031a49efe2adb59e31611f6871895a3243d835127Yuichi Araki            mCallback.onCloseMenu(menu, allMenusAreClosing);
13131a49efe2adb59e31611f6871895a3243d835127Yuichi Araki        }
13231a49efe2adb59e31611f6871895a3243d835127Yuichi Araki    }
13331a49efe2adb59e31611f6871895a3243d835127Yuichi Araki
13431a49efe2adb59e31611f6871895a3243d835127Yuichi Araki    @Override
13531a49efe2adb59e31611f6871895a3243d835127Yuichi Araki    public boolean flagActionItems() {
13631a49efe2adb59e31611f6871895a3243d835127Yuichi Araki        return false;
13731a49efe2adb59e31611f6871895a3243d835127Yuichi Araki    }
13831a49efe2adb59e31611f6871895a3243d835127Yuichi Araki
13931a49efe2adb59e31611f6871895a3243d835127Yuichi Araki    @Override
14031a49efe2adb59e31611f6871895a3243d835127Yuichi Araki    public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item) {
14131a49efe2adb59e31611f6871895a3243d835127Yuichi Araki        return false;
14231a49efe2adb59e31611f6871895a3243d835127Yuichi Araki    }
14331a49efe2adb59e31611f6871895a3243d835127Yuichi Araki
14431a49efe2adb59e31611f6871895a3243d835127Yuichi Araki    @Override
14531a49efe2adb59e31611f6871895a3243d835127Yuichi Araki    public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item) {
14631a49efe2adb59e31611f6871895a3243d835127Yuichi Araki        return false;
14731a49efe2adb59e31611f6871895a3243d835127Yuichi Araki    }
14831a49efe2adb59e31611f6871895a3243d835127Yuichi Araki
14931a49efe2adb59e31611f6871895a3243d835127Yuichi Araki    @Override
15031a49efe2adb59e31611f6871895a3243d835127Yuichi Araki    public int getId() {
15131a49efe2adb59e31611f6871895a3243d835127Yuichi Araki        return mId;
15231a49efe2adb59e31611f6871895a3243d835127Yuichi Araki    }
15331a49efe2adb59e31611f6871895a3243d835127Yuichi Araki
15431a49efe2adb59e31611f6871895a3243d835127Yuichi Araki    public void setId(int id) {
15531a49efe2adb59e31611f6871895a3243d835127Yuichi Araki        mId = id;
15631a49efe2adb59e31611f6871895a3243d835127Yuichi Araki    }
15731a49efe2adb59e31611f6871895a3243d835127Yuichi Araki
15831a49efe2adb59e31611f6871895a3243d835127Yuichi Araki    @Override
15931a49efe2adb59e31611f6871895a3243d835127Yuichi Araki    public Parcelable onSaveInstanceState() {
16001090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki        Bundle state = new Bundle();
16101090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki        if (mMenuView != null) {
16276bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki            SparseArray<Parcelable> hierarchy = new SparseArray<>();
16301090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki            mMenuView.saveHierarchyState(hierarchy);
16476bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki            state.putSparseParcelableArray(STATE_HIERARCHY, hierarchy);
16576bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki        }
16676bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki        if (mAdapter != null) {
16776bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki            state.putBundle(STATE_ADAPTER, mAdapter.createInstanceState());
16801090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki        }
16901090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki        return state;
17031a49efe2adb59e31611f6871895a3243d835127Yuichi Araki    }
17131a49efe2adb59e31611f6871895a3243d835127Yuichi Araki
17231a49efe2adb59e31611f6871895a3243d835127Yuichi Araki    @Override
17301090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki    public void onRestoreInstanceState(Parcelable parcelable) {
17401090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki        Bundle state = (Bundle) parcelable;
17501090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki        SparseArray<Parcelable> hierarchy = state.getSparseParcelableArray(STATE_HIERARCHY);
17601090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki        if (hierarchy != null) {
17701090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki            mMenuView.restoreHierarchyState(hierarchy);
17801090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki        }
17976bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki        Bundle adapterState = state.getBundle(STATE_ADAPTER);
18076bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki        if (adapterState != null) {
18176bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki            mAdapter.restoreInstanceState(adapterState);
18276bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki        }
18331a49efe2adb59e31611f6871895a3243d835127Yuichi Araki    }
18431a49efe2adb59e31611f6871895a3243d835127Yuichi Araki
185f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki    public void setCheckedItem(MenuItemImpl item) {
186f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki        mAdapter.setCheckedItem(item);
187f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki    }
188f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki
1897c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes    public View inflateHeaderView(@LayoutRes int res) {
1907c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes        View view = mLayoutInflater.inflate(res, mHeaderLayout, false);
1917c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes        addHeaderView(view);
1927c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes        return view;
1937c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes    }
1947c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes
19501090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki    public void addHeaderView(@NonNull View view) {
1967c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes        mHeaderLayout.addView(view);
1977c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes        // The padding on top should be cleared.
19860abdeb39630c4c74a4c401e221f0c968caa26f5Yuichi Araki        mMenuView.setPadding(0, 0, 0, mMenuView.getPaddingBottom());
19901090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki    }
20001090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki
2017c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes    public void removeHeaderView(@NonNull View view) {
2027c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes        mHeaderLayout.removeView(view);
2037c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes        if (mHeaderLayout.getChildCount() == 0) {
20472fa50f289d462aae5038e8dd78e134a0fffcf12Yuichi Araki            mMenuView.setPadding(0, mPaddingTopDefault, 0, mMenuView.getPaddingBottom());
20501090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki        }
20631a49efe2adb59e31611f6871895a3243d835127Yuichi Araki    }
20731a49efe2adb59e31611f6871895a3243d835127Yuichi Araki
208cdccc4c6d5f1e40610ce4df4afeb1f99cbdb63e8Yuichi Araki    public int getHeaderCount() {
209cdccc4c6d5f1e40610ce4df4afeb1f99cbdb63e8Yuichi Araki        return mHeaderLayout.getChildCount();
210cdccc4c6d5f1e40610ce4df4afeb1f99cbdb63e8Yuichi Araki    }
211cdccc4c6d5f1e40610ce4df4afeb1f99cbdb63e8Yuichi Araki
212cdccc4c6d5f1e40610ce4df4afeb1f99cbdb63e8Yuichi Araki    public View getHeaderView(int index) {
213cdccc4c6d5f1e40610ce4df4afeb1f99cbdb63e8Yuichi Araki        return mHeaderLayout.getChildAt(index);
214cdccc4c6d5f1e40610ce4df4afeb1f99cbdb63e8Yuichi Araki    }
215cdccc4c6d5f1e40610ce4df4afeb1f99cbdb63e8Yuichi Araki
216d3ee2c7d22c0cb204ea9077fa9e64511266d6799Yuichi Araki    @Nullable
217d3ee2c7d22c0cb204ea9077fa9e64511266d6799Yuichi Araki    public ColorStateList getItemTintList() {
218a63940ca14cd3ad9620e94f709930bb968525c57Chris Banes        return mIconTintList;
219d3ee2c7d22c0cb204ea9077fa9e64511266d6799Yuichi Araki    }
220d3ee2c7d22c0cb204ea9077fa9e64511266d6799Yuichi Araki
221a63940ca14cd3ad9620e94f709930bb968525c57Chris Banes    public void setItemIconTintList(@Nullable ColorStateList tint) {
222a63940ca14cd3ad9620e94f709930bb968525c57Chris Banes        mIconTintList = tint;
223153fa9a03422419cd56b7d17def1ae907fc7b5cfChris Banes        updateMenuView(false);
224d3ee2c7d22c0cb204ea9077fa9e64511266d6799Yuichi Araki    }
225d3ee2c7d22c0cb204ea9077fa9e64511266d6799Yuichi Araki
226a63940ca14cd3ad9620e94f709930bb968525c57Chris Banes    @Nullable
227a63940ca14cd3ad9620e94f709930bb968525c57Chris Banes    public ColorStateList getItemTextColor() {
228a63940ca14cd3ad9620e94f709930bb968525c57Chris Banes        return mTextColor;
229a63940ca14cd3ad9620e94f709930bb968525c57Chris Banes    }
230a63940ca14cd3ad9620e94f709930bb968525c57Chris Banes
231a63940ca14cd3ad9620e94f709930bb968525c57Chris Banes    public void setItemTextColor(@Nullable ColorStateList textColor) {
232a63940ca14cd3ad9620e94f709930bb968525c57Chris Banes        mTextColor = textColor;
233153fa9a03422419cd56b7d17def1ae907fc7b5cfChris Banes        updateMenuView(false);
234153fa9a03422419cd56b7d17def1ae907fc7b5cfChris Banes    }
235153fa9a03422419cd56b7d17def1ae907fc7b5cfChris Banes
236153fa9a03422419cd56b7d17def1ae907fc7b5cfChris Banes    public void setItemTextAppearance(@StyleRes int resId) {
237153fa9a03422419cd56b7d17def1ae907fc7b5cfChris Banes        mTextAppearance = resId;
238153fa9a03422419cd56b7d17def1ae907fc7b5cfChris Banes        mTextAppearanceSet = true;
239153fa9a03422419cd56b7d17def1ae907fc7b5cfChris Banes        updateMenuView(false);
240a63940ca14cd3ad9620e94f709930bb968525c57Chris Banes    }
241a63940ca14cd3ad9620e94f709930bb968525c57Chris Banes
242a63940ca14cd3ad9620e94f709930bb968525c57Chris Banes    public Drawable getItemBackground() {
243a63940ca14cd3ad9620e94f709930bb968525c57Chris Banes        return mItemBackground;
244d3ee2c7d22c0cb204ea9077fa9e64511266d6799Yuichi Araki    }
245d3ee2c7d22c0cb204ea9077fa9e64511266d6799Yuichi Araki
246a63940ca14cd3ad9620e94f709930bb968525c57Chris Banes    public void setItemBackground(Drawable itemBackground) {
247a63940ca14cd3ad9620e94f709930bb968525c57Chris Banes        mItemBackground = itemBackground;
248d3ee2c7d22c0cb204ea9077fa9e64511266d6799Yuichi Araki    }
249d3ee2c7d22c0cb204ea9077fa9e64511266d6799Yuichi Araki
250cc7a09fc0018e348027151daecf581b1d1b78f11Yuichi Araki    public void setUpdateSuspended(boolean updateSuspended) {
251cc7a09fc0018e348027151daecf581b1d1b78f11Yuichi Araki        if (mAdapter != null) {
252cc7a09fc0018e348027151daecf581b1d1b78f11Yuichi Araki            mAdapter.setUpdateSuspended(updateSuspended);
253cc7a09fc0018e348027151daecf581b1d1b78f11Yuichi Araki        }
254cc7a09fc0018e348027151daecf581b1d1b78f11Yuichi Araki    }
255cc7a09fc0018e348027151daecf581b1d1b78f11Yuichi Araki
25664bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki    private abstract static class ViewHolder extends RecyclerView.ViewHolder {
25764bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki
25864bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki        public ViewHolder(View itemView) {
25964bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki            super(itemView);
26064bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki        }
26164bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki
26264bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki    }
26364bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki
26464bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki    private static class NormalViewHolder extends ViewHolder {
26564bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki
26664bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki        public NormalViewHolder(LayoutInflater inflater, ViewGroup parent,
26764bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki                View.OnClickListener listener) {
26864bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki            super(inflater.inflate(R.layout.design_navigation_item, parent, false));
26964bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki            itemView.setOnClickListener(listener);
27064bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki        }
27164bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki
27264bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki    }
27364bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki
27464bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki    private static class SubheaderViewHolder extends ViewHolder {
27564bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki
27664bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki        public SubheaderViewHolder(LayoutInflater inflater, ViewGroup parent) {
27764bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki            super(inflater.inflate(R.layout.design_navigation_item_subheader, parent, false));
27864bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki        }
27964bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki
28064bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki    }
28164bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki
28264bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki    private static class SeparatorViewHolder extends ViewHolder {
28364bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki
28464bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki        public SeparatorViewHolder(LayoutInflater inflater, ViewGroup parent) {
28564bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki            super(inflater.inflate(R.layout.design_navigation_item_separator, parent, false));
28664bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki        }
28764bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki
28864bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki    }
28964bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki
2907c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes    private static class HeaderViewHolder extends ViewHolder {
2917c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes
2927c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes        public HeaderViewHolder(View itemView) {
2937c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes            super(itemView);
2947c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes        }
2957c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes
2967c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes    }
2977c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes
29864bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki    /**
29964bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki     * Handles click events for the menu items. The items has to be {@link NavigationMenuItemView}.
30064bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki     */
30164bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki    private final View.OnClickListener mOnClickListener = new View.OnClickListener() {
30264bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki
30364bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki        @Override
30464bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki        public void onClick(View v) {
30564bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki            NavigationMenuItemView itemView = (NavigationMenuItemView) v;
30664bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki            setUpdateSuspended(true);
30764bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki            MenuItemImpl item = itemView.getItemData();
30864bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki            boolean result = mMenu.performItemAction(item, NavigationMenuPresenter.this, 0);
30964bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki            if (item != null && item.isCheckable() && result) {
31064bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki                mAdapter.setCheckedItem(item);
31164bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki            }
31264bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki            setUpdateSuspended(false);
31364bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki            updateMenuView(false);
31464bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki        }
31564bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki
31664bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki    };
31764bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki
31864bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki    private class NavigationMenuAdapter extends RecyclerView.Adapter<ViewHolder> {
31976bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki
320f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki        private static final String STATE_CHECKED_ITEM = "android:menu:checked";
32176bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki
32236d347c02fa8da71ccd69634484be8156fa0085bYuichi Araki        private static final String STATE_ACTION_VIEWS = "android:menu:action_views";
32301090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki        private static final int VIEW_TYPE_NORMAL = 0;
32401090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki        private static final int VIEW_TYPE_SUBHEADER = 1;
32501090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki        private static final int VIEW_TYPE_SEPARATOR = 2;
3267c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes        private static final int VIEW_TYPE_HEADER = 3;
32701090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki
3283a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes        private final ArrayList<NavigationMenuItem> mItems = new ArrayList<>();
329f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki        private MenuItemImpl mCheckedItem;
3303a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes        private ColorDrawable mTransparentIcon;
33176bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki        private boolean mUpdateSuspended;
3323a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes
3333a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes        NavigationMenuAdapter() {
3343a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes            prepareMenuItems();
3353a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes        }
3363a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes
33731a49efe2adb59e31611f6871895a3243d835127Yuichi Araki        @Override
33831a49efe2adb59e31611f6871895a3243d835127Yuichi Araki        public long getItemId(int position) {
33931a49efe2adb59e31611f6871895a3243d835127Yuichi Araki            return position;
34031a49efe2adb59e31611f6871895a3243d835127Yuichi Araki        }
34131a49efe2adb59e31611f6871895a3243d835127Yuichi Araki
34231a49efe2adb59e31611f6871895a3243d835127Yuichi Araki        @Override
34364bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki        public int getItemCount() {
34464bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki            return mItems.size();
34501090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki        }
34601090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki
34701090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki        @Override
34801090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki        public int getItemViewType(int position) {
34964bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki            NavigationMenuItem item = mItems.get(position);
35064bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki            if (item instanceof NavigationMenuSeparatorItem) {
35101090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki                return VIEW_TYPE_SEPARATOR;
3527c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes            } else if (item instanceof NavigationMenuHeaderItem) {
3537c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes                return VIEW_TYPE_HEADER;
35464bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki            } else if (item instanceof NavigationMenuTextItem) {
35564bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki                NavigationMenuTextItem textItem = (NavigationMenuTextItem) item;
35664bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki                if (textItem.getMenuItem().hasSubMenu()) {
35764bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki                    return VIEW_TYPE_SUBHEADER;
35864bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki                } else {
35964bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki                    return VIEW_TYPE_NORMAL;
36064bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki                }
36101090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki            }
36264bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki            throw new RuntimeException("Unknown item type.");
36301090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki        }
36401090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki
36501090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki        @Override
36664bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki        public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
36701090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki            switch (viewType) {
36801090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki                case VIEW_TYPE_NORMAL:
36964bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki                    return new NormalViewHolder(mLayoutInflater, parent, mOnClickListener);
37064bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki                case VIEW_TYPE_SUBHEADER:
37164bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki                    return new SubheaderViewHolder(mLayoutInflater, parent);
37264bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki                case VIEW_TYPE_SEPARATOR:
37364bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki                    return new SeparatorViewHolder(mLayoutInflater, parent);
3747c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes                case VIEW_TYPE_HEADER:
3757c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes                    return new HeaderViewHolder(mHeaderLayout);
37664bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki            }
37764bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki            return null;
37864bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki        }
37964bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki
38064bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki        @Override
38164bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki        public void onBindViewHolder(ViewHolder holder, int position) {
38264bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki            switch (getItemViewType(position)) {
38364bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki                case VIEW_TYPE_NORMAL: {
38464bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki                    NavigationMenuItemView itemView = (NavigationMenuItemView) holder.itemView;
385a63940ca14cd3ad9620e94f709930bb968525c57Chris Banes                    itemView.setIconTintList(mIconTintList);
386153fa9a03422419cd56b7d17def1ae907fc7b5cfChris Banes                    if (mTextAppearanceSet) {
387153fa9a03422419cd56b7d17def1ae907fc7b5cfChris Banes                        itemView.setTextAppearance(itemView.getContext(), mTextAppearance);
388153fa9a03422419cd56b7d17def1ae907fc7b5cfChris Banes                    }
389153fa9a03422419cd56b7d17def1ae907fc7b5cfChris Banes                    if (mTextColor != null) {
390153fa9a03422419cd56b7d17def1ae907fc7b5cfChris Banes                        itemView.setTextColor(mTextColor);
391153fa9a03422419cd56b7d17def1ae907fc7b5cfChris Banes                    }
3921a542ba7235ec038f7ec1ac0ed65f35d29f5c952Yuichi Araki                    itemView.setBackgroundDrawable(mItemBackground != null ?
3931a542ba7235ec038f7ec1ac0ed65f35d29f5c952Yuichi Araki                            mItemBackground.getConstantState().newDrawable() : null);
39464bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki                    NavigationMenuTextItem item = (NavigationMenuTextItem) mItems.get(position);
39501090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki                    itemView.initialize(item.getMenuItem(), 0);
39601090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki                    break;
39764bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki                }
39864bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki                case VIEW_TYPE_SUBHEADER: {
39964bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki                    TextView subHeader = (TextView) holder.itemView;
40064bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki                    NavigationMenuTextItem item = (NavigationMenuTextItem) mItems.get(position);
40101090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki                    subHeader.setText(item.getMenuItem().getTitle());
40201090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki                    break;
40364bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki                }
40464bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki                case VIEW_TYPE_SEPARATOR: {
40564bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki                    NavigationMenuSeparatorItem item =
40664bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki                            (NavigationMenuSeparatorItem) mItems.get(position);
40764bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki                    holder.itemView.setPadding(0, item.getPaddingTop(), 0,
40860abdeb39630c4c74a4c401e221f0c968caa26f5Yuichi Araki                            item.getPaddingBottom());
40901090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki                    break;
41064bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki                }
4117c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes                case VIEW_TYPE_HEADER: {
4127c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes                    break;
4137c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes                }
41431a49efe2adb59e31611f6871895a3243d835127Yuichi Araki            }
41501090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki
41601090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki        }
41701090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki
41801090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki        @Override
41964bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki        public void onViewRecycled(ViewHolder holder) {
42064bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki            if (holder instanceof NormalViewHolder) {
42164bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki                ((NavigationMenuItemView) holder.itemView).recycle();
42264bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki            }
42301090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki        }
42401090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki
42564bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki        public void update() {
4263a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes            prepareMenuItems();
42764bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki            notifyDataSetChanged();
4283a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes        }
4293a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes
4303a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes        /**
4313a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes         * Flattens the visible menu items of {@link #mMenu} into {@link #mItems},
4323a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes         * while inserting separators between items when necessary.
4333a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes         */
4343a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes        private void prepareMenuItems() {
43576bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki            if (mUpdateSuspended) {
43676bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki                return;
43776bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki            }
43842db3143bed767c8e826e69f214672be358078ebYuichi Araki            mUpdateSuspended = true;
4393a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes            mItems.clear();
4407c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes            mItems.add(new NavigationMenuHeaderItem());
44164bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki
4423a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes            int currentGroupId = -1;
4433a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes            int currentGroupStart = 0;
4443a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes            boolean currentGroupHasIcon = false;
4453a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes            for (int i = 0, totalSize = mMenu.getVisibleItems().size(); i < totalSize; i++) {
4463a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes                MenuItemImpl item = mMenu.getVisibleItems().get(i);
447f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki                if (item.isChecked()) {
448f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki                    setCheckedItem(item);
449f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki                }
450f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki                if (item.isCheckable()) {
451f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki                    item.setExclusiveCheckable(false);
452f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki                }
4533a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes                if (item.hasSubMenu()) {
4543a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes                    SubMenu subMenu = item.getSubMenu();
4553a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes                    if (subMenu.hasVisibleItems()) {
4563a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes                        if (i != 0) {
45764bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki                            mItems.add(new NavigationMenuSeparatorItem(mPaddingSeparator, 0));
4583a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes                        }
45964bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki                        mItems.add(new NavigationMenuTextItem(item));
4603a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes                        boolean subMenuHasIcon = false;
4613a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes                        int subMenuStart = mItems.size();
4623a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes                        for (int j = 0, size = subMenu.size(); j < size; j++) {
463f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki                            MenuItemImpl subMenuItem = (MenuItemImpl) subMenu.getItem(j);
4643a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes                            if (subMenuItem.isVisible()) {
4653a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes                                if (!subMenuHasIcon && subMenuItem.getIcon() != null) {
4663a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes                                    subMenuHasIcon = true;
4673a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes                                }
468f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki                                if (subMenuItem.isCheckable()) {
469f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki                                    subMenuItem.setExclusiveCheckable(false);
470f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki                                }
471f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki                                if (item.isChecked()) {
472f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki                                    setCheckedItem(item);
473f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki                                }
47464bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki                                mItems.add(new NavigationMenuTextItem(subMenuItem));
4753a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes                            }
4763a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes                        }
4773a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes                        if (subMenuHasIcon) {
4783a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes                            appendTransparentIconIfMissing(subMenuStart, mItems.size());
4793a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes                        }
4803a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes                    }
4813a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes                } else {
4823a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes                    int groupId = item.getGroupId();
4833a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes                    if (groupId != currentGroupId) { // first item in group
4843a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes                        currentGroupStart = mItems.size();
4853a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes                        currentGroupHasIcon = item.getIcon() != null;
4863a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes                        if (i != 0) {
4873a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes                            currentGroupStart++;
48864bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki                            mItems.add(new NavigationMenuSeparatorItem(
48960abdeb39630c4c74a4c401e221f0c968caa26f5Yuichi Araki                                    mPaddingSeparator, mPaddingSeparator));
4903a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes                        }
4913a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes                    } else if (!currentGroupHasIcon && item.getIcon() != null) {
4923a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes                        currentGroupHasIcon = true;
4933a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes                        appendTransparentIconIfMissing(currentGroupStart, mItems.size());
4943a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes                    }
4953a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes                    if (currentGroupHasIcon && item.getIcon() == null) {
4963a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes                        item.setIcon(android.R.color.transparent);
4973a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes                    }
49864bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki                    mItems.add(new NavigationMenuTextItem(item));
4993a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes                    currentGroupId = groupId;
5003a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes                }
5013a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes            }
50242db3143bed767c8e826e69f214672be358078ebYuichi Araki            mUpdateSuspended = false;
5033a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes        }
5043a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes
5053a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes        private void appendTransparentIconIfMissing(int startIndex, int endIndex) {
5063a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes            for (int i = startIndex; i < endIndex; i++) {
50764bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki                NavigationMenuTextItem textItem = (NavigationMenuTextItem) mItems.get(i);
50864bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki                MenuItem item = textItem.getMenuItem();
5093a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes                if (item.getIcon() == null) {
5103a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes                    if (mTransparentIcon == null) {
5113a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes                        mTransparentIcon = new ColorDrawable(android.R.color.transparent);
5123a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes                    }
5133a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes                    item.setIcon(mTransparentIcon);
5143a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes                }
5153a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes            }
5163a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes        }
51776bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki
518f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki        public void setCheckedItem(MenuItemImpl checkedItem) {
519f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki            if (mCheckedItem == checkedItem || !checkedItem.isCheckable()) {
520f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki                return;
521f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki            }
522f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki            if (mCheckedItem != null) {
523f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki                mCheckedItem.setChecked(false);
524f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki            }
525f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki            mCheckedItem = checkedItem;
526f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki            checkedItem.setChecked(true);
527f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki        }
528f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki
52976bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki        public Bundle createInstanceState() {
53076bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki            Bundle state = new Bundle();
531024b36390fce843107b0916f0c3468e5a67a212aYuichi Araki            if (mCheckedItem != null) {
532024b36390fce843107b0916f0c3468e5a67a212aYuichi Araki                state.putInt(STATE_CHECKED_ITEM, mCheckedItem.getItemId());
533024b36390fce843107b0916f0c3468e5a67a212aYuichi Araki            }
53436d347c02fa8da71ccd69634484be8156fa0085bYuichi Araki            // Store the states of the action views.
53536d347c02fa8da71ccd69634484be8156fa0085bYuichi Araki            SparseArray<ParcelableSparseArray> actionViewStates = new SparseArray<>();
53636d347c02fa8da71ccd69634484be8156fa0085bYuichi Araki            for (NavigationMenuItem navigationMenuItem : mItems) {
53764bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki                if (navigationMenuItem instanceof NavigationMenuTextItem) {
53864bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki                    MenuItemImpl item = ((NavigationMenuTextItem) navigationMenuItem).getMenuItem();
53964bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki                    View actionView = item != null ? item.getActionView() : null;
54064bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki                    if (actionView != null) {
54164bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki                        ParcelableSparseArray container = new ParcelableSparseArray();
54264bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki                        actionView.saveHierarchyState(container);
54364bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki                        actionViewStates.put(item.getItemId(), container);
54464bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki                    }
54536d347c02fa8da71ccd69634484be8156fa0085bYuichi Araki                }
54636d347c02fa8da71ccd69634484be8156fa0085bYuichi Araki            }
54736d347c02fa8da71ccd69634484be8156fa0085bYuichi Araki            state.putSparseParcelableArray(STATE_ACTION_VIEWS, actionViewStates);
54876bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki            return state;
54976bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki        }
55076bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki
55176bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki        public void restoreInstanceState(Bundle state) {
552f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki            int checkedItem = state.getInt(STATE_CHECKED_ITEM, 0);
553f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki            if (checkedItem != 0) {
55476bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki                mUpdateSuspended = true;
55576bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki                for (NavigationMenuItem item : mItems) {
55664bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki                    if (item instanceof NavigationMenuTextItem) {
55764bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki                        MenuItemImpl menuItem = ((NavigationMenuTextItem) item).getMenuItem();
55864bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki                        if (menuItem != null && menuItem.getItemId() == checkedItem) {
55964bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki                            setCheckedItem(menuItem);
56064bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki                            break;
56164bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki                        }
56276bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki                    }
56376bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki                }
56476bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki                mUpdateSuspended = false;
56576bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki                prepareMenuItems();
56676bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki            }
56736d347c02fa8da71ccd69634484be8156fa0085bYuichi Araki            // Restore the states of the action views.
56836d347c02fa8da71ccd69634484be8156fa0085bYuichi Araki            SparseArray<ParcelableSparseArray> actionViewStates = state
56936d347c02fa8da71ccd69634484be8156fa0085bYuichi Araki                    .getSparseParcelableArray(STATE_ACTION_VIEWS);
57036d347c02fa8da71ccd69634484be8156fa0085bYuichi Araki            for (NavigationMenuItem navigationMenuItem : mItems) {
57164bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki                if (navigationMenuItem instanceof NavigationMenuTextItem) {
57264bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki                    MenuItemImpl item = ((NavigationMenuTextItem) navigationMenuItem).getMenuItem();
57364bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki                    View actionView = item != null ? item.getActionView() : null;
57464bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki                    if (actionView != null) {
57564bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki                        actionView.restoreHierarchyState(actionViewStates.get(item.getItemId()));
57664bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki                    }
57736d347c02fa8da71ccd69634484be8156fa0085bYuichi Araki                }
57836d347c02fa8da71ccd69634484be8156fa0085bYuichi Araki            }
57976bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki        }
58076bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki
581cc7a09fc0018e348027151daecf581b1d1b78f11Yuichi Araki        public void setUpdateSuspended(boolean updateSuspended) {
582cc7a09fc0018e348027151daecf581b1d1b78f11Yuichi Araki            mUpdateSuspended = updateSuspended;
583cc7a09fc0018e348027151daecf581b1d1b78f11Yuichi Araki        }
584cc7a09fc0018e348027151daecf581b1d1b78f11Yuichi Araki
58501090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki    }
58601090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki
58701090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki    /**
58864bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki     * Unified data model for all sorts of navigation menu items.
589e7b2c26d2ffadc94dc6ee043ab12e03201e1bf95Yuichi Araki     */
59064bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki    private interface NavigationMenuItem {
59164bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki    }
59260abdeb39630c4c74a4c401e221f0c968caa26f5Yuichi Araki
59364bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki    /**
59464bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki     * Normal or subheader items.
59564bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki     */
59664bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki    private static class NavigationMenuTextItem implements NavigationMenuItem {
597e7b2c26d2ffadc94dc6ee043ab12e03201e1bf95Yuichi Araki
59864bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki        private final MenuItemImpl mMenuItem;
599e7b2c26d2ffadc94dc6ee043ab12e03201e1bf95Yuichi Araki
60064bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki        private NavigationMenuTextItem(MenuItemImpl item) {
601ca2f07c9cc83b98d73a18da7177044ee147ffb94Chris Banes            mMenuItem = item;
60260abdeb39630c4c74a4c401e221f0c968caa26f5Yuichi Araki        }
60360abdeb39630c4c74a4c401e221f0c968caa26f5Yuichi Araki
60464bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki        public MenuItemImpl getMenuItem() {
60564bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki            return mMenuItem;
606ca2f07c9cc83b98d73a18da7177044ee147ffb94Chris Banes        }
607ca2f07c9cc83b98d73a18da7177044ee147ffb94Chris Banes
60864bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki    }
60964bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki
61064bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki    /**
61164bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki     * Separator items.
61264bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki     */
61364bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki    private static class NavigationMenuSeparatorItem implements NavigationMenuItem {
614ca2f07c9cc83b98d73a18da7177044ee147ffb94Chris Banes
61564bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki        private final int mPaddingTop;
61664bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki
61764bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki        private final int mPaddingBottom;
61864bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki
61964bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki        public NavigationMenuSeparatorItem(int paddingTop, int paddingBottom) {
62064bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki            mPaddingTop = paddingTop;
62164bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki            mPaddingBottom = paddingBottom;
622ca2f07c9cc83b98d73a18da7177044ee147ffb94Chris Banes        }
623ca2f07c9cc83b98d73a18da7177044ee147ffb94Chris Banes
62460abdeb39630c4c74a4c401e221f0c968caa26f5Yuichi Araki        public int getPaddingTop() {
62560abdeb39630c4c74a4c401e221f0c968caa26f5Yuichi Araki            return mPaddingTop;
62660abdeb39630c4c74a4c401e221f0c968caa26f5Yuichi Araki        }
62760abdeb39630c4c74a4c401e221f0c968caa26f5Yuichi Araki
62860abdeb39630c4c74a4c401e221f0c968caa26f5Yuichi Araki        public int getPaddingBottom() {
62960abdeb39630c4c74a4c401e221f0c968caa26f5Yuichi Araki            return mPaddingBottom;
63001090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki        }
63101090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki
63264bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki    }
6337c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes
6347c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes    /**
6357c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes     * Header (not subheader) items.
6367c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes     */
6377c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes    private static class NavigationMenuHeaderItem implements NavigationMenuItem {
6387c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes        // The actual content is hold by NavigationMenuPresenter#mHeaderLayout.
6397c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes    }
6407c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes
64131a49efe2adb59e31611f6871895a3243d835127Yuichi Araki}
642