| /* |
| * 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 com.android.internal.app; |
| |
| import com.android.internal.view.menu.MenuBuilder; |
| import com.android.internal.view.menu.MenuPresenter; |
| import com.android.internal.widget.DecorToolbar; |
| import com.android.internal.widget.ToolbarWidgetWrapper; |
| |
| import android.annotation.Nullable; |
| import android.app.ActionBar; |
| import android.content.Context; |
| import android.content.res.Configuration; |
| import android.graphics.drawable.Drawable; |
| import android.view.ActionMode; |
| import android.view.KeyCharacterMap; |
| 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.view.WindowCallbackWrapper; |
| import android.widget.SpinnerAdapter; |
| import android.widget.Toolbar; |
| |
| import java.util.ArrayList; |
| |
| 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 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.Callback windowCallback) { |
| mDecorToolbar = new ToolbarWidgetWrapper(toolbar, false); |
| mWindowCallback = new ToolbarCallbackWrapper(windowCallback); |
| mDecorToolbar.setWindowCallback(mWindowCallback); |
| toolbar.setOnMenuItemClickListener(mMenuClicker); |
| mDecorToolbar.setWindowTitle(title); |
| } |
| |
| 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) { |
| if (view != null) { |
| 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) { |
| mDecorToolbar.getViewGroup().setElevation(elevation); |
| } |
| |
| @Override |
| public float getElevation() { |
| return mDecorToolbar.getViewGroup().getElevation(); |
| } |
| |
| @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 ActionMode startActionMode(ActionMode.Callback callback) { |
| return null; |
| } |
| |
| @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 closeOptionsMenu() { |
| return mDecorToolbar.hideOverflowMenu(); |
| } |
| |
| @Override |
| public boolean invalidateOptionsMenu() { |
| mDecorToolbar.getViewGroup().removeCallbacks(mMenuInvalidator); |
| mDecorToolbar.getViewGroup().postOnAnimation(mMenuInvalidator); |
| return true; |
| } |
| |
| @Override |
| public boolean collapseActionView() { |
| if (mDecorToolbar.hasExpandedActionView()) { |
| mDecorToolbar.collapseActionView(); |
| return true; |
| } |
| return false; |
| } |
| |
| void populateOptionsMenu() { |
| if (!mMenuCallbackSet) { |
| mDecorToolbar.setMenuCallbacks(new ActionMenuPresenterCallback(), new MenuBuilderCallback()); |
| mMenuCallbackSet = true; |
| } |
| final Menu menu = mDecorToolbar.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 event) { |
| Menu menu = mDecorToolbar.getMenu(); |
| if (menu != null) { |
| final KeyCharacterMap kmap = KeyCharacterMap.load( |
| event != null ? event.getDeviceId() : KeyCharacterMap.VIRTUAL_KEYBOARD); |
| menu.setQwertyMode(kmap.getKeyboardType() != KeyCharacterMap.NUMERIC); |
| return menu.performShortcut(keyCode, event, 0); |
| } |
| return false; |
| } |
| |
| @Override |
| public void onDestroy() { |
| // Remove any invalidation callbacks |
| mDecorToolbar.getViewGroup().removeCallbacks(mMenuInvalidator); |
| } |
| |
| 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 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) { |
| if (featureId == Window.FEATURE_OPTIONS_PANEL) { |
| // This gets called by PhoneWindow.preparePanel. Since this already manages |
| // its own panel, we return a dummy view here to prevent PhoneWindow from |
| // preparing a default one. |
| return new View(mDecorToolbar.getContext()); |
| } |
| return super.onCreatePanelView(featureId); |
| } |
| } |
| |
| private final class ActionMenuPresenterCallback implements MenuPresenter.Callback { |
| private boolean mClosingActionMenu; |
| |
| @Override |
| public boolean onOpenSubMenu(MenuBuilder subMenu) { |
| if (mWindowCallback != null) { |
| mWindowCallback.onMenuOpened(Window.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(Window.FEATURE_ACTION_BAR, menu); |
| } |
| mClosingActionMenu = false; |
| } |
| } |
| |
| 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(Window.FEATURE_ACTION_BAR, menu); |
| } else if (mWindowCallback.onPreparePanel(Window.FEATURE_OPTIONS_PANEL, |
| null, menu)) { |
| mWindowCallback.onMenuOpened(Window.FEATURE_ACTION_BAR, menu); |
| } |
| } |
| } |
| } |
| } |