Home | History | Annotate | Download | only in app
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 
     18 package com.android.internal.app;
     19 
     20 import android.annotation.Nullable;
     21 import android.app.ActionBar;
     22 import android.content.Context;
     23 import android.content.res.Configuration;
     24 import android.graphics.drawable.Drawable;
     25 import android.view.ActionMode;
     26 import android.view.KeyEvent;
     27 import android.view.LayoutInflater;
     28 import android.view.Menu;
     29 import android.view.MenuItem;
     30 import android.view.View;
     31 import android.view.Window;
     32 import android.view.WindowCallbackWrapper;
     33 import android.widget.SpinnerAdapter;
     34 import android.widget.Toolbar;
     35 import com.android.internal.view.menu.MenuBuilder;
     36 import com.android.internal.view.menu.MenuPresenter;
     37 import com.android.internal.widget.DecorToolbar;
     38 import com.android.internal.widget.ToolbarWidgetWrapper;
     39 
     40 import java.util.ArrayList;
     41 
     42 public class ToolbarActionBar extends ActionBar {
     43     private Toolbar mToolbar;
     44     private DecorToolbar mDecorToolbar;
     45     private boolean mToolbarMenuPrepared;
     46     private Window.Callback mWindowCallback;
     47     private boolean mMenuCallbackSet;
     48 
     49     private boolean mLastMenuVisibility;
     50     private ArrayList<OnMenuVisibilityListener> mMenuVisibilityListeners =
     51             new ArrayList<OnMenuVisibilityListener>();
     52 
     53     private final Runnable mMenuInvalidator = new Runnable() {
     54         @Override
     55         public void run() {
     56             populateOptionsMenu();
     57         }
     58     };
     59 
     60     private final Toolbar.OnMenuItemClickListener mMenuClicker =
     61             new Toolbar.OnMenuItemClickListener() {
     62         @Override
     63         public boolean onMenuItemClick(MenuItem item) {
     64             return mWindowCallback.onMenuItemSelected(Window.FEATURE_OPTIONS_PANEL, item);
     65         }
     66     };
     67 
     68     public ToolbarActionBar(Toolbar toolbar, CharSequence title, Window.Callback windowCallback) {
     69         mToolbar = toolbar;
     70         mDecorToolbar = new ToolbarWidgetWrapper(toolbar, false);
     71         mWindowCallback = new ToolbarCallbackWrapper(windowCallback);
     72         mDecorToolbar.setWindowCallback(mWindowCallback);
     73         toolbar.setOnMenuItemClickListener(mMenuClicker);
     74         mDecorToolbar.setWindowTitle(title);
     75     }
     76 
     77     public Window.Callback getWrappedWindowCallback() {
     78         return mWindowCallback;
     79     }
     80 
     81     @Override
     82     public void setCustomView(View view) {
     83         setCustomView(view, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
     84     }
     85 
     86     @Override
     87     public void setCustomView(View view, LayoutParams layoutParams) {
     88         view.setLayoutParams(layoutParams);
     89         mDecorToolbar.setCustomView(view);
     90     }
     91 
     92     @Override
     93     public void setCustomView(int resId) {
     94         final LayoutInflater inflater = LayoutInflater.from(mToolbar.getContext());
     95         setCustomView(inflater.inflate(resId, mToolbar, false));
     96     }
     97 
     98     @Override
     99     public void setIcon(int resId) {
    100         mDecorToolbar.setIcon(resId);
    101     }
    102 
    103     @Override
    104     public void setIcon(Drawable icon) {
    105         mDecorToolbar.setIcon(icon);
    106     }
    107 
    108     @Override
    109     public void setLogo(int resId) {
    110         mDecorToolbar.setLogo(resId);
    111     }
    112 
    113     @Override
    114     public void setLogo(Drawable logo) {
    115         mDecorToolbar.setLogo(logo);
    116     }
    117 
    118     @Override
    119     public void setStackedBackgroundDrawable(Drawable d) {
    120         // This space for rent (do nothing)
    121     }
    122 
    123     @Override
    124     public void setSplitBackgroundDrawable(Drawable d) {
    125         // This space for rent (do nothing)
    126     }
    127 
    128     @Override
    129     public void setHomeButtonEnabled(boolean enabled) {
    130         // If the nav button on a Toolbar is present, it's enabled. No-op.
    131     }
    132 
    133     @Override
    134     public void setElevation(float elevation) {
    135         mToolbar.setElevation(elevation);
    136     }
    137 
    138     @Override
    139     public float getElevation() {
    140         return mToolbar.getElevation();
    141     }
    142 
    143     @Override
    144     public Context getThemedContext() {
    145         return mToolbar.getContext();
    146     }
    147 
    148     @Override
    149     public boolean isTitleTruncated() {
    150         return super.isTitleTruncated();
    151     }
    152 
    153     @Override
    154     public void setHomeAsUpIndicator(Drawable indicator) {
    155         mToolbar.setNavigationIcon(indicator);
    156     }
    157 
    158     @Override
    159     public void setHomeAsUpIndicator(int resId) {
    160         mToolbar.setNavigationIcon(resId);
    161     }
    162 
    163     @Override
    164     public void setHomeActionContentDescription(CharSequence description) {
    165         mDecorToolbar.setNavigationContentDescription(description);
    166     }
    167 
    168     @Override
    169     public void setDefaultDisplayHomeAsUpEnabled(boolean enabled) {
    170         // Do nothing
    171     }
    172 
    173     @Override
    174     public void setHomeActionContentDescription(int resId) {
    175         mDecorToolbar.setNavigationContentDescription(resId);
    176     }
    177 
    178     @Override
    179     public void setShowHideAnimationEnabled(boolean enabled) {
    180         // This space for rent; no-op.
    181     }
    182 
    183     @Override
    184     public void onConfigurationChanged(Configuration config) {
    185         super.onConfigurationChanged(config);
    186     }
    187 
    188     @Override
    189     public ActionMode startActionMode(ActionMode.Callback callback) {
    190         return null;
    191     }
    192 
    193     @Override
    194     public void setListNavigationCallbacks(SpinnerAdapter adapter, OnNavigationListener callback) {
    195         mDecorToolbar.setDropdownParams(adapter, new NavItemSelectedListener(callback));
    196     }
    197 
    198     @Override
    199     public void setSelectedNavigationItem(int position) {
    200         switch (mDecorToolbar.getNavigationMode()) {
    201             case NAVIGATION_MODE_LIST:
    202                 mDecorToolbar.setDropdownSelectedPosition(position);
    203                 break;
    204             default:
    205                 throw new IllegalStateException(
    206                         "setSelectedNavigationIndex not valid for current navigation mode");
    207         }
    208     }
    209 
    210     @Override
    211     public int getSelectedNavigationIndex() {
    212         return -1;
    213     }
    214 
    215     @Override
    216     public int getNavigationItemCount() {
    217         return 0;
    218     }
    219 
    220     @Override
    221     public void setTitle(CharSequence title) {
    222         mDecorToolbar.setTitle(title);
    223     }
    224 
    225     @Override
    226     public void setTitle(int resId) {
    227         mDecorToolbar.setTitle(resId != 0 ? mDecorToolbar.getContext().getText(resId) : null);
    228     }
    229 
    230     @Override
    231     public void setWindowTitle(CharSequence title) {
    232         mDecorToolbar.setWindowTitle(title);
    233     }
    234 
    235     @Override
    236     public void setSubtitle(CharSequence subtitle) {
    237         mDecorToolbar.setSubtitle(subtitle);
    238     }
    239 
    240     @Override
    241     public void setSubtitle(int resId) {
    242         mDecorToolbar.setSubtitle(resId != 0 ? mDecorToolbar.getContext().getText(resId) : null);
    243     }
    244 
    245     @Override
    246     public void setDisplayOptions(@DisplayOptions int options) {
    247         setDisplayOptions(options, 0xffffffff);
    248     }
    249 
    250     @Override
    251     public void setDisplayOptions(@DisplayOptions int options, @DisplayOptions int mask) {
    252         final int currentOptions = mDecorToolbar.getDisplayOptions();
    253         mDecorToolbar.setDisplayOptions(options & mask | currentOptions & ~mask);
    254     }
    255 
    256     @Override
    257     public void setDisplayUseLogoEnabled(boolean useLogo) {
    258         setDisplayOptions(useLogo ? DISPLAY_USE_LOGO : 0, DISPLAY_USE_LOGO);
    259     }
    260 
    261     @Override
    262     public void setDisplayShowHomeEnabled(boolean showHome) {
    263         setDisplayOptions(showHome ? DISPLAY_SHOW_HOME : 0, DISPLAY_SHOW_HOME);
    264     }
    265 
    266     @Override
    267     public void setDisplayHomeAsUpEnabled(boolean showHomeAsUp) {
    268         setDisplayOptions(showHomeAsUp ? DISPLAY_HOME_AS_UP : 0, DISPLAY_HOME_AS_UP);
    269     }
    270 
    271     @Override
    272     public void setDisplayShowTitleEnabled(boolean showTitle) {
    273         setDisplayOptions(showTitle ? DISPLAY_SHOW_TITLE : 0, DISPLAY_SHOW_TITLE);
    274     }
    275 
    276     @Override
    277     public void setDisplayShowCustomEnabled(boolean showCustom) {
    278         setDisplayOptions(showCustom ? DISPLAY_SHOW_CUSTOM : 0, DISPLAY_SHOW_CUSTOM);
    279     }
    280 
    281     @Override
    282     public void setBackgroundDrawable(@Nullable Drawable d) {
    283         mToolbar.setBackground(d);
    284     }
    285 
    286     @Override
    287     public View getCustomView() {
    288         return mDecorToolbar.getCustomView();
    289     }
    290 
    291     @Override
    292     public CharSequence getTitle() {
    293         return mToolbar.getTitle();
    294     }
    295 
    296     @Override
    297     public CharSequence getSubtitle() {
    298         return mToolbar.getSubtitle();
    299     }
    300 
    301     @Override
    302     public int getNavigationMode() {
    303         return NAVIGATION_MODE_STANDARD;
    304     }
    305 
    306     @Override
    307     public void setNavigationMode(@NavigationMode int mode) {
    308         if (mode == ActionBar.NAVIGATION_MODE_TABS) {
    309             throw new IllegalArgumentException("Tabs not supported in this configuration");
    310         }
    311         mDecorToolbar.setNavigationMode(mode);
    312     }
    313 
    314     @Override
    315     public int getDisplayOptions() {
    316         return mDecorToolbar.getDisplayOptions();
    317     }
    318 
    319     @Override
    320     public Tab newTab() {
    321         throw new UnsupportedOperationException(
    322                 "Tabs are not supported in toolbar action bars");
    323     }
    324 
    325     @Override
    326     public void addTab(Tab tab) {
    327         throw new UnsupportedOperationException(
    328                 "Tabs are not supported in toolbar action bars");
    329     }
    330 
    331     @Override
    332     public void addTab(Tab tab, boolean setSelected) {
    333         throw new UnsupportedOperationException(
    334                 "Tabs are not supported in toolbar action bars");
    335     }
    336 
    337     @Override
    338     public void addTab(Tab tab, int position) {
    339         throw new UnsupportedOperationException(
    340                 "Tabs are not supported in toolbar action bars");
    341     }
    342 
    343     @Override
    344     public void addTab(Tab tab, int position, boolean setSelected) {
    345         throw new UnsupportedOperationException(
    346                 "Tabs are not supported in toolbar action bars");
    347     }
    348 
    349     @Override
    350     public void removeTab(Tab tab) {
    351         throw new UnsupportedOperationException(
    352                 "Tabs are not supported in toolbar action bars");
    353     }
    354 
    355     @Override
    356     public void removeTabAt(int position) {
    357         throw new UnsupportedOperationException(
    358                 "Tabs are not supported in toolbar action bars");
    359     }
    360 
    361     @Override
    362     public void removeAllTabs() {
    363         throw new UnsupportedOperationException(
    364                 "Tabs are not supported in toolbar action bars");
    365     }
    366 
    367     @Override
    368     public void selectTab(Tab tab) {
    369         throw new UnsupportedOperationException(
    370                 "Tabs are not supported in toolbar action bars");
    371     }
    372 
    373     @Override
    374     public Tab getSelectedTab() {
    375         throw new UnsupportedOperationException(
    376                 "Tabs are not supported in toolbar action bars");
    377     }
    378 
    379     @Override
    380     public Tab getTabAt(int index) {
    381         throw new UnsupportedOperationException(
    382                 "Tabs are not supported in toolbar action bars");
    383     }
    384 
    385     @Override
    386     public int getTabCount() {
    387         return 0;
    388     }
    389 
    390     @Override
    391     public int getHeight() {
    392         return mToolbar.getHeight();
    393     }
    394 
    395     @Override
    396     public void show() {
    397         // TODO: Consider a better transition for this.
    398         // Right now use no automatic transition so that the app can supply one if desired.
    399         mToolbar.setVisibility(View.VISIBLE);
    400     }
    401 
    402     @Override
    403     public void hide() {
    404         // TODO: Consider a better transition for this.
    405         // Right now use no automatic transition so that the app can supply one if desired.
    406         mToolbar.setVisibility(View.GONE);
    407     }
    408 
    409     @Override
    410     public boolean isShowing() {
    411         return mToolbar.getVisibility() == View.VISIBLE;
    412     }
    413 
    414     @Override
    415     public boolean openOptionsMenu() {
    416         return mToolbar.showOverflowMenu();
    417     }
    418 
    419     @Override
    420     public boolean invalidateOptionsMenu() {
    421         mToolbar.removeCallbacks(mMenuInvalidator);
    422         mToolbar.postOnAnimation(mMenuInvalidator);
    423         return true;
    424     }
    425 
    426     @Override
    427     public boolean collapseActionView() {
    428         if (mToolbar.hasExpandedActionView()) {
    429             mToolbar.collapseActionView();
    430             return true;
    431         }
    432         return false;
    433     }
    434 
    435     void populateOptionsMenu() {
    436         if (!mMenuCallbackSet) {
    437             mToolbar.setMenuCallbacks(new ActionMenuPresenterCallback(), new MenuBuilderCallback());
    438             mMenuCallbackSet = true;
    439         }
    440         final Menu menu = mToolbar.getMenu();
    441         final MenuBuilder mb = menu instanceof MenuBuilder ? (MenuBuilder) menu : null;
    442         if (mb != null) {
    443             mb.stopDispatchingItemsChanged();
    444         }
    445         try {
    446             menu.clear();
    447             if (!mWindowCallback.onCreatePanelMenu(Window.FEATURE_OPTIONS_PANEL, menu) ||
    448                     !mWindowCallback.onPreparePanel(Window.FEATURE_OPTIONS_PANEL, null, menu)) {
    449                 menu.clear();
    450             }
    451         } finally {
    452             if (mb != null) {
    453                 mb.startDispatchingItemsChanged();
    454             }
    455         }
    456     }
    457 
    458     @Override
    459     public boolean onMenuKeyEvent(KeyEvent event) {
    460         if (event.getAction() == KeyEvent.ACTION_UP) {
    461             openOptionsMenu();
    462         }
    463         return true;
    464     }
    465 
    466     public void addOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
    467         mMenuVisibilityListeners.add(listener);
    468     }
    469 
    470     public void removeOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
    471         mMenuVisibilityListeners.remove(listener);
    472     }
    473 
    474     public void dispatchMenuVisibilityChanged(boolean isVisible) {
    475         if (isVisible == mLastMenuVisibility) {
    476             return;
    477         }
    478         mLastMenuVisibility = isVisible;
    479 
    480         final int count = mMenuVisibilityListeners.size();
    481         for (int i = 0; i < count; i++) {
    482             mMenuVisibilityListeners.get(i).onMenuVisibilityChanged(isVisible);
    483         }
    484     }
    485 
    486     private class ToolbarCallbackWrapper extends WindowCallbackWrapper {
    487         public ToolbarCallbackWrapper(Window.Callback wrapped) {
    488             super(wrapped);
    489         }
    490 
    491         @Override
    492         public boolean onPreparePanel(int featureId, View view, Menu menu) {
    493             final boolean result = super.onPreparePanel(featureId, view, menu);
    494             if (result && !mToolbarMenuPrepared) {
    495                 mDecorToolbar.setMenuPrepared();
    496                 mToolbarMenuPrepared = true;
    497             }
    498             return result;
    499         }
    500     }
    501 
    502     private final class ActionMenuPresenterCallback implements MenuPresenter.Callback {
    503         private boolean mClosingActionMenu;
    504 
    505         @Override
    506         public boolean onOpenSubMenu(MenuBuilder subMenu) {
    507             if (mWindowCallback != null) {
    508                 mWindowCallback.onMenuOpened(Window.FEATURE_ACTION_BAR, subMenu);
    509                 return true;
    510             }
    511             return false;
    512         }
    513 
    514         @Override
    515         public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
    516             if (mClosingActionMenu) {
    517                 return;
    518             }
    519 
    520             mClosingActionMenu = true;
    521             mToolbar.dismissPopupMenus();
    522             if (mWindowCallback != null) {
    523                 mWindowCallback.onPanelClosed(Window.FEATURE_ACTION_BAR, menu);
    524             }
    525             mClosingActionMenu = false;
    526         }
    527     }
    528 
    529     private final class MenuBuilderCallback implements MenuBuilder.Callback {
    530 
    531         @Override
    532         public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
    533             return false;
    534         }
    535 
    536         @Override
    537         public void onMenuModeChange(MenuBuilder menu) {
    538             if (mWindowCallback != null) {
    539                 if (mToolbar.isOverflowMenuShowing()) {
    540                     mWindowCallback.onPanelClosed(Window.FEATURE_ACTION_BAR, menu);
    541                 } else if (mWindowCallback.onPreparePanel(Window.FEATURE_OPTIONS_PANEL,
    542                         null, menu)) {
    543                     mWindowCallback.onMenuOpened(Window.FEATURE_ACTION_BAR, menu);
    544                 }
    545             }
    546         }
    547     }
    548 }
    549