Home | History | Annotate | Download | only in app
      1 /*
      2  * Copyright (C) 2010 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 package com.android.internal.app;
     18 
     19 import com.android.internal.view.ActionBarPolicy;
     20 import com.android.internal.view.menu.MenuBuilder;
     21 import com.android.internal.view.menu.MenuPopupHelper;
     22 import com.android.internal.view.menu.SubMenuBuilder;
     23 import com.android.internal.widget.ActionBarContainer;
     24 import com.android.internal.widget.ActionBarContextView;
     25 import com.android.internal.widget.ActionBarOverlayLayout;
     26 import com.android.internal.widget.ActionBarView;
     27 import com.android.internal.widget.ScrollingTabContainerView;
     28 
     29 import android.animation.Animator;
     30 import android.animation.Animator.AnimatorListener;
     31 import android.animation.AnimatorListenerAdapter;
     32 import android.animation.AnimatorSet;
     33 import android.animation.ObjectAnimator;
     34 import android.app.ActionBar;
     35 import android.app.Activity;
     36 import android.app.Dialog;
     37 import android.app.FragmentTransaction;
     38 import android.content.Context;
     39 import android.content.res.Configuration;
     40 import android.content.res.Resources;
     41 import android.graphics.drawable.Drawable;
     42 import android.os.Handler;
     43 import android.util.Log;
     44 import android.util.TypedValue;
     45 import android.view.ActionMode;
     46 import android.view.ContextThemeWrapper;
     47 import android.view.LayoutInflater;
     48 import android.view.Menu;
     49 import android.view.MenuInflater;
     50 import android.view.MenuItem;
     51 import android.view.View;
     52 import android.view.ViewGroup;
     53 import android.view.Window;
     54 import android.view.accessibility.AccessibilityEvent;
     55 import android.view.animation.AnimationUtils;
     56 import android.widget.SpinnerAdapter;
     57 
     58 import java.lang.ref.WeakReference;
     59 import java.util.ArrayList;
     60 
     61 /**
     62  * ActionBarImpl is the ActionBar implementation used
     63  * by devices of all screen sizes. If it detects a compatible decor,
     64  * it will split contextual modes across both the ActionBarView at
     65  * the top of the screen and a horizontal LinearLayout at the bottom
     66  * which is normally hidden.
     67  */
     68 public class ActionBarImpl extends ActionBar {
     69     private static final String TAG = "ActionBarImpl";
     70 
     71     private Context mContext;
     72     private Context mThemedContext;
     73     private Activity mActivity;
     74     private Dialog mDialog;
     75 
     76     private ActionBarOverlayLayout mOverlayLayout;
     77     private ActionBarContainer mContainerView;
     78     private ViewGroup mTopVisibilityView;
     79     private ActionBarView mActionView;
     80     private ActionBarContextView mContextView;
     81     private ActionBarContainer mSplitView;
     82     private View mContentView;
     83     private ScrollingTabContainerView mTabScrollView;
     84 
     85     private ArrayList<TabImpl> mTabs = new ArrayList<TabImpl>();
     86 
     87     private TabImpl mSelectedTab;
     88     private int mSavedTabPosition = INVALID_POSITION;
     89 
     90     private boolean mDisplayHomeAsUpSet;
     91 
     92     ActionModeImpl mActionMode;
     93     ActionMode mDeferredDestroyActionMode;
     94     ActionMode.Callback mDeferredModeDestroyCallback;
     95 
     96     private boolean mLastMenuVisibility;
     97     private ArrayList<OnMenuVisibilityListener> mMenuVisibilityListeners =
     98             new ArrayList<OnMenuVisibilityListener>();
     99 
    100     private static final int CONTEXT_DISPLAY_NORMAL = 0;
    101     private static final int CONTEXT_DISPLAY_SPLIT = 1;
    102 
    103     private static final int INVALID_POSITION = -1;
    104 
    105     private int mContextDisplayMode;
    106     private boolean mHasEmbeddedTabs;
    107 
    108     final Handler mHandler = new Handler();
    109     Runnable mTabSelector;
    110 
    111     private int mCurWindowVisibility = View.VISIBLE;
    112 
    113     private boolean mHiddenByApp;
    114     private boolean mHiddenBySystem;
    115     private boolean mShowingForMode;
    116 
    117     private boolean mNowShowing = true;
    118 
    119     private Animator mCurrentShowAnim;
    120     private boolean mShowHideAnimationEnabled;
    121 
    122     final AnimatorListener mHideListener = new AnimatorListenerAdapter() {
    123         @Override
    124         public void onAnimationEnd(Animator animation) {
    125             if (mContentView != null) {
    126                 mContentView.setTranslationY(0);
    127                 mTopVisibilityView.setTranslationY(0);
    128             }
    129             if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) {
    130                 mSplitView.setVisibility(View.GONE);
    131             }
    132             mTopVisibilityView.setVisibility(View.GONE);
    133             mContainerView.setTransitioning(false);
    134             mCurrentShowAnim = null;
    135             completeDeferredDestroyActionMode();
    136             if (mOverlayLayout != null) {
    137                 mOverlayLayout.requestFitSystemWindows();
    138             }
    139         }
    140     };
    141 
    142     final AnimatorListener mShowListener = new AnimatorListenerAdapter() {
    143         @Override
    144         public void onAnimationEnd(Animator animation) {
    145             mCurrentShowAnim = null;
    146             mTopVisibilityView.requestLayout();
    147         }
    148     };
    149 
    150     public ActionBarImpl(Activity activity) {
    151         mActivity = activity;
    152         Window window = activity.getWindow();
    153         View decor = window.getDecorView();
    154         init(decor);
    155         if (!mActivity.getWindow().hasFeature(Window.FEATURE_ACTION_BAR_OVERLAY)) {
    156             mContentView = decor.findViewById(android.R.id.content);
    157         }
    158     }
    159 
    160     public ActionBarImpl(Dialog dialog) {
    161         mDialog = dialog;
    162         init(dialog.getWindow().getDecorView());
    163     }
    164 
    165     private void init(View decor) {
    166         mContext = decor.getContext();
    167         mOverlayLayout = (ActionBarOverlayLayout) decor.findViewById(
    168                 com.android.internal.R.id.action_bar_overlay_layout);
    169         if (mOverlayLayout != null) {
    170             mOverlayLayout.setActionBar(this);
    171         }
    172         mActionView = (ActionBarView) decor.findViewById(com.android.internal.R.id.action_bar);
    173         mContextView = (ActionBarContextView) decor.findViewById(
    174                 com.android.internal.R.id.action_context_bar);
    175         mContainerView = (ActionBarContainer) decor.findViewById(
    176                 com.android.internal.R.id.action_bar_container);
    177         mTopVisibilityView = (ViewGroup)decor.findViewById(
    178                 com.android.internal.R.id.top_action_bar);
    179         if (mTopVisibilityView == null) {
    180             mTopVisibilityView = mContainerView;
    181         }
    182         mSplitView = (ActionBarContainer) decor.findViewById(
    183                 com.android.internal.R.id.split_action_bar);
    184 
    185         if (mActionView == null || mContextView == null || mContainerView == null) {
    186             throw new IllegalStateException(getClass().getSimpleName() + " can only be used " +
    187                     "with a compatible window decor layout");
    188         }
    189 
    190         mActionView.setContextView(mContextView);
    191         mContextDisplayMode = mActionView.isSplitActionBar() ?
    192                 CONTEXT_DISPLAY_SPLIT : CONTEXT_DISPLAY_NORMAL;
    193 
    194         // This was initially read from the action bar style
    195         final int current = mActionView.getDisplayOptions();
    196         final boolean homeAsUp = (current & DISPLAY_HOME_AS_UP) != 0;
    197         if (homeAsUp) {
    198             mDisplayHomeAsUpSet = true;
    199         }
    200 
    201         ActionBarPolicy abp = ActionBarPolicy.get(mContext);
    202         setHomeButtonEnabled(abp.enableHomeButtonByDefault() || homeAsUp);
    203         setHasEmbeddedTabs(abp.hasEmbeddedTabs());
    204     }
    205 
    206     public void onConfigurationChanged(Configuration newConfig) {
    207         setHasEmbeddedTabs(ActionBarPolicy.get(mContext).hasEmbeddedTabs());
    208     }
    209 
    210     private void setHasEmbeddedTabs(boolean hasEmbeddedTabs) {
    211         mHasEmbeddedTabs = hasEmbeddedTabs;
    212         // Switch tab layout configuration if needed
    213         if (!mHasEmbeddedTabs) {
    214             mActionView.setEmbeddedTabView(null);
    215             mContainerView.setTabContainer(mTabScrollView);
    216         } else {
    217             mContainerView.setTabContainer(null);
    218             mActionView.setEmbeddedTabView(mTabScrollView);
    219         }
    220         final boolean isInTabMode = getNavigationMode() == NAVIGATION_MODE_TABS;
    221         if (mTabScrollView != null) {
    222             if (isInTabMode) {
    223                 mTabScrollView.setVisibility(View.VISIBLE);
    224                 if (mOverlayLayout != null) {
    225                     mOverlayLayout.requestFitSystemWindows();
    226                 }
    227             } else {
    228                 mTabScrollView.setVisibility(View.GONE);
    229             }
    230         }
    231         mActionView.setCollapsable(!mHasEmbeddedTabs && isInTabMode);
    232     }
    233 
    234     public boolean hasNonEmbeddedTabs() {
    235         return !mHasEmbeddedTabs && getNavigationMode() == NAVIGATION_MODE_TABS;
    236     }
    237 
    238     private void ensureTabsExist() {
    239         if (mTabScrollView != null) {
    240             return;
    241         }
    242 
    243         ScrollingTabContainerView tabScroller = new ScrollingTabContainerView(mContext);
    244 
    245         if (mHasEmbeddedTabs) {
    246             tabScroller.setVisibility(View.VISIBLE);
    247             mActionView.setEmbeddedTabView(tabScroller);
    248         } else {
    249             if (getNavigationMode() == NAVIGATION_MODE_TABS) {
    250                 tabScroller.setVisibility(View.VISIBLE);
    251                 if (mOverlayLayout != null) {
    252                     mOverlayLayout.requestFitSystemWindows();
    253                 }
    254             } else {
    255                 tabScroller.setVisibility(View.GONE);
    256             }
    257             mContainerView.setTabContainer(tabScroller);
    258         }
    259         mTabScrollView = tabScroller;
    260     }
    261 
    262     void completeDeferredDestroyActionMode() {
    263         if (mDeferredModeDestroyCallback != null) {
    264             mDeferredModeDestroyCallback.onDestroyActionMode(mDeferredDestroyActionMode);
    265             mDeferredDestroyActionMode = null;
    266             mDeferredModeDestroyCallback = null;
    267         }
    268     }
    269 
    270     public void setWindowVisibility(int visibility) {
    271         mCurWindowVisibility = visibility;
    272     }
    273 
    274     /**
    275      * Enables or disables animation between show/hide states.
    276      * If animation is disabled using this method, animations in progress
    277      * will be finished.
    278      *
    279      * @param enabled true to animate, false to not animate.
    280      */
    281     public void setShowHideAnimationEnabled(boolean enabled) {
    282         mShowHideAnimationEnabled = enabled;
    283         if (!enabled && mCurrentShowAnim != null) {
    284             mCurrentShowAnim.end();
    285         }
    286     }
    287 
    288     public void addOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
    289         mMenuVisibilityListeners.add(listener);
    290     }
    291 
    292     public void removeOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
    293         mMenuVisibilityListeners.remove(listener);
    294     }
    295 
    296     public void dispatchMenuVisibilityChanged(boolean isVisible) {
    297         if (isVisible == mLastMenuVisibility) {
    298             return;
    299         }
    300         mLastMenuVisibility = isVisible;
    301 
    302         final int count = mMenuVisibilityListeners.size();
    303         for (int i = 0; i < count; i++) {
    304             mMenuVisibilityListeners.get(i).onMenuVisibilityChanged(isVisible);
    305         }
    306     }
    307 
    308     @Override
    309     public void setCustomView(int resId) {
    310         setCustomView(LayoutInflater.from(getThemedContext()).inflate(resId, mActionView, false));
    311     }
    312 
    313     @Override
    314     public void setDisplayUseLogoEnabled(boolean useLogo) {
    315         setDisplayOptions(useLogo ? DISPLAY_USE_LOGO : 0, DISPLAY_USE_LOGO);
    316     }
    317 
    318     @Override
    319     public void setDisplayShowHomeEnabled(boolean showHome) {
    320         setDisplayOptions(showHome ? DISPLAY_SHOW_HOME : 0, DISPLAY_SHOW_HOME);
    321     }
    322 
    323     @Override
    324     public void setDisplayHomeAsUpEnabled(boolean showHomeAsUp) {
    325         setDisplayOptions(showHomeAsUp ? DISPLAY_HOME_AS_UP : 0, DISPLAY_HOME_AS_UP);
    326     }
    327 
    328     @Override
    329     public void setDisplayShowTitleEnabled(boolean showTitle) {
    330         setDisplayOptions(showTitle ? DISPLAY_SHOW_TITLE : 0, DISPLAY_SHOW_TITLE);
    331     }
    332 
    333     @Override
    334     public void setDisplayShowCustomEnabled(boolean showCustom) {
    335         setDisplayOptions(showCustom ? DISPLAY_SHOW_CUSTOM : 0, DISPLAY_SHOW_CUSTOM);
    336     }
    337 
    338     @Override
    339     public void setHomeButtonEnabled(boolean enable) {
    340         mActionView.setHomeButtonEnabled(enable);
    341     }
    342 
    343     @Override
    344     public void setTitle(int resId) {
    345         setTitle(mContext.getString(resId));
    346     }
    347 
    348     @Override
    349     public void setSubtitle(int resId) {
    350         setSubtitle(mContext.getString(resId));
    351     }
    352 
    353     public void setSelectedNavigationItem(int position) {
    354         switch (mActionView.getNavigationMode()) {
    355         case NAVIGATION_MODE_TABS:
    356             selectTab(mTabs.get(position));
    357             break;
    358         case NAVIGATION_MODE_LIST:
    359             mActionView.setDropdownSelectedPosition(position);
    360             break;
    361         default:
    362             throw new IllegalStateException(
    363                     "setSelectedNavigationIndex not valid for current navigation mode");
    364         }
    365     }
    366 
    367     public void removeAllTabs() {
    368         cleanupTabs();
    369     }
    370 
    371     private void cleanupTabs() {
    372         if (mSelectedTab != null) {
    373             selectTab(null);
    374         }
    375         mTabs.clear();
    376         if (mTabScrollView != null) {
    377             mTabScrollView.removeAllTabs();
    378         }
    379         mSavedTabPosition = INVALID_POSITION;
    380     }
    381 
    382     public void setTitle(CharSequence title) {
    383         mActionView.setTitle(title);
    384     }
    385 
    386     public void setSubtitle(CharSequence subtitle) {
    387         mActionView.setSubtitle(subtitle);
    388     }
    389 
    390     public void setDisplayOptions(int options) {
    391         if ((options & DISPLAY_HOME_AS_UP) != 0) {
    392             mDisplayHomeAsUpSet = true;
    393         }
    394         mActionView.setDisplayOptions(options);
    395     }
    396 
    397     public void setDisplayOptions(int options, int mask) {
    398         final int current = mActionView.getDisplayOptions();
    399         if ((mask & DISPLAY_HOME_AS_UP) != 0) {
    400             mDisplayHomeAsUpSet = true;
    401         }
    402         mActionView.setDisplayOptions((options & mask) | (current & ~mask));
    403     }
    404 
    405     public void setBackgroundDrawable(Drawable d) {
    406         mContainerView.setPrimaryBackground(d);
    407     }
    408 
    409     public void setStackedBackgroundDrawable(Drawable d) {
    410         mContainerView.setStackedBackground(d);
    411     }
    412 
    413     public void setSplitBackgroundDrawable(Drawable d) {
    414         if (mSplitView != null) {
    415             mSplitView.setSplitBackground(d);
    416         }
    417     }
    418 
    419     public View getCustomView() {
    420         return mActionView.getCustomNavigationView();
    421     }
    422 
    423     public CharSequence getTitle() {
    424         return mActionView.getTitle();
    425     }
    426 
    427     public CharSequence getSubtitle() {
    428         return mActionView.getSubtitle();
    429     }
    430 
    431     public int getNavigationMode() {
    432         return mActionView.getNavigationMode();
    433     }
    434 
    435     public int getDisplayOptions() {
    436         return mActionView.getDisplayOptions();
    437     }
    438 
    439     public ActionMode startActionMode(ActionMode.Callback callback) {
    440         if (mActionMode != null) {
    441             mActionMode.finish();
    442         }
    443 
    444         mContextView.killMode();
    445         ActionModeImpl mode = new ActionModeImpl(callback);
    446         if (mode.dispatchOnCreate()) {
    447             mode.invalidate();
    448             mContextView.initForMode(mode);
    449             animateToMode(true);
    450             if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) {
    451                 // TODO animate this
    452                 if (mSplitView.getVisibility() != View.VISIBLE) {
    453                     mSplitView.setVisibility(View.VISIBLE);
    454                     if (mOverlayLayout != null) {
    455                         mOverlayLayout.requestFitSystemWindows();
    456                     }
    457                 }
    458             }
    459             mContextView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
    460             mActionMode = mode;
    461             return mode;
    462         }
    463         return null;
    464     }
    465 
    466     private void configureTab(Tab tab, int position) {
    467         final TabImpl tabi = (TabImpl) tab;
    468         final ActionBar.TabListener callback = tabi.getCallback();
    469 
    470         if (callback == null) {
    471             throw new IllegalStateException("Action Bar Tab must have a Callback");
    472         }
    473 
    474         tabi.setPosition(position);
    475         mTabs.add(position, tabi);
    476 
    477         final int count = mTabs.size();
    478         for (int i = position + 1; i < count; i++) {
    479             mTabs.get(i).setPosition(i);
    480         }
    481     }
    482 
    483     @Override
    484     public void addTab(Tab tab) {
    485         addTab(tab, mTabs.isEmpty());
    486     }
    487 
    488     @Override
    489     public void addTab(Tab tab, int position) {
    490         addTab(tab, position, mTabs.isEmpty());
    491     }
    492 
    493     @Override
    494     public void addTab(Tab tab, boolean setSelected) {
    495         ensureTabsExist();
    496         mTabScrollView.addTab(tab, setSelected);
    497         configureTab(tab, mTabs.size());
    498         if (setSelected) {
    499             selectTab(tab);
    500         }
    501     }
    502 
    503     @Override
    504     public void addTab(Tab tab, int position, boolean setSelected) {
    505         ensureTabsExist();
    506         mTabScrollView.addTab(tab, position, setSelected);
    507         configureTab(tab, position);
    508         if (setSelected) {
    509             selectTab(tab);
    510         }
    511     }
    512 
    513     @Override
    514     public Tab newTab() {
    515         return new TabImpl();
    516     }
    517 
    518     @Override
    519     public void removeTab(Tab tab) {
    520         removeTabAt(tab.getPosition());
    521     }
    522 
    523     @Override
    524     public void removeTabAt(int position) {
    525         if (mTabScrollView == null) {
    526             // No tabs around to remove
    527             return;
    528         }
    529 
    530         int selectedTabPosition = mSelectedTab != null
    531                 ? mSelectedTab.getPosition() : mSavedTabPosition;
    532         mTabScrollView.removeTabAt(position);
    533         TabImpl removedTab = mTabs.remove(position);
    534         if (removedTab != null) {
    535             removedTab.setPosition(-1);
    536         }
    537 
    538         final int newTabCount = mTabs.size();
    539         for (int i = position; i < newTabCount; i++) {
    540             mTabs.get(i).setPosition(i);
    541         }
    542 
    543         if (selectedTabPosition == position) {
    544             selectTab(mTabs.isEmpty() ? null : mTabs.get(Math.max(0, position - 1)));
    545         }
    546     }
    547 
    548     @Override
    549     public void selectTab(Tab tab) {
    550         if (getNavigationMode() != NAVIGATION_MODE_TABS) {
    551             mSavedTabPosition = tab != null ? tab.getPosition() : INVALID_POSITION;
    552             return;
    553         }
    554 
    555         final FragmentTransaction trans = mActivity.getFragmentManager().beginTransaction()
    556                 .disallowAddToBackStack();
    557 
    558         if (mSelectedTab == tab) {
    559             if (mSelectedTab != null) {
    560                 mSelectedTab.getCallback().onTabReselected(mSelectedTab, trans);
    561                 mTabScrollView.animateToTab(tab.getPosition());
    562             }
    563         } else {
    564             mTabScrollView.setTabSelected(tab != null ? tab.getPosition() : Tab.INVALID_POSITION);
    565             if (mSelectedTab != null) {
    566                 mSelectedTab.getCallback().onTabUnselected(mSelectedTab, trans);
    567             }
    568             mSelectedTab = (TabImpl) tab;
    569             if (mSelectedTab != null) {
    570                 mSelectedTab.getCallback().onTabSelected(mSelectedTab, trans);
    571             }
    572         }
    573 
    574         if (!trans.isEmpty()) {
    575             trans.commit();
    576         }
    577     }
    578 
    579     @Override
    580     public Tab getSelectedTab() {
    581         return mSelectedTab;
    582     }
    583 
    584     @Override
    585     public int getHeight() {
    586         return mContainerView.getHeight();
    587     }
    588 
    589     @Override
    590     public void show() {
    591         if (mHiddenByApp) {
    592             mHiddenByApp = false;
    593             updateVisibility(false);
    594         }
    595     }
    596 
    597     private void showForActionMode() {
    598         if (!mShowingForMode) {
    599             mShowingForMode = true;
    600             if (mOverlayLayout != null) {
    601                 mOverlayLayout.setShowingForActionMode(true);
    602             }
    603             updateVisibility(false);
    604         }
    605     }
    606 
    607     public void showForSystem() {
    608         if (mHiddenBySystem) {
    609             mHiddenBySystem = false;
    610             updateVisibility(true);
    611         }
    612     }
    613 
    614     @Override
    615     public void hide() {
    616         if (!mHiddenByApp) {
    617             mHiddenByApp = true;
    618             updateVisibility(false);
    619         }
    620     }
    621 
    622     private void hideForActionMode() {
    623         if (mShowingForMode) {
    624             mShowingForMode = false;
    625             if (mOverlayLayout != null) {
    626                 mOverlayLayout.setShowingForActionMode(false);
    627             }
    628             updateVisibility(false);
    629         }
    630     }
    631 
    632     public void hideForSystem() {
    633         if (!mHiddenBySystem) {
    634             mHiddenBySystem = true;
    635             updateVisibility(true);
    636         }
    637     }
    638 
    639     private static boolean checkShowingFlags(boolean hiddenByApp, boolean hiddenBySystem,
    640             boolean showingForMode) {
    641         if (showingForMode) {
    642             return true;
    643         } else if (hiddenByApp || hiddenBySystem) {
    644             return false;
    645         } else {
    646             return true;
    647         }
    648     }
    649 
    650     private void updateVisibility(boolean fromSystem) {
    651         // Based on the current state, should we be hidden or shown?
    652         final boolean shown = checkShowingFlags(mHiddenByApp, mHiddenBySystem,
    653                 mShowingForMode);
    654 
    655         if (shown) {
    656             if (!mNowShowing) {
    657                 mNowShowing = true;
    658                 doShow(fromSystem);
    659             }
    660         } else {
    661             if (mNowShowing) {
    662                 mNowShowing = false;
    663                 doHide(fromSystem);
    664             }
    665         }
    666     }
    667 
    668     public void doShow(boolean fromSystem) {
    669         if (mCurrentShowAnim != null) {
    670             mCurrentShowAnim.end();
    671         }
    672         mTopVisibilityView.setVisibility(View.VISIBLE);
    673 
    674         if (mCurWindowVisibility == View.VISIBLE && (mShowHideAnimationEnabled
    675                 || fromSystem)) {
    676             mTopVisibilityView.setTranslationY(0); // because we're about to ask its window loc
    677             float startingY = -mTopVisibilityView.getHeight();
    678             if (fromSystem) {
    679                 int topLeft[] = {0, 0};
    680                 mTopVisibilityView.getLocationInWindow(topLeft);
    681                 startingY -= topLeft[1];
    682             }
    683             mTopVisibilityView.setTranslationY(startingY);
    684             AnimatorSet anim = new AnimatorSet();
    685             AnimatorSet.Builder b = anim.play(ObjectAnimator.ofFloat(mTopVisibilityView,
    686                     "translationY", 0));
    687             if (mContentView != null) {
    688                 b.with(ObjectAnimator.ofFloat(mContentView, "translationY",
    689                         startingY, 0));
    690             }
    691             if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) {
    692                 mSplitView.setTranslationY(mSplitView.getHeight());
    693                 mSplitView.setVisibility(View.VISIBLE);
    694                 b.with(ObjectAnimator.ofFloat(mSplitView, "translationY", 0));
    695             }
    696             anim.setInterpolator(AnimationUtils.loadInterpolator(mContext,
    697                     com.android.internal.R.interpolator.decelerate_cubic));
    698             anim.setDuration(250);
    699             // If this is being shown from the system, add a small delay.
    700             // This is because we will also be animating in the status bar,
    701             // and these two elements can't be done in lock-step.  So we give
    702             // a little time for the status bar to start its animation before
    703             // the action bar animates.  (This corresponds to the corresponding
    704             // case when hiding, where the status bar has a small delay before
    705             // starting.)
    706             anim.addListener(mShowListener);
    707             mCurrentShowAnim = anim;
    708             anim.start();
    709         } else {
    710             mTopVisibilityView.setAlpha(1);
    711             mTopVisibilityView.setTranslationY(0);
    712             if (mContentView != null) {
    713                 mContentView.setTranslationY(0);
    714             }
    715             if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) {
    716                 mSplitView.setAlpha(1);
    717                 mSplitView.setTranslationY(0);
    718                 mSplitView.setVisibility(View.VISIBLE);
    719             }
    720             mShowListener.onAnimationEnd(null);
    721         }
    722         if (mOverlayLayout != null) {
    723             mOverlayLayout.requestFitSystemWindows();
    724         }
    725     }
    726 
    727     public void doHide(boolean fromSystem) {
    728         if (mCurrentShowAnim != null) {
    729             mCurrentShowAnim.end();
    730         }
    731 
    732         if (mCurWindowVisibility == View.VISIBLE && (mShowHideAnimationEnabled
    733                 || fromSystem)) {
    734             mTopVisibilityView.setAlpha(1);
    735             mContainerView.setTransitioning(true);
    736             AnimatorSet anim = new AnimatorSet();
    737             float endingY = -mTopVisibilityView.getHeight();
    738             if (fromSystem) {
    739                 int topLeft[] = {0, 0};
    740                 mTopVisibilityView.getLocationInWindow(topLeft);
    741                 endingY -= topLeft[1];
    742             }
    743             AnimatorSet.Builder b = anim.play(ObjectAnimator.ofFloat(mTopVisibilityView,
    744                     "translationY", endingY));
    745             if (mContentView != null) {
    746                 b.with(ObjectAnimator.ofFloat(mContentView, "translationY",
    747                         0, endingY));
    748             }
    749             if (mSplitView != null && mSplitView.getVisibility() == View.VISIBLE) {
    750                 mSplitView.setAlpha(1);
    751                 b.with(ObjectAnimator.ofFloat(mSplitView, "translationY",
    752                         mSplitView.getHeight()));
    753             }
    754             anim.setInterpolator(AnimationUtils.loadInterpolator(mContext,
    755                     com.android.internal.R.interpolator.accelerate_cubic));
    756             anim.setDuration(250);
    757             anim.addListener(mHideListener);
    758             mCurrentShowAnim = anim;
    759             anim.start();
    760         } else {
    761             mHideListener.onAnimationEnd(null);
    762         }
    763     }
    764 
    765     public boolean isShowing() {
    766         return mNowShowing;
    767     }
    768 
    769     public boolean isSystemShowing() {
    770         return !mHiddenBySystem;
    771     }
    772 
    773     void animateToMode(boolean toActionMode) {
    774         if (toActionMode) {
    775             showForActionMode();
    776         } else {
    777             hideForActionMode();
    778         }
    779 
    780         mActionView.animateToVisibility(toActionMode ? View.GONE : View.VISIBLE);
    781         mContextView.animateToVisibility(toActionMode ? View.VISIBLE : View.GONE);
    782         if (mTabScrollView != null && !mActionView.hasEmbeddedTabs() && mActionView.isCollapsed()) {
    783             mTabScrollView.animateToVisibility(toActionMode ? View.GONE : View.VISIBLE);
    784         }
    785     }
    786 
    787     public Context getThemedContext() {
    788         if (mThemedContext == null) {
    789             TypedValue outValue = new TypedValue();
    790             Resources.Theme currentTheme = mContext.getTheme();
    791             currentTheme.resolveAttribute(com.android.internal.R.attr.actionBarWidgetTheme,
    792                     outValue, true);
    793             final int targetThemeRes = outValue.resourceId;
    794 
    795             if (targetThemeRes != 0 && mContext.getThemeResId() != targetThemeRes) {
    796                 mThemedContext = new ContextThemeWrapper(mContext, targetThemeRes);
    797             } else {
    798                 mThemedContext = mContext;
    799             }
    800         }
    801         return mThemedContext;
    802     }
    803 
    804     /**
    805      * @hide
    806      */
    807     public class ActionModeImpl extends ActionMode implements MenuBuilder.Callback {
    808         private ActionMode.Callback mCallback;
    809         private MenuBuilder mMenu;
    810         private WeakReference<View> mCustomView;
    811 
    812         public ActionModeImpl(ActionMode.Callback callback) {
    813             mCallback = callback;
    814             mMenu = new MenuBuilder(getThemedContext())
    815                     .setDefaultShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
    816             mMenu.setCallback(this);
    817         }
    818 
    819         @Override
    820         public MenuInflater getMenuInflater() {
    821             return new MenuInflater(getThemedContext());
    822         }
    823 
    824         @Override
    825         public Menu getMenu() {
    826             return mMenu;
    827         }
    828 
    829         @Override
    830         public void finish() {
    831             if (mActionMode != this) {
    832                 // Not the active action mode - no-op
    833                 return;
    834             }
    835 
    836             // If this change in state is going to cause the action bar
    837             // to be hidden, defer the onDestroy callback until the animation
    838             // is finished and associated relayout is about to happen. This lets
    839             // apps better anticipate visibility and layout behavior.
    840             if (!checkShowingFlags(mHiddenByApp, mHiddenBySystem, false)) {
    841                 // With the current state but the action bar hidden, our
    842                 // overall showing state is going to be false.
    843                 mDeferredDestroyActionMode = this;
    844                 mDeferredModeDestroyCallback = mCallback;
    845             } else {
    846                 mCallback.onDestroyActionMode(this);
    847             }
    848             mCallback = null;
    849             animateToMode(false);
    850 
    851             // Clear out the context mode views after the animation finishes
    852             mContextView.closeMode();
    853             mActionView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
    854 
    855             mActionMode = null;
    856         }
    857 
    858         @Override
    859         public void invalidate() {
    860             mMenu.stopDispatchingItemsChanged();
    861             try {
    862                 mCallback.onPrepareActionMode(this, mMenu);
    863             } finally {
    864                 mMenu.startDispatchingItemsChanged();
    865             }
    866         }
    867 
    868         public boolean dispatchOnCreate() {
    869             mMenu.stopDispatchingItemsChanged();
    870             try {
    871                 return mCallback.onCreateActionMode(this, mMenu);
    872             } finally {
    873                 mMenu.startDispatchingItemsChanged();
    874             }
    875         }
    876 
    877         @Override
    878         public void setCustomView(View view) {
    879             mContextView.setCustomView(view);
    880             mCustomView = new WeakReference<View>(view);
    881         }
    882 
    883         @Override
    884         public void setSubtitle(CharSequence subtitle) {
    885             mContextView.setSubtitle(subtitle);
    886         }
    887 
    888         @Override
    889         public void setTitle(CharSequence title) {
    890             mContextView.setTitle(title);
    891         }
    892 
    893         @Override
    894         public void setTitle(int resId) {
    895             setTitle(mContext.getResources().getString(resId));
    896         }
    897 
    898         @Override
    899         public void setSubtitle(int resId) {
    900             setSubtitle(mContext.getResources().getString(resId));
    901         }
    902 
    903         @Override
    904         public CharSequence getTitle() {
    905             return mContextView.getTitle();
    906         }
    907 
    908         @Override
    909         public CharSequence getSubtitle() {
    910             return mContextView.getSubtitle();
    911         }
    912 
    913         @Override
    914         public void setTitleOptionalHint(boolean titleOptional) {
    915             super.setTitleOptionalHint(titleOptional);
    916             mContextView.setTitleOptional(titleOptional);
    917         }
    918 
    919         @Override
    920         public boolean isTitleOptional() {
    921             return mContextView.isTitleOptional();
    922         }
    923 
    924         @Override
    925         public View getCustomView() {
    926             return mCustomView != null ? mCustomView.get() : null;
    927         }
    928 
    929         public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
    930             if (mCallback != null) {
    931                 return mCallback.onActionItemClicked(this, item);
    932             } else {
    933                 return false;
    934             }
    935         }
    936 
    937         public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
    938         }
    939 
    940         public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
    941             if (mCallback == null) {
    942                 return false;
    943             }
    944 
    945             if (!subMenu.hasVisibleItems()) {
    946                 return true;
    947             }
    948 
    949             new MenuPopupHelper(getThemedContext(), subMenu).show();
    950             return true;
    951         }
    952 
    953         public void onCloseSubMenu(SubMenuBuilder menu) {
    954         }
    955 
    956         public void onMenuModeChange(MenuBuilder menu) {
    957             if (mCallback == null) {
    958                 return;
    959             }
    960             invalidate();
    961             mContextView.showOverflowMenu();
    962         }
    963     }
    964 
    965     /**
    966      * @hide
    967      */
    968     public class TabImpl extends ActionBar.Tab {
    969         private ActionBar.TabListener mCallback;
    970         private Object mTag;
    971         private Drawable mIcon;
    972         private CharSequence mText;
    973         private CharSequence mContentDesc;
    974         private int mPosition = -1;
    975         private View mCustomView;
    976 
    977         @Override
    978         public Object getTag() {
    979             return mTag;
    980         }
    981 
    982         @Override
    983         public Tab setTag(Object tag) {
    984             mTag = tag;
    985             return this;
    986         }
    987 
    988         public ActionBar.TabListener getCallback() {
    989             return mCallback;
    990         }
    991 
    992         @Override
    993         public Tab setTabListener(ActionBar.TabListener callback) {
    994             mCallback = callback;
    995             return this;
    996         }
    997 
    998         @Override
    999         public View getCustomView() {
   1000             return mCustomView;
   1001         }
   1002 
   1003         @Override
   1004         public Tab setCustomView(View view) {
   1005             mCustomView = view;
   1006             if (mPosition >= 0) {
   1007                 mTabScrollView.updateTab(mPosition);
   1008             }
   1009             return this;
   1010         }
   1011 
   1012         @Override
   1013         public Tab setCustomView(int layoutResId) {
   1014             return setCustomView(LayoutInflater.from(getThemedContext())
   1015                     .inflate(layoutResId, null));
   1016         }
   1017 
   1018         @Override
   1019         public Drawable getIcon() {
   1020             return mIcon;
   1021         }
   1022 
   1023         @Override
   1024         public int getPosition() {
   1025             return mPosition;
   1026         }
   1027 
   1028         public void setPosition(int position) {
   1029             mPosition = position;
   1030         }
   1031 
   1032         @Override
   1033         public CharSequence getText() {
   1034             return mText;
   1035         }
   1036 
   1037         @Override
   1038         public Tab setIcon(Drawable icon) {
   1039             mIcon = icon;
   1040             if (mPosition >= 0) {
   1041                 mTabScrollView.updateTab(mPosition);
   1042             }
   1043             return this;
   1044         }
   1045 
   1046         @Override
   1047         public Tab setIcon(int resId) {
   1048             return setIcon(mContext.getResources().getDrawable(resId));
   1049         }
   1050 
   1051         @Override
   1052         public Tab setText(CharSequence text) {
   1053             mText = text;
   1054             if (mPosition >= 0) {
   1055                 mTabScrollView.updateTab(mPosition);
   1056             }
   1057             return this;
   1058         }
   1059 
   1060         @Override
   1061         public Tab setText(int resId) {
   1062             return setText(mContext.getResources().getText(resId));
   1063         }
   1064 
   1065         @Override
   1066         public void select() {
   1067             selectTab(this);
   1068         }
   1069 
   1070         @Override
   1071         public Tab setContentDescription(int resId) {
   1072             return setContentDescription(mContext.getResources().getText(resId));
   1073         }
   1074 
   1075         @Override
   1076         public Tab setContentDescription(CharSequence contentDesc) {
   1077             mContentDesc = contentDesc;
   1078             if (mPosition >= 0) {
   1079                 mTabScrollView.updateTab(mPosition);
   1080             }
   1081             return this;
   1082         }
   1083 
   1084         @Override
   1085         public CharSequence getContentDescription() {
   1086             return mContentDesc;
   1087         }
   1088     }
   1089 
   1090     @Override
   1091     public void setCustomView(View view) {
   1092         mActionView.setCustomNavigationView(view);
   1093     }
   1094 
   1095     @Override
   1096     public void setCustomView(View view, LayoutParams layoutParams) {
   1097         view.setLayoutParams(layoutParams);
   1098         mActionView.setCustomNavigationView(view);
   1099     }
   1100 
   1101     @Override
   1102     public void setListNavigationCallbacks(SpinnerAdapter adapter, OnNavigationListener callback) {
   1103         mActionView.setDropdownAdapter(adapter);
   1104         mActionView.setCallback(callback);
   1105     }
   1106 
   1107     @Override
   1108     public int getSelectedNavigationIndex() {
   1109         switch (mActionView.getNavigationMode()) {
   1110             case NAVIGATION_MODE_TABS:
   1111                 return mSelectedTab != null ? mSelectedTab.getPosition() : -1;
   1112             case NAVIGATION_MODE_LIST:
   1113                 return mActionView.getDropdownSelectedPosition();
   1114             default:
   1115                 return -1;
   1116         }
   1117     }
   1118 
   1119     @Override
   1120     public int getNavigationItemCount() {
   1121         switch (mActionView.getNavigationMode()) {
   1122             case NAVIGATION_MODE_TABS:
   1123                 return mTabs.size();
   1124             case NAVIGATION_MODE_LIST:
   1125                 SpinnerAdapter adapter = mActionView.getDropdownAdapter();
   1126                 return adapter != null ? adapter.getCount() : 0;
   1127             default:
   1128                 return 0;
   1129         }
   1130     }
   1131 
   1132     @Override
   1133     public int getTabCount() {
   1134         return mTabs.size();
   1135     }
   1136 
   1137     @Override
   1138     public void setNavigationMode(int mode) {
   1139         final int oldMode = mActionView.getNavigationMode();
   1140         switch (oldMode) {
   1141             case NAVIGATION_MODE_TABS:
   1142                 mSavedTabPosition = getSelectedNavigationIndex();
   1143                 selectTab(null);
   1144                 mTabScrollView.setVisibility(View.GONE);
   1145                 break;
   1146         }
   1147         if (oldMode != mode && !mHasEmbeddedTabs) {
   1148             if (mOverlayLayout != null) {
   1149                 mOverlayLayout.requestFitSystemWindows();
   1150             }
   1151         }
   1152         mActionView.setNavigationMode(mode);
   1153         switch (mode) {
   1154             case NAVIGATION_MODE_TABS:
   1155                 ensureTabsExist();
   1156                 mTabScrollView.setVisibility(View.VISIBLE);
   1157                 if (mSavedTabPosition != INVALID_POSITION) {
   1158                     setSelectedNavigationItem(mSavedTabPosition);
   1159                     mSavedTabPosition = INVALID_POSITION;
   1160                 }
   1161                 break;
   1162         }
   1163         mActionView.setCollapsable(mode == NAVIGATION_MODE_TABS && !mHasEmbeddedTabs);
   1164     }
   1165 
   1166     @Override
   1167     public Tab getTabAt(int index) {
   1168         return mTabs.get(index);
   1169     }
   1170 
   1171 
   1172     @Override
   1173     public void setIcon(int resId) {
   1174         mActionView.setIcon(resId);
   1175     }
   1176 
   1177     @Override
   1178     public void setIcon(Drawable icon) {
   1179         mActionView.setIcon(icon);
   1180     }
   1181 
   1182     @Override
   1183     public void setLogo(int resId) {
   1184         mActionView.setLogo(resId);
   1185     }
   1186 
   1187     @Override
   1188     public void setLogo(Drawable logo) {
   1189         mActionView.setLogo(logo);
   1190     }
   1191 
   1192     public void setDefaultDisplayHomeAsUpEnabled(boolean enable) {
   1193         if (!mDisplayHomeAsUpSet) {
   1194             setDisplayHomeAsUpEnabled(enable);
   1195         }
   1196     }
   1197 }
   1198