NavigationMenuPresenter.java revision 30d42dc19655e637644adc3846025027240bf0af
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(); 8860abdeb39630c4c74a4c401e221f0c968caa26f5Yuichi Araki mPaddingSeparator = res.getDimensionPixelOffset( 89a577676a64e5353b8ec927117151aa6be84adf66Chris Banes R.dimen.design_navigation_separator_vertical_padding); 9031a49efe2adb59e31611f6871895a3243d835127Yuichi Araki } 9131a49efe2adb59e31611f6871895a3243d835127Yuichi Araki 9231a49efe2adb59e31611f6871895a3243d835127Yuichi Araki @Override 9331a49efe2adb59e31611f6871895a3243d835127Yuichi Araki public MenuView getMenuView(ViewGroup root) { 9431a49efe2adb59e31611f6871895a3243d835127Yuichi Araki if (mMenuView == null) { 9531a49efe2adb59e31611f6871895a3243d835127Yuichi Araki mMenuView = (NavigationMenuView) mLayoutInflater.inflate( 96a5081dfb26b3664d97d5fe09b9b6a9c9667e0e9fYuichi Araki R.layout.design_navigation_menu, root, false); 9731a49efe2adb59e31611f6871895a3243d835127Yuichi Araki if (mAdapter == null) { 9831a49efe2adb59e31611f6871895a3243d835127Yuichi Araki mAdapter = new NavigationMenuAdapter(); 9931a49efe2adb59e31611f6871895a3243d835127Yuichi Araki } 1007c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes mHeaderLayout = (LinearLayout) mLayoutInflater 1017c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes .inflate(R.layout.design_navigation_item_header, 1027c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes mMenuView, false); 10331a49efe2adb59e31611f6871895a3243d835127Yuichi Araki mMenuView.setAdapter(mAdapter); 10431a49efe2adb59e31611f6871895a3243d835127Yuichi Araki } 10531a49efe2adb59e31611f6871895a3243d835127Yuichi Araki return mMenuView; 10631a49efe2adb59e31611f6871895a3243d835127Yuichi Araki } 10731a49efe2adb59e31611f6871895a3243d835127Yuichi Araki 10831a49efe2adb59e31611f6871895a3243d835127Yuichi Araki @Override 10931a49efe2adb59e31611f6871895a3243d835127Yuichi Araki public void updateMenuView(boolean cleared) { 11031a49efe2adb59e31611f6871895a3243d835127Yuichi Araki if (mAdapter != null) { 11164bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki mAdapter.update(); 11231a49efe2adb59e31611f6871895a3243d835127Yuichi Araki } 11331a49efe2adb59e31611f6871895a3243d835127Yuichi Araki } 11431a49efe2adb59e31611f6871895a3243d835127Yuichi Araki 11531a49efe2adb59e31611f6871895a3243d835127Yuichi Araki @Override 11631a49efe2adb59e31611f6871895a3243d835127Yuichi Araki public void setCallback(Callback cb) { 11731a49efe2adb59e31611f6871895a3243d835127Yuichi Araki mCallback = cb; 11831a49efe2adb59e31611f6871895a3243d835127Yuichi Araki } 11931a49efe2adb59e31611f6871895a3243d835127Yuichi Araki 12031a49efe2adb59e31611f6871895a3243d835127Yuichi Araki @Override 12131a49efe2adb59e31611f6871895a3243d835127Yuichi Araki public boolean onSubMenuSelected(SubMenuBuilder subMenu) { 12231a49efe2adb59e31611f6871895a3243d835127Yuichi Araki return false; 12331a49efe2adb59e31611f6871895a3243d835127Yuichi Araki } 12431a49efe2adb59e31611f6871895a3243d835127Yuichi Araki 12531a49efe2adb59e31611f6871895a3243d835127Yuichi Araki @Override 12631a49efe2adb59e31611f6871895a3243d835127Yuichi Araki public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) { 12731a49efe2adb59e31611f6871895a3243d835127Yuichi Araki if (mCallback != null) { 12831a49efe2adb59e31611f6871895a3243d835127Yuichi Araki mCallback.onCloseMenu(menu, allMenusAreClosing); 12931a49efe2adb59e31611f6871895a3243d835127Yuichi Araki } 13031a49efe2adb59e31611f6871895a3243d835127Yuichi Araki } 13131a49efe2adb59e31611f6871895a3243d835127Yuichi Araki 13231a49efe2adb59e31611f6871895a3243d835127Yuichi Araki @Override 13331a49efe2adb59e31611f6871895a3243d835127Yuichi Araki public boolean flagActionItems() { 13431a49efe2adb59e31611f6871895a3243d835127Yuichi Araki return false; 13531a49efe2adb59e31611f6871895a3243d835127Yuichi Araki } 13631a49efe2adb59e31611f6871895a3243d835127Yuichi Araki 13731a49efe2adb59e31611f6871895a3243d835127Yuichi Araki @Override 13831a49efe2adb59e31611f6871895a3243d835127Yuichi Araki public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item) { 13931a49efe2adb59e31611f6871895a3243d835127Yuichi Araki return false; 14031a49efe2adb59e31611f6871895a3243d835127Yuichi Araki } 14131a49efe2adb59e31611f6871895a3243d835127Yuichi Araki 14231a49efe2adb59e31611f6871895a3243d835127Yuichi Araki @Override 14331a49efe2adb59e31611f6871895a3243d835127Yuichi Araki public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item) { 14431a49efe2adb59e31611f6871895a3243d835127Yuichi Araki return false; 14531a49efe2adb59e31611f6871895a3243d835127Yuichi Araki } 14631a49efe2adb59e31611f6871895a3243d835127Yuichi Araki 14731a49efe2adb59e31611f6871895a3243d835127Yuichi Araki @Override 14831a49efe2adb59e31611f6871895a3243d835127Yuichi Araki public int getId() { 14931a49efe2adb59e31611f6871895a3243d835127Yuichi Araki return mId; 15031a49efe2adb59e31611f6871895a3243d835127Yuichi Araki } 15131a49efe2adb59e31611f6871895a3243d835127Yuichi Araki 15231a49efe2adb59e31611f6871895a3243d835127Yuichi Araki public void setId(int id) { 15331a49efe2adb59e31611f6871895a3243d835127Yuichi Araki mId = id; 15431a49efe2adb59e31611f6871895a3243d835127Yuichi Araki } 15531a49efe2adb59e31611f6871895a3243d835127Yuichi Araki 15631a49efe2adb59e31611f6871895a3243d835127Yuichi Araki @Override 15731a49efe2adb59e31611f6871895a3243d835127Yuichi Araki public Parcelable onSaveInstanceState() { 15801090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki Bundle state = new Bundle(); 15901090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki if (mMenuView != null) { 16076bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki SparseArray<Parcelable> hierarchy = new SparseArray<>(); 16101090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki mMenuView.saveHierarchyState(hierarchy); 16276bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki state.putSparseParcelableArray(STATE_HIERARCHY, hierarchy); 16376bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki } 16476bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki if (mAdapter != null) { 16576bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki state.putBundle(STATE_ADAPTER, mAdapter.createInstanceState()); 16601090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki } 16701090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki return state; 16831a49efe2adb59e31611f6871895a3243d835127Yuichi Araki } 16931a49efe2adb59e31611f6871895a3243d835127Yuichi Araki 17031a49efe2adb59e31611f6871895a3243d835127Yuichi Araki @Override 17101090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki public void onRestoreInstanceState(Parcelable parcelable) { 17201090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki Bundle state = (Bundle) parcelable; 17301090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki SparseArray<Parcelable> hierarchy = state.getSparseParcelableArray(STATE_HIERARCHY); 17401090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki if (hierarchy != null) { 17501090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki mMenuView.restoreHierarchyState(hierarchy); 17601090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki } 17776bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki Bundle adapterState = state.getBundle(STATE_ADAPTER); 17876bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki if (adapterState != null) { 17976bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki mAdapter.restoreInstanceState(adapterState); 18076bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki } 18131a49efe2adb59e31611f6871895a3243d835127Yuichi Araki } 18231a49efe2adb59e31611f6871895a3243d835127Yuichi Araki 183f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki public void setCheckedItem(MenuItemImpl item) { 184f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki mAdapter.setCheckedItem(item); 185f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki } 186f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki 1877c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes public View inflateHeaderView(@LayoutRes int res) { 1887c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes View view = mLayoutInflater.inflate(res, mHeaderLayout, false); 1897c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes addHeaderView(view); 1907c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes return view; 1917c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes } 1927c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes 19301090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki public void addHeaderView(@NonNull View view) { 1947c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes mHeaderLayout.addView(view); 1957c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes // The padding on top should be cleared. 19660abdeb39630c4c74a4c401e221f0c968caa26f5Yuichi Araki mMenuView.setPadding(0, 0, 0, mMenuView.getPaddingBottom()); 19701090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki } 19801090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki 1997c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes public void removeHeaderView(@NonNull View view) { 2007c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes mHeaderLayout.removeView(view); 2017c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes if (mHeaderLayout.getChildCount() == 0) { 20272fa50f289d462aae5038e8dd78e134a0fffcf12Yuichi Araki mMenuView.setPadding(0, mPaddingTopDefault, 0, mMenuView.getPaddingBottom()); 20301090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki } 20431a49efe2adb59e31611f6871895a3243d835127Yuichi Araki } 20531a49efe2adb59e31611f6871895a3243d835127Yuichi Araki 206cdccc4c6d5f1e40610ce4df4afeb1f99cbdb63e8Yuichi Araki public int getHeaderCount() { 207cdccc4c6d5f1e40610ce4df4afeb1f99cbdb63e8Yuichi Araki return mHeaderLayout.getChildCount(); 208cdccc4c6d5f1e40610ce4df4afeb1f99cbdb63e8Yuichi Araki } 209cdccc4c6d5f1e40610ce4df4afeb1f99cbdb63e8Yuichi Araki 210cdccc4c6d5f1e40610ce4df4afeb1f99cbdb63e8Yuichi Araki public View getHeaderView(int index) { 211cdccc4c6d5f1e40610ce4df4afeb1f99cbdb63e8Yuichi Araki return mHeaderLayout.getChildAt(index); 212cdccc4c6d5f1e40610ce4df4afeb1f99cbdb63e8Yuichi Araki } 213cdccc4c6d5f1e40610ce4df4afeb1f99cbdb63e8Yuichi Araki 214d3ee2c7d22c0cb204ea9077fa9e64511266d6799Yuichi Araki @Nullable 215d3ee2c7d22c0cb204ea9077fa9e64511266d6799Yuichi Araki public ColorStateList getItemTintList() { 216a63940ca14cd3ad9620e94f709930bb968525c57Chris Banes return mIconTintList; 217d3ee2c7d22c0cb204ea9077fa9e64511266d6799Yuichi Araki } 218d3ee2c7d22c0cb204ea9077fa9e64511266d6799Yuichi Araki 219a63940ca14cd3ad9620e94f709930bb968525c57Chris Banes public void setItemIconTintList(@Nullable ColorStateList tint) { 220a63940ca14cd3ad9620e94f709930bb968525c57Chris Banes mIconTintList = tint; 221153fa9a03422419cd56b7d17def1ae907fc7b5cfChris Banes updateMenuView(false); 222d3ee2c7d22c0cb204ea9077fa9e64511266d6799Yuichi Araki } 223d3ee2c7d22c0cb204ea9077fa9e64511266d6799Yuichi Araki 224a63940ca14cd3ad9620e94f709930bb968525c57Chris Banes @Nullable 225a63940ca14cd3ad9620e94f709930bb968525c57Chris Banes public ColorStateList getItemTextColor() { 226a63940ca14cd3ad9620e94f709930bb968525c57Chris Banes return mTextColor; 227a63940ca14cd3ad9620e94f709930bb968525c57Chris Banes } 228a63940ca14cd3ad9620e94f709930bb968525c57Chris Banes 229a63940ca14cd3ad9620e94f709930bb968525c57Chris Banes public void setItemTextColor(@Nullable ColorStateList textColor) { 230a63940ca14cd3ad9620e94f709930bb968525c57Chris Banes mTextColor = textColor; 231153fa9a03422419cd56b7d17def1ae907fc7b5cfChris Banes updateMenuView(false); 232153fa9a03422419cd56b7d17def1ae907fc7b5cfChris Banes } 233153fa9a03422419cd56b7d17def1ae907fc7b5cfChris Banes 234153fa9a03422419cd56b7d17def1ae907fc7b5cfChris Banes public void setItemTextAppearance(@StyleRes int resId) { 235153fa9a03422419cd56b7d17def1ae907fc7b5cfChris Banes mTextAppearance = resId; 236153fa9a03422419cd56b7d17def1ae907fc7b5cfChris Banes mTextAppearanceSet = true; 237153fa9a03422419cd56b7d17def1ae907fc7b5cfChris Banes updateMenuView(false); 238a63940ca14cd3ad9620e94f709930bb968525c57Chris Banes } 239a63940ca14cd3ad9620e94f709930bb968525c57Chris Banes 240a63940ca14cd3ad9620e94f709930bb968525c57Chris Banes public Drawable getItemBackground() { 241a63940ca14cd3ad9620e94f709930bb968525c57Chris Banes return mItemBackground; 242d3ee2c7d22c0cb204ea9077fa9e64511266d6799Yuichi Araki } 243d3ee2c7d22c0cb204ea9077fa9e64511266d6799Yuichi Araki 244a63940ca14cd3ad9620e94f709930bb968525c57Chris Banes public void setItemBackground(Drawable itemBackground) { 245a63940ca14cd3ad9620e94f709930bb968525c57Chris Banes mItemBackground = itemBackground; 246d3ee2c7d22c0cb204ea9077fa9e64511266d6799Yuichi Araki } 247d3ee2c7d22c0cb204ea9077fa9e64511266d6799Yuichi Araki 248cc7a09fc0018e348027151daecf581b1d1b78f11Yuichi Araki public void setUpdateSuspended(boolean updateSuspended) { 249cc7a09fc0018e348027151daecf581b1d1b78f11Yuichi Araki if (mAdapter != null) { 250cc7a09fc0018e348027151daecf581b1d1b78f11Yuichi Araki mAdapter.setUpdateSuspended(updateSuspended); 251cc7a09fc0018e348027151daecf581b1d1b78f11Yuichi Araki } 252cc7a09fc0018e348027151daecf581b1d1b78f11Yuichi Araki } 253cc7a09fc0018e348027151daecf581b1d1b78f11Yuichi Araki 25430d42dc19655e637644adc3846025027240bf0afYuichi Araki public void setPaddingTopDefault(int paddingTopDefault) { 25530d42dc19655e637644adc3846025027240bf0afYuichi Araki if (mPaddingTopDefault != paddingTopDefault) { 25630d42dc19655e637644adc3846025027240bf0afYuichi Araki mPaddingTopDefault = paddingTopDefault; 25730d42dc19655e637644adc3846025027240bf0afYuichi Araki if (mHeaderLayout.getChildCount() == 0) { 25830d42dc19655e637644adc3846025027240bf0afYuichi Araki mMenuView.setPadding(0, mPaddingTopDefault, 0, mMenuView.getPaddingBottom()); 25930d42dc19655e637644adc3846025027240bf0afYuichi Araki } 26030d42dc19655e637644adc3846025027240bf0afYuichi Araki } 26130d42dc19655e637644adc3846025027240bf0afYuichi Araki } 26230d42dc19655e637644adc3846025027240bf0afYuichi Araki 26364bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki private abstract static class ViewHolder extends RecyclerView.ViewHolder { 26464bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki 26564bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki public ViewHolder(View itemView) { 26664bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki super(itemView); 26764bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki } 26864bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki 26964bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki } 27064bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki 27164bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki private static class NormalViewHolder extends ViewHolder { 27264bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki 27364bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki public NormalViewHolder(LayoutInflater inflater, ViewGroup parent, 27464bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki View.OnClickListener listener) { 27564bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki super(inflater.inflate(R.layout.design_navigation_item, parent, false)); 27664bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki itemView.setOnClickListener(listener); 27764bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki } 27864bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki 27964bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki } 28064bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki 28164bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki private static class SubheaderViewHolder extends ViewHolder { 28264bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki 28364bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki public SubheaderViewHolder(LayoutInflater inflater, ViewGroup parent) { 28464bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki super(inflater.inflate(R.layout.design_navigation_item_subheader, parent, false)); 28564bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki } 28664bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki 28764bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki } 28864bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki 28964bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki private static class SeparatorViewHolder extends ViewHolder { 29064bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki 29164bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki public SeparatorViewHolder(LayoutInflater inflater, ViewGroup parent) { 29264bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki super(inflater.inflate(R.layout.design_navigation_item_separator, parent, false)); 29364bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki } 29464bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki 29564bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki } 29664bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki 2977c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes private static class HeaderViewHolder extends ViewHolder { 2987c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes 2997c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes public HeaderViewHolder(View itemView) { 3007c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes super(itemView); 3017c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes } 3027c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes 3037c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes } 3047c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes 30564bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki /** 30664bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki * Handles click events for the menu items. The items has to be {@link NavigationMenuItemView}. 30764bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki */ 30864bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki private final View.OnClickListener mOnClickListener = new View.OnClickListener() { 30964bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki 31064bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki @Override 31164bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki public void onClick(View v) { 31264bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki NavigationMenuItemView itemView = (NavigationMenuItemView) v; 31364bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki setUpdateSuspended(true); 31464bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki MenuItemImpl item = itemView.getItemData(); 31564bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki boolean result = mMenu.performItemAction(item, NavigationMenuPresenter.this, 0); 31664bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki if (item != null && item.isCheckable() && result) { 31764bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki mAdapter.setCheckedItem(item); 31864bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki } 31964bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki setUpdateSuspended(false); 32064bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki updateMenuView(false); 32164bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki } 32264bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki 32364bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki }; 32464bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki 32564bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki private class NavigationMenuAdapter extends RecyclerView.Adapter<ViewHolder> { 32676bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki 327f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki private static final String STATE_CHECKED_ITEM = "android:menu:checked"; 32876bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki 32936d347c02fa8da71ccd69634484be8156fa0085bYuichi Araki private static final String STATE_ACTION_VIEWS = "android:menu:action_views"; 33001090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki private static final int VIEW_TYPE_NORMAL = 0; 33101090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki private static final int VIEW_TYPE_SUBHEADER = 1; 33201090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki private static final int VIEW_TYPE_SEPARATOR = 2; 3337c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes private static final int VIEW_TYPE_HEADER = 3; 33401090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki 3353a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes private final ArrayList<NavigationMenuItem> mItems = new ArrayList<>(); 336f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki private MenuItemImpl mCheckedItem; 3373a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes private ColorDrawable mTransparentIcon; 33876bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki private boolean mUpdateSuspended; 3393a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes 3403a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes NavigationMenuAdapter() { 3413a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes prepareMenuItems(); 3423a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes } 3433a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes 34431a49efe2adb59e31611f6871895a3243d835127Yuichi Araki @Override 34531a49efe2adb59e31611f6871895a3243d835127Yuichi Araki public long getItemId(int position) { 34631a49efe2adb59e31611f6871895a3243d835127Yuichi Araki return position; 34731a49efe2adb59e31611f6871895a3243d835127Yuichi Araki } 34831a49efe2adb59e31611f6871895a3243d835127Yuichi Araki 34931a49efe2adb59e31611f6871895a3243d835127Yuichi Araki @Override 35064bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki public int getItemCount() { 35164bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki return mItems.size(); 35201090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki } 35301090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki 35401090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki @Override 35501090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki public int getItemViewType(int position) { 35664bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki NavigationMenuItem item = mItems.get(position); 35764bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki if (item instanceof NavigationMenuSeparatorItem) { 35801090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki return VIEW_TYPE_SEPARATOR; 3597c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes } else if (item instanceof NavigationMenuHeaderItem) { 3607c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes return VIEW_TYPE_HEADER; 36164bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki } else if (item instanceof NavigationMenuTextItem) { 36264bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki NavigationMenuTextItem textItem = (NavigationMenuTextItem) item; 36364bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki if (textItem.getMenuItem().hasSubMenu()) { 36464bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki return VIEW_TYPE_SUBHEADER; 36564bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki } else { 36664bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki return VIEW_TYPE_NORMAL; 36764bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki } 36801090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki } 36964bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki throw new RuntimeException("Unknown item type."); 37001090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki } 37101090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki 37201090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki @Override 37364bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 37401090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki switch (viewType) { 37501090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki case VIEW_TYPE_NORMAL: 37664bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki return new NormalViewHolder(mLayoutInflater, parent, mOnClickListener); 37764bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki case VIEW_TYPE_SUBHEADER: 37864bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki return new SubheaderViewHolder(mLayoutInflater, parent); 37964bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki case VIEW_TYPE_SEPARATOR: 38064bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki return new SeparatorViewHolder(mLayoutInflater, parent); 3817c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes case VIEW_TYPE_HEADER: 3827c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes return new HeaderViewHolder(mHeaderLayout); 38364bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki } 38464bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki return null; 38564bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki } 38664bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki 38764bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki @Override 38864bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki public void onBindViewHolder(ViewHolder holder, int position) { 38964bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki switch (getItemViewType(position)) { 39064bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki case VIEW_TYPE_NORMAL: { 39164bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki NavigationMenuItemView itemView = (NavigationMenuItemView) holder.itemView; 392a63940ca14cd3ad9620e94f709930bb968525c57Chris Banes itemView.setIconTintList(mIconTintList); 393153fa9a03422419cd56b7d17def1ae907fc7b5cfChris Banes if (mTextAppearanceSet) { 394153fa9a03422419cd56b7d17def1ae907fc7b5cfChris Banes itemView.setTextAppearance(itemView.getContext(), mTextAppearance); 395153fa9a03422419cd56b7d17def1ae907fc7b5cfChris Banes } 396153fa9a03422419cd56b7d17def1ae907fc7b5cfChris Banes if (mTextColor != null) { 397153fa9a03422419cd56b7d17def1ae907fc7b5cfChris Banes itemView.setTextColor(mTextColor); 398153fa9a03422419cd56b7d17def1ae907fc7b5cfChris Banes } 3991a542ba7235ec038f7ec1ac0ed65f35d29f5c952Yuichi Araki itemView.setBackgroundDrawable(mItemBackground != null ? 4001a542ba7235ec038f7ec1ac0ed65f35d29f5c952Yuichi Araki mItemBackground.getConstantState().newDrawable() : null); 40164bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki NavigationMenuTextItem item = (NavigationMenuTextItem) mItems.get(position); 40201090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki itemView.initialize(item.getMenuItem(), 0); 40301090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki break; 40464bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki } 40564bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki case VIEW_TYPE_SUBHEADER: { 40664bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki TextView subHeader = (TextView) holder.itemView; 40764bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki NavigationMenuTextItem item = (NavigationMenuTextItem) mItems.get(position); 40801090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki subHeader.setText(item.getMenuItem().getTitle()); 40901090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki break; 41064bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki } 41164bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki case VIEW_TYPE_SEPARATOR: { 41264bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki NavigationMenuSeparatorItem item = 41364bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki (NavigationMenuSeparatorItem) mItems.get(position); 41464bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki holder.itemView.setPadding(0, item.getPaddingTop(), 0, 41560abdeb39630c4c74a4c401e221f0c968caa26f5Yuichi Araki item.getPaddingBottom()); 41601090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki break; 41764bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki } 4187c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes case VIEW_TYPE_HEADER: { 4197c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes break; 4207c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes } 42131a49efe2adb59e31611f6871895a3243d835127Yuichi Araki } 42201090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki 42301090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki } 42401090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki 42501090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki @Override 42664bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki public void onViewRecycled(ViewHolder holder) { 42764bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki if (holder instanceof NormalViewHolder) { 42864bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki ((NavigationMenuItemView) holder.itemView).recycle(); 42964bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki } 43001090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki } 43101090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki 43264bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki public void update() { 4333a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes prepareMenuItems(); 43464bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki notifyDataSetChanged(); 4353a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes } 4363a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes 4373a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes /** 4383a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes * Flattens the visible menu items of {@link #mMenu} into {@link #mItems}, 4393a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes * while inserting separators between items when necessary. 4403a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes */ 4413a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes private void prepareMenuItems() { 44276bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki if (mUpdateSuspended) { 44376bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki return; 44476bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki } 44542db3143bed767c8e826e69f214672be358078ebYuichi Araki mUpdateSuspended = true; 4463a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes mItems.clear(); 4477c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes mItems.add(new NavigationMenuHeaderItem()); 44864bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki 4493a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes int currentGroupId = -1; 4503a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes int currentGroupStart = 0; 4513a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes boolean currentGroupHasIcon = false; 4523a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes for (int i = 0, totalSize = mMenu.getVisibleItems().size(); i < totalSize; i++) { 4533a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes MenuItemImpl item = mMenu.getVisibleItems().get(i); 454f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki if (item.isChecked()) { 455f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki setCheckedItem(item); 456f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki } 457f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki if (item.isCheckable()) { 458f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki item.setExclusiveCheckable(false); 459f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki } 4603a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes if (item.hasSubMenu()) { 4613a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes SubMenu subMenu = item.getSubMenu(); 4623a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes if (subMenu.hasVisibleItems()) { 4633a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes if (i != 0) { 46464bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki mItems.add(new NavigationMenuSeparatorItem(mPaddingSeparator, 0)); 4653a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes } 46664bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki mItems.add(new NavigationMenuTextItem(item)); 4673a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes boolean subMenuHasIcon = false; 4683a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes int subMenuStart = mItems.size(); 4693a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes for (int j = 0, size = subMenu.size(); j < size; j++) { 470f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki MenuItemImpl subMenuItem = (MenuItemImpl) subMenu.getItem(j); 4713a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes if (subMenuItem.isVisible()) { 4723a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes if (!subMenuHasIcon && subMenuItem.getIcon() != null) { 4733a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes subMenuHasIcon = true; 4743a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes } 475f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki if (subMenuItem.isCheckable()) { 476f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki subMenuItem.setExclusiveCheckable(false); 477f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki } 478f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki if (item.isChecked()) { 479f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki setCheckedItem(item); 480f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki } 48164bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki mItems.add(new NavigationMenuTextItem(subMenuItem)); 4823a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes } 4833a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes } 4843a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes if (subMenuHasIcon) { 4853a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes appendTransparentIconIfMissing(subMenuStart, mItems.size()); 4863a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes } 4873a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes } 4883a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes } else { 4893a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes int groupId = item.getGroupId(); 4903a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes if (groupId != currentGroupId) { // first item in group 4913a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes currentGroupStart = mItems.size(); 4923a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes currentGroupHasIcon = item.getIcon() != null; 4933a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes if (i != 0) { 4943a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes currentGroupStart++; 49564bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki mItems.add(new NavigationMenuSeparatorItem( 49660abdeb39630c4c74a4c401e221f0c968caa26f5Yuichi Araki mPaddingSeparator, mPaddingSeparator)); 4973a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes } 4983a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes } else if (!currentGroupHasIcon && item.getIcon() != null) { 4993a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes currentGroupHasIcon = true; 5003a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes appendTransparentIconIfMissing(currentGroupStart, mItems.size()); 5013a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes } 5023a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes if (currentGroupHasIcon && item.getIcon() == null) { 5033a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes item.setIcon(android.R.color.transparent); 5043a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes } 50564bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki mItems.add(new NavigationMenuTextItem(item)); 5063a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes currentGroupId = groupId; 5073a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes } 5083a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes } 50942db3143bed767c8e826e69f214672be358078ebYuichi Araki mUpdateSuspended = false; 5103a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes } 5113a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes 5123a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes private void appendTransparentIconIfMissing(int startIndex, int endIndex) { 5133a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes for (int i = startIndex; i < endIndex; i++) { 51464bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki NavigationMenuTextItem textItem = (NavigationMenuTextItem) mItems.get(i); 51564bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki MenuItem item = textItem.getMenuItem(); 5163a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes if (item.getIcon() == null) { 5173a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes if (mTransparentIcon == null) { 5183a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes mTransparentIcon = new ColorDrawable(android.R.color.transparent); 5193a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes } 5203a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes item.setIcon(mTransparentIcon); 5213a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes } 5223a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes } 5233a2c9c408e240e761b043139c5d228d3ad93f6c2Chris Banes } 52476bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki 525f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki public void setCheckedItem(MenuItemImpl checkedItem) { 526f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki if (mCheckedItem == checkedItem || !checkedItem.isCheckable()) { 527f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki return; 528f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki } 529f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki if (mCheckedItem != null) { 530f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki mCheckedItem.setChecked(false); 531f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki } 532f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki mCheckedItem = checkedItem; 533f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki checkedItem.setChecked(true); 534f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki } 535f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki 53676bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki public Bundle createInstanceState() { 53776bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki Bundle state = new Bundle(); 538024b36390fce843107b0916f0c3468e5a67a212aYuichi Araki if (mCheckedItem != null) { 539024b36390fce843107b0916f0c3468e5a67a212aYuichi Araki state.putInt(STATE_CHECKED_ITEM, mCheckedItem.getItemId()); 540024b36390fce843107b0916f0c3468e5a67a212aYuichi Araki } 54136d347c02fa8da71ccd69634484be8156fa0085bYuichi Araki // Store the states of the action views. 54236d347c02fa8da71ccd69634484be8156fa0085bYuichi Araki SparseArray<ParcelableSparseArray> actionViewStates = new SparseArray<>(); 54336d347c02fa8da71ccd69634484be8156fa0085bYuichi Araki for (NavigationMenuItem navigationMenuItem : mItems) { 54464bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki if (navigationMenuItem instanceof NavigationMenuTextItem) { 54564bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki MenuItemImpl item = ((NavigationMenuTextItem) navigationMenuItem).getMenuItem(); 54664bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki View actionView = item != null ? item.getActionView() : null; 54764bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki if (actionView != null) { 54864bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki ParcelableSparseArray container = new ParcelableSparseArray(); 54964bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki actionView.saveHierarchyState(container); 55064bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki actionViewStates.put(item.getItemId(), container); 55164bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki } 55236d347c02fa8da71ccd69634484be8156fa0085bYuichi Araki } 55336d347c02fa8da71ccd69634484be8156fa0085bYuichi Araki } 55436d347c02fa8da71ccd69634484be8156fa0085bYuichi Araki state.putSparseParcelableArray(STATE_ACTION_VIEWS, actionViewStates); 55576bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki return state; 55676bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki } 55776bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki 55876bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki public void restoreInstanceState(Bundle state) { 559f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki int checkedItem = state.getInt(STATE_CHECKED_ITEM, 0); 560f9b8005bf607feddd9b482f817bd68c46739e4f1Yuichi Araki if (checkedItem != 0) { 56176bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki mUpdateSuspended = true; 56276bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki for (NavigationMenuItem item : mItems) { 56364bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki if (item instanceof NavigationMenuTextItem) { 56464bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki MenuItemImpl menuItem = ((NavigationMenuTextItem) item).getMenuItem(); 56564bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki if (menuItem != null && menuItem.getItemId() == checkedItem) { 56664bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki setCheckedItem(menuItem); 56764bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki break; 56864bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki } 56976bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki } 57076bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki } 57176bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki mUpdateSuspended = false; 57276bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki prepareMenuItems(); 57376bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki } 57436d347c02fa8da71ccd69634484be8156fa0085bYuichi Araki // Restore the states of the action views. 57536d347c02fa8da71ccd69634484be8156fa0085bYuichi Araki SparseArray<ParcelableSparseArray> actionViewStates = state 57636d347c02fa8da71ccd69634484be8156fa0085bYuichi Araki .getSparseParcelableArray(STATE_ACTION_VIEWS); 57736d347c02fa8da71ccd69634484be8156fa0085bYuichi Araki for (NavigationMenuItem navigationMenuItem : mItems) { 57864bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki if (navigationMenuItem instanceof NavigationMenuTextItem) { 57964bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki MenuItemImpl item = ((NavigationMenuTextItem) navigationMenuItem).getMenuItem(); 58064bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki View actionView = item != null ? item.getActionView() : null; 58164bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki if (actionView != null) { 58264bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki actionView.restoreHierarchyState(actionViewStates.get(item.getItemId())); 58364bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki } 58436d347c02fa8da71ccd69634484be8156fa0085bYuichi Araki } 58536d347c02fa8da71ccd69634484be8156fa0085bYuichi Araki } 58676bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki } 58776bd4d2c1173100ab73c4f27dc42dd917c48915fYuichi Araki 588cc7a09fc0018e348027151daecf581b1d1b78f11Yuichi Araki public void setUpdateSuspended(boolean updateSuspended) { 589cc7a09fc0018e348027151daecf581b1d1b78f11Yuichi Araki mUpdateSuspended = updateSuspended; 590cc7a09fc0018e348027151daecf581b1d1b78f11Yuichi Araki } 591cc7a09fc0018e348027151daecf581b1d1b78f11Yuichi Araki 59201090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki } 59301090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki 59401090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki /** 59564bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki * Unified data model for all sorts of navigation menu items. 596e7b2c26d2ffadc94dc6ee043ab12e03201e1bf95Yuichi Araki */ 59764bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki private interface NavigationMenuItem { 59864bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki } 59960abdeb39630c4c74a4c401e221f0c968caa26f5Yuichi Araki 60064bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki /** 60164bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki * Normal or subheader items. 60264bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki */ 60364bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki private static class NavigationMenuTextItem implements NavigationMenuItem { 604e7b2c26d2ffadc94dc6ee043ab12e03201e1bf95Yuichi Araki 60564bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki private final MenuItemImpl mMenuItem; 606e7b2c26d2ffadc94dc6ee043ab12e03201e1bf95Yuichi Araki 60764bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki private NavigationMenuTextItem(MenuItemImpl item) { 608ca2f07c9cc83b98d73a18da7177044ee147ffb94Chris Banes mMenuItem = item; 60960abdeb39630c4c74a4c401e221f0c968caa26f5Yuichi Araki } 61060abdeb39630c4c74a4c401e221f0c968caa26f5Yuichi Araki 61164bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki public MenuItemImpl getMenuItem() { 61264bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki return mMenuItem; 613ca2f07c9cc83b98d73a18da7177044ee147ffb94Chris Banes } 614ca2f07c9cc83b98d73a18da7177044ee147ffb94Chris Banes 61564bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki } 61664bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki 61764bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki /** 61864bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki * Separator items. 61964bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki */ 62064bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki private static class NavigationMenuSeparatorItem implements NavigationMenuItem { 621ca2f07c9cc83b98d73a18da7177044ee147ffb94Chris Banes 62264bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki private final int mPaddingTop; 62364bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki 62464bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki private final int mPaddingBottom; 62564bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki 62664bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki public NavigationMenuSeparatorItem(int paddingTop, int paddingBottom) { 62764bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki mPaddingTop = paddingTop; 62864bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki mPaddingBottom = paddingBottom; 629ca2f07c9cc83b98d73a18da7177044ee147ffb94Chris Banes } 630ca2f07c9cc83b98d73a18da7177044ee147ffb94Chris Banes 63160abdeb39630c4c74a4c401e221f0c968caa26f5Yuichi Araki public int getPaddingTop() { 63260abdeb39630c4c74a4c401e221f0c968caa26f5Yuichi Araki return mPaddingTop; 63360abdeb39630c4c74a4c401e221f0c968caa26f5Yuichi Araki } 63460abdeb39630c4c74a4c401e221f0c968caa26f5Yuichi Araki 63560abdeb39630c4c74a4c401e221f0c968caa26f5Yuichi Araki public int getPaddingBottom() { 63660abdeb39630c4c74a4c401e221f0c968caa26f5Yuichi Araki return mPaddingBottom; 63701090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki } 63801090f9556e7518c9ee206de6efe42de9003f6f5Yuichi Araki 63964bcb674cc45ab712a591d4f540d5c13404f3b83Yuichi Araki } 6407c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes 6417c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes /** 6427c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes * Header (not subheader) items. 6437c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes */ 6447c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes private static class NavigationMenuHeaderItem implements NavigationMenuItem { 6457c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes // The actual content is hold by NavigationMenuPresenter#mHeaderLayout. 6467c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes } 6477c89489dcb1e7cc454da4375c387caf20201acb7Chris Banes 64831a49efe2adb59e31611f6871895a3243d835127Yuichi Araki} 649