635 lines
19 KiB
Java
635 lines
19 KiB
Java
/*
|
|
* Copyright (C) 2014 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package android.support.v7.internal.app;
|
|
|
|
import android.content.Context;
|
|
import android.content.res.Configuration;
|
|
import android.content.res.Resources;
|
|
import android.graphics.drawable.Drawable;
|
|
import android.support.annotation.Nullable;
|
|
import android.support.v4.view.ViewCompat;
|
|
import android.support.v4.view.WindowCompat;
|
|
import android.support.v7.app.ActionBar;
|
|
import android.support.v7.internal.view.WindowCallbackWrapper;
|
|
import android.support.v7.appcompat.R;
|
|
import android.support.v7.internal.view.menu.ListMenuPresenter;
|
|
import android.support.v7.internal.view.menu.MenuBuilder;
|
|
import android.support.v7.internal.view.menu.MenuPresenter;
|
|
import android.support.v7.internal.widget.DecorToolbar;
|
|
import android.support.v7.internal.widget.ToolbarWidgetWrapper;
|
|
import android.support.v7.widget.Toolbar;
|
|
import android.util.TypedValue;
|
|
import android.view.ContextThemeWrapper;
|
|
import android.view.KeyEvent;
|
|
import android.view.LayoutInflater;
|
|
import android.view.Menu;
|
|
import android.view.MenuItem;
|
|
import android.view.View;
|
|
import android.view.Window;
|
|
import android.widget.SpinnerAdapter;
|
|
|
|
import java.util.ArrayList;
|
|
|
|
/**
|
|
* @hide
|
|
*/
|
|
public class ToolbarActionBar extends ActionBar {
|
|
private DecorToolbar mDecorToolbar;
|
|
private boolean mToolbarMenuPrepared;
|
|
private Window.Callback mWindowCallback;
|
|
private boolean mMenuCallbackSet;
|
|
|
|
private boolean mLastMenuVisibility;
|
|
private ArrayList<OnMenuVisibilityListener> mMenuVisibilityListeners =
|
|
new ArrayList<OnMenuVisibilityListener>();
|
|
|
|
private Window mWindow;
|
|
private ListMenuPresenter mListMenuPresenter;
|
|
|
|
private final Runnable mMenuInvalidator = new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
populateOptionsMenu();
|
|
}
|
|
};
|
|
|
|
private final Toolbar.OnMenuItemClickListener mMenuClicker =
|
|
new Toolbar.OnMenuItemClickListener() {
|
|
@Override
|
|
public boolean onMenuItemClick(MenuItem item) {
|
|
return mWindowCallback.onMenuItemSelected(Window.FEATURE_OPTIONS_PANEL, item);
|
|
}
|
|
};
|
|
|
|
public ToolbarActionBar(Toolbar toolbar, CharSequence title, Window window) {
|
|
mDecorToolbar = new ToolbarWidgetWrapper(toolbar, false);
|
|
mWindowCallback = new ToolbarCallbackWrapper(window.getCallback());
|
|
mDecorToolbar.setWindowCallback(mWindowCallback);
|
|
toolbar.setOnMenuItemClickListener(mMenuClicker);
|
|
mDecorToolbar.setWindowTitle(title);
|
|
|
|
mWindow = window;
|
|
}
|
|
|
|
public Window.Callback getWrappedWindowCallback() {
|
|
return mWindowCallback;
|
|
}
|
|
|
|
@Override
|
|
public void setCustomView(View view) {
|
|
setCustomView(view, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
|
|
}
|
|
|
|
@Override
|
|
public void setCustomView(View view, LayoutParams layoutParams) {
|
|
view.setLayoutParams(layoutParams);
|
|
mDecorToolbar.setCustomView(view);
|
|
}
|
|
|
|
@Override
|
|
public void setCustomView(int resId) {
|
|
final LayoutInflater inflater = LayoutInflater.from(mDecorToolbar.getContext());
|
|
setCustomView(inflater.inflate(resId, mDecorToolbar.getViewGroup(), false));
|
|
}
|
|
|
|
@Override
|
|
public void setIcon(int resId) {
|
|
mDecorToolbar.setIcon(resId);
|
|
}
|
|
|
|
@Override
|
|
public void setIcon(Drawable icon) {
|
|
mDecorToolbar.setIcon(icon);
|
|
}
|
|
|
|
@Override
|
|
public void setLogo(int resId) {
|
|
mDecorToolbar.setLogo(resId);
|
|
}
|
|
|
|
@Override
|
|
public void setLogo(Drawable logo) {
|
|
mDecorToolbar.setLogo(logo);
|
|
}
|
|
|
|
@Override
|
|
public void setStackedBackgroundDrawable(Drawable d) {
|
|
// This space for rent (do nothing)
|
|
}
|
|
|
|
@Override
|
|
public void setSplitBackgroundDrawable(Drawable d) {
|
|
// This space for rent (do nothing)
|
|
}
|
|
|
|
@Override
|
|
public void setHomeButtonEnabled(boolean enabled) {
|
|
// If the nav button on a Toolbar is present, it's enabled. No-op.
|
|
}
|
|
|
|
@Override
|
|
public void setElevation(float elevation) {
|
|
ViewCompat.setElevation(mDecorToolbar.getViewGroup(), elevation);
|
|
}
|
|
|
|
@Override
|
|
public float getElevation() {
|
|
return ViewCompat.getElevation(mDecorToolbar.getViewGroup());
|
|
}
|
|
|
|
@Override
|
|
public Context getThemedContext() {
|
|
return mDecorToolbar.getContext();
|
|
}
|
|
|
|
@Override
|
|
public boolean isTitleTruncated() {
|
|
return super.isTitleTruncated();
|
|
}
|
|
|
|
@Override
|
|
public void setHomeAsUpIndicator(Drawable indicator) {
|
|
mDecorToolbar.setNavigationIcon(indicator);
|
|
}
|
|
|
|
@Override
|
|
public void setHomeAsUpIndicator(int resId) {
|
|
mDecorToolbar.setNavigationIcon(resId);
|
|
}
|
|
|
|
@Override
|
|
public void setHomeActionContentDescription(CharSequence description) {
|
|
mDecorToolbar.setNavigationContentDescription(description);
|
|
}
|
|
|
|
@Override
|
|
public void setDefaultDisplayHomeAsUpEnabled(boolean enabled) {
|
|
// Do nothing
|
|
}
|
|
|
|
@Override
|
|
public void setHomeActionContentDescription(int resId) {
|
|
mDecorToolbar.setNavigationContentDescription(resId);
|
|
}
|
|
|
|
@Override
|
|
public void setShowHideAnimationEnabled(boolean enabled) {
|
|
// This space for rent; no-op.
|
|
}
|
|
|
|
@Override
|
|
public void onConfigurationChanged(Configuration config) {
|
|
super.onConfigurationChanged(config);
|
|
}
|
|
|
|
@Override
|
|
public void setListNavigationCallbacks(SpinnerAdapter adapter, OnNavigationListener callback) {
|
|
mDecorToolbar.setDropdownParams(adapter, new NavItemSelectedListener(callback));
|
|
}
|
|
|
|
@Override
|
|
public void setSelectedNavigationItem(int position) {
|
|
switch (mDecorToolbar.getNavigationMode()) {
|
|
case NAVIGATION_MODE_LIST:
|
|
mDecorToolbar.setDropdownSelectedPosition(position);
|
|
break;
|
|
default:
|
|
throw new IllegalStateException(
|
|
"setSelectedNavigationIndex not valid for current navigation mode");
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public int getSelectedNavigationIndex() {
|
|
return -1;
|
|
}
|
|
|
|
@Override
|
|
public int getNavigationItemCount() {
|
|
return 0;
|
|
}
|
|
|
|
@Override
|
|
public void setTitle(CharSequence title) {
|
|
mDecorToolbar.setTitle(title);
|
|
}
|
|
|
|
@Override
|
|
public void setTitle(int resId) {
|
|
mDecorToolbar.setTitle(resId != 0 ? mDecorToolbar.getContext().getText(resId) : null);
|
|
}
|
|
|
|
@Override
|
|
public void setWindowTitle(CharSequence title) {
|
|
mDecorToolbar.setWindowTitle(title);
|
|
}
|
|
|
|
@Override
|
|
public void setSubtitle(CharSequence subtitle) {
|
|
mDecorToolbar.setSubtitle(subtitle);
|
|
}
|
|
|
|
@Override
|
|
public void setSubtitle(int resId) {
|
|
mDecorToolbar.setSubtitle(resId != 0 ? mDecorToolbar.getContext().getText(resId) : null);
|
|
}
|
|
|
|
@Override
|
|
public void setDisplayOptions(@DisplayOptions int options) {
|
|
setDisplayOptions(options, 0xffffffff);
|
|
}
|
|
|
|
@Override
|
|
public void setDisplayOptions(@DisplayOptions int options, @DisplayOptions int mask) {
|
|
final int currentOptions = mDecorToolbar.getDisplayOptions();
|
|
mDecorToolbar.setDisplayOptions(options & mask | currentOptions & ~mask);
|
|
}
|
|
|
|
@Override
|
|
public void setDisplayUseLogoEnabled(boolean useLogo) {
|
|
setDisplayOptions(useLogo ? DISPLAY_USE_LOGO : 0, DISPLAY_USE_LOGO);
|
|
}
|
|
|
|
@Override
|
|
public void setDisplayShowHomeEnabled(boolean showHome) {
|
|
setDisplayOptions(showHome ? DISPLAY_SHOW_HOME : 0, DISPLAY_SHOW_HOME);
|
|
}
|
|
|
|
@Override
|
|
public void setDisplayHomeAsUpEnabled(boolean showHomeAsUp) {
|
|
setDisplayOptions(showHomeAsUp ? DISPLAY_HOME_AS_UP : 0, DISPLAY_HOME_AS_UP);
|
|
}
|
|
|
|
@Override
|
|
public void setDisplayShowTitleEnabled(boolean showTitle) {
|
|
setDisplayOptions(showTitle ? DISPLAY_SHOW_TITLE : 0, DISPLAY_SHOW_TITLE);
|
|
}
|
|
|
|
@Override
|
|
public void setDisplayShowCustomEnabled(boolean showCustom) {
|
|
setDisplayOptions(showCustom ? DISPLAY_SHOW_CUSTOM : 0, DISPLAY_SHOW_CUSTOM);
|
|
}
|
|
|
|
@Override
|
|
public void setBackgroundDrawable(@Nullable Drawable d) {
|
|
mDecorToolbar.setBackgroundDrawable(d);
|
|
}
|
|
|
|
@Override
|
|
public View getCustomView() {
|
|
return mDecorToolbar.getCustomView();
|
|
}
|
|
|
|
@Override
|
|
public CharSequence getTitle() {
|
|
return mDecorToolbar.getTitle();
|
|
}
|
|
|
|
@Override
|
|
public CharSequence getSubtitle() {
|
|
return mDecorToolbar.getSubtitle();
|
|
}
|
|
|
|
@Override
|
|
public int getNavigationMode() {
|
|
return NAVIGATION_MODE_STANDARD;
|
|
}
|
|
|
|
@Override
|
|
public void setNavigationMode(@NavigationMode int mode) {
|
|
if (mode == ActionBar.NAVIGATION_MODE_TABS) {
|
|
throw new IllegalArgumentException("Tabs not supported in this configuration");
|
|
}
|
|
mDecorToolbar.setNavigationMode(mode);
|
|
}
|
|
|
|
@Override
|
|
public int getDisplayOptions() {
|
|
return mDecorToolbar.getDisplayOptions();
|
|
}
|
|
|
|
@Override
|
|
public Tab newTab() {
|
|
throw new UnsupportedOperationException(
|
|
"Tabs are not supported in toolbar action bars");
|
|
}
|
|
|
|
@Override
|
|
public void addTab(Tab tab) {
|
|
throw new UnsupportedOperationException(
|
|
"Tabs are not supported in toolbar action bars");
|
|
}
|
|
|
|
@Override
|
|
public void addTab(Tab tab, boolean setSelected) {
|
|
throw new UnsupportedOperationException(
|
|
"Tabs are not supported in toolbar action bars");
|
|
}
|
|
|
|
@Override
|
|
public void addTab(Tab tab, int position) {
|
|
throw new UnsupportedOperationException(
|
|
"Tabs are not supported in toolbar action bars");
|
|
}
|
|
|
|
@Override
|
|
public void addTab(Tab tab, int position, boolean setSelected) {
|
|
throw new UnsupportedOperationException(
|
|
"Tabs are not supported in toolbar action bars");
|
|
}
|
|
|
|
@Override
|
|
public void removeTab(Tab tab) {
|
|
throw new UnsupportedOperationException(
|
|
"Tabs are not supported in toolbar action bars");
|
|
}
|
|
|
|
@Override
|
|
public void removeTabAt(int position) {
|
|
throw new UnsupportedOperationException(
|
|
"Tabs are not supported in toolbar action bars");
|
|
}
|
|
|
|
@Override
|
|
public void removeAllTabs() {
|
|
throw new UnsupportedOperationException(
|
|
"Tabs are not supported in toolbar action bars");
|
|
}
|
|
|
|
@Override
|
|
public void selectTab(Tab tab) {
|
|
throw new UnsupportedOperationException(
|
|
"Tabs are not supported in toolbar action bars");
|
|
}
|
|
|
|
@Override
|
|
public Tab getSelectedTab() {
|
|
throw new UnsupportedOperationException(
|
|
"Tabs are not supported in toolbar action bars");
|
|
}
|
|
|
|
@Override
|
|
public Tab getTabAt(int index) {
|
|
throw new UnsupportedOperationException(
|
|
"Tabs are not supported in toolbar action bars");
|
|
}
|
|
|
|
@Override
|
|
public int getTabCount() {
|
|
return 0;
|
|
}
|
|
|
|
@Override
|
|
public int getHeight() {
|
|
return mDecorToolbar.getHeight();
|
|
}
|
|
|
|
@Override
|
|
public void show() {
|
|
// TODO: Consider a better transition for this.
|
|
// Right now use no automatic transition so that the app can supply one if desired.
|
|
mDecorToolbar.setVisibility(View.VISIBLE);
|
|
}
|
|
|
|
@Override
|
|
public void hide() {
|
|
// TODO: Consider a better transition for this.
|
|
// Right now use no automatic transition so that the app can supply one if desired.
|
|
mDecorToolbar.setVisibility(View.GONE);
|
|
}
|
|
|
|
@Override
|
|
public boolean isShowing() {
|
|
return mDecorToolbar.getVisibility() == View.VISIBLE;
|
|
}
|
|
|
|
@Override
|
|
public boolean openOptionsMenu() {
|
|
return mDecorToolbar.showOverflowMenu();
|
|
}
|
|
|
|
@Override
|
|
public boolean invalidateOptionsMenu() {
|
|
mDecorToolbar.getViewGroup().removeCallbacks(mMenuInvalidator);
|
|
ViewCompat.postOnAnimation(mDecorToolbar.getViewGroup(), mMenuInvalidator);
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean collapseActionView() {
|
|
if (mDecorToolbar.hasExpandedActionView()) {
|
|
mDecorToolbar.collapseActionView();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void populateOptionsMenu() {
|
|
final Menu menu = getMenu();
|
|
final MenuBuilder mb = menu instanceof MenuBuilder ? (MenuBuilder) menu : null;
|
|
if (mb != null) {
|
|
mb.stopDispatchingItemsChanged();
|
|
}
|
|
try {
|
|
menu.clear();
|
|
if (!mWindowCallback.onCreatePanelMenu(Window.FEATURE_OPTIONS_PANEL, menu) ||
|
|
!mWindowCallback.onPreparePanel(Window.FEATURE_OPTIONS_PANEL, null, menu)) {
|
|
menu.clear();
|
|
}
|
|
} finally {
|
|
if (mb != null) {
|
|
mb.startDispatchingItemsChanged();
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean onMenuKeyEvent(KeyEvent event) {
|
|
if (event.getAction() == KeyEvent.ACTION_UP) {
|
|
openOptionsMenu();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean onKeyShortcut(int keyCode, KeyEvent ev) {
|
|
Menu menu = getMenu();
|
|
return menu != null ? menu.performShortcut(keyCode, ev, 0) : false;
|
|
}
|
|
|
|
public void addOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
|
|
mMenuVisibilityListeners.add(listener);
|
|
}
|
|
|
|
public void removeOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
|
|
mMenuVisibilityListeners.remove(listener);
|
|
}
|
|
|
|
public void dispatchMenuVisibilityChanged(boolean isVisible) {
|
|
if (isVisible == mLastMenuVisibility) {
|
|
return;
|
|
}
|
|
mLastMenuVisibility = isVisible;
|
|
|
|
final int count = mMenuVisibilityListeners.size();
|
|
for (int i = 0; i < count; i++) {
|
|
mMenuVisibilityListeners.get(i).onMenuVisibilityChanged(isVisible);
|
|
}
|
|
}
|
|
|
|
private View getListMenuView(Menu menu) {
|
|
ensureListMenuPresenter(menu);
|
|
|
|
if (menu == null || mListMenuPresenter == null) {
|
|
return null;
|
|
}
|
|
|
|
if (mListMenuPresenter.getAdapter().getCount() > 0) {
|
|
return (View) mListMenuPresenter.getMenuView(mDecorToolbar.getViewGroup());
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private void ensureListMenuPresenter(Menu menu) {
|
|
if (mListMenuPresenter == null && (menu instanceof MenuBuilder)) {
|
|
MenuBuilder mb = (MenuBuilder) menu;
|
|
|
|
Context context = mDecorToolbar.getContext();
|
|
final TypedValue outValue = new TypedValue();
|
|
final Resources.Theme widgetTheme = context.getResources().newTheme();
|
|
widgetTheme.setTo(context.getTheme());
|
|
|
|
// Apply the panelMenuListTheme
|
|
widgetTheme.resolveAttribute(R.attr.panelMenuListTheme, outValue, true);
|
|
if (outValue.resourceId != 0) {
|
|
widgetTheme.applyStyle(outValue.resourceId, true);
|
|
} else {
|
|
widgetTheme.applyStyle(R.style.Theme_AppCompat_CompactMenu, true);
|
|
}
|
|
|
|
context = new ContextThemeWrapper(context, 0);
|
|
context.getTheme().setTo(widgetTheme);
|
|
|
|
// Finally create the list menu presenter
|
|
mListMenuPresenter = new ListMenuPresenter(context, R.layout.abc_list_menu_item_layout);
|
|
mListMenuPresenter.setCallback(new PanelMenuPresenterCallback());
|
|
mb.addMenuPresenter(mListMenuPresenter);
|
|
}
|
|
}
|
|
|
|
private class ToolbarCallbackWrapper extends WindowCallbackWrapper {
|
|
public ToolbarCallbackWrapper(Window.Callback wrapped) {
|
|
super(wrapped);
|
|
}
|
|
|
|
@Override
|
|
public boolean onPreparePanel(int featureId, View view, Menu menu) {
|
|
final boolean result = super.onPreparePanel(featureId, view, menu);
|
|
if (result && !mToolbarMenuPrepared) {
|
|
mDecorToolbar.setMenuPrepared();
|
|
mToolbarMenuPrepared = true;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
@Override
|
|
public View onCreatePanelView(int featureId) {
|
|
switch (featureId) {
|
|
case Window.FEATURE_OPTIONS_PANEL:
|
|
final Menu menu = mDecorToolbar.getMenu();
|
|
if (onPreparePanel(featureId, null, menu) && onMenuOpened(featureId, menu)) {
|
|
return getListMenuView(menu);
|
|
}
|
|
break;
|
|
}
|
|
return super.onCreatePanelView(featureId);
|
|
}
|
|
}
|
|
|
|
private Menu getMenu() {
|
|
if (!mMenuCallbackSet) {
|
|
mDecorToolbar.setMenuCallbacks(new ActionMenuPresenterCallback(),
|
|
new MenuBuilderCallback());
|
|
mMenuCallbackSet = true;
|
|
}
|
|
return mDecorToolbar.getMenu();
|
|
}
|
|
|
|
private final class ActionMenuPresenterCallback implements MenuPresenter.Callback {
|
|
private boolean mClosingActionMenu;
|
|
|
|
@Override
|
|
public boolean onOpenSubMenu(MenuBuilder subMenu) {
|
|
if (mWindowCallback != null) {
|
|
mWindowCallback.onMenuOpened(WindowCompat.FEATURE_ACTION_BAR, subMenu);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
|
|
if (mClosingActionMenu) {
|
|
return;
|
|
}
|
|
|
|
mClosingActionMenu = true;
|
|
mDecorToolbar.dismissPopupMenus();
|
|
if (mWindowCallback != null) {
|
|
mWindowCallback.onPanelClosed(WindowCompat.FEATURE_ACTION_BAR, menu);
|
|
}
|
|
mClosingActionMenu = false;
|
|
}
|
|
}
|
|
|
|
private final class PanelMenuPresenterCallback implements MenuPresenter.Callback {
|
|
@Override
|
|
public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
|
|
if (mWindowCallback != null) {
|
|
mWindowCallback.onPanelClosed(Window.FEATURE_OPTIONS_PANEL, menu);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean onOpenSubMenu(MenuBuilder subMenu) {
|
|
if (subMenu == null && mWindowCallback != null) {
|
|
mWindowCallback.onMenuOpened(Window.FEATURE_OPTIONS_PANEL, subMenu);
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
private final class MenuBuilderCallback implements MenuBuilder.Callback {
|
|
|
|
@Override
|
|
public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public void onMenuModeChange(MenuBuilder menu) {
|
|
if (mWindowCallback != null) {
|
|
if (mDecorToolbar.isOverflowMenuShowing()) {
|
|
mWindowCallback.onPanelClosed(WindowCompat.FEATURE_ACTION_BAR, menu);
|
|
} else if (mWindowCallback.onPreparePanel(Window.FEATURE_OPTIONS_PANEL,
|
|
null, menu)) {
|
|
mWindowCallback.onMenuOpened(WindowCompat.FEATURE_ACTION_BAR, menu);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|