content: /*
   * Copyright (C) 2010 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.R;
  import com.android.internal.view.ActionBarPolicy;
  import com.android.internal.view.menu.MenuBuilder;
  import com.android.internal.view.menu.MenuPopupHelper;
  import com.android.internal.view.menu.SubMenuBuilder;
  import com.android.internal.widget.ActionBarContainer;
  import com.android.internal.widget.ActionBarContextView;
  import com.android.internal.widget.ActionBarOverlayLayout;
  import com.android.internal.widget.DecorToolbar;
  import com.android.internal.widget.ScrollingTabContainerView;
  
  import android.animation.Animator;
  import android.animation.Animator.AnimatorListener;
  import android.animation.AnimatorListenerAdapter;
  import android.animation.AnimatorSet;
  import android.animation.ObjectAnimator;
  import android.animation.ValueAnimator;
  import android.annotation.UnsupportedAppUsage;
  import android.app.ActionBar;
  import android.app.Activity;
  import android.app.Dialog;
  import android.app.FragmentTransaction;
  import android.content.Context;
  import android.content.res.Configuration;
  import android.content.res.Resources;
  import android.content.res.TypedArray;
  import android.graphics.drawable.Drawable;
  import android.util.TypedValue;
  import android.view.ActionMode;
  import android.view.ContextThemeWrapper;
  import android.view.LayoutInflater;
  import android.view.Menu;
  import android.view.MenuInflater;
  import android.view.MenuItem;
  import android.view.View;
  import android.view.ViewParent;
  import android.view.Window;
  import android.view.accessibility.AccessibilityEvent;
  import android.view.animation.AnimationUtils;
  import android.widget.SpinnerAdapter;
  import android.widget.Toolbar;
  
  import java.lang.ref.WeakReference;
  import java.util.ArrayList;
  
  /**
   * WindowDecorActionBar is the ActionBar implementation used
   * by devices of all screen sizes as part of the window decor layout.
   * If it detects a compatible decor, it will split contextual modes
   * across both the ActionBarView at the top of the screen and
   * a horizontal LinearLayout at the bottom which is normally hidden.
   */
  public class WindowDecorActionBar extends ActionBar implements
          ActionBarOverlayLayout.ActionBarVisibilityCallback {
      private static final String TAG = "WindowDecorActionBar";
  
      private Context mContext;
      private Context mThemedContext;
      private Activity mActivity;
      private Dialog mDialog;
  
      private ActionBarOverlayLayout mOverlayLayout;
      private ActionBarContainer mContainerView;
      private DecorToolbar mDecorToolbar;
      @UnsupportedAppUsage
      private ActionBarContextView mContextView;
      private ActionBarContainer mSplitView;
      private View mContentView;
      @UnsupportedAppUsage
      private ScrollingTabContainerView mTabScrollView;
  
      private ArrayList<TabImpl> mTabs = new ArrayList<TabImpl>();
  
      private TabImpl mSelectedTab;
      private int mSavedTabPosition = INVALID_POSITION;
  
      private boolean mDisplayHomeAsUpSet;
  
      ActionMode mActionMode;
      ActionMode mDeferredDestroyActionMode;
      ActionMode.Callback mDeferredModeDestroyCallback;
  
      private boolean mLastMenuVisibility;
      private ArrayList<OnMenuVisibilityListener> mMenuVisibilityListeners =
              new ArrayList<OnMenuVisibilityListener>();
  
      private static final int CONTEXT_DISPLAY_NORMAL = 0;
      private static final int CONTEXT_DISPLAY_SPLIT = 1;
  
      private static final int INVALID_POSITION = -1;
  
      // The fade duration for toolbar and action bar when entering/exiting action mode.
      private static final long FADE_OUT_DURATION_MS = 100;
      private static final long FADE_IN_DURATION_MS = 200;
  
      private int mContextDisplayMode;
      private boolean mHasEmbeddedTabs;
  
      private int mCurWindowVisibility = View.VISIBLE;
  
      private boolean mContentAnimations = true;
      private boolean mHiddenByApp;
      private boolean mHiddenBySystem;
      private boolean mShowingForMode;
  
      private boolean mNowShowing = true;
  
      private Animator mCurrentShowAnim;
      private boolean mShowHideAnimationEnabled;
      boolean mHideOnContentScroll;
  
      final AnimatorListener mHideListener = new AnimatorListenerAdapter() {
          @Override
          public void onAnimationEnd(Animator animation) {
              if (mContentAnimations && mContentView != null) {
                  mContentView.setTranslationY(0);
                  mContainerView.setTranslationY(0);
              }
              if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) {
                  mSplitView.setVisibility(View.GONE);
              }
              mContainerView.setVisibility(View.GONE);
              mContainerView.setTransitioning(false);
              mCurrentShowAnim = null;
              completeDeferredDestroyActionMode();
              if (mOverlayLayout != null) {
                  mOverlayLayout.requestApplyInsets();
              }
          }
      };
  
      final AnimatorListener mShowListener = new AnimatorListenerAdapter() {
          @Override
          public void onAnimationEnd(Animator animation) {
              mCurrentShowAnim = null;
              mContainerView.requestLayout();
          }
      };
  
      final ValueAnimator.AnimatorUpdateListener mUpdateListener =
              new ValueAnimator.AnimatorUpdateListener() {
          @Override
          public void onAnimationUpdate(ValueAnimator animation) {
              final ViewParent parent = mContainerView.getParent();
              ((View) parent).invalidate();
          }
      };
  
      public WindowDecorActionBar(Activity activity) {
          mActivity = activity;
          Window window = activity.getWindow();
          View decor = window.getDecorView();
          boolean overlayMode = mActivity.getWindow().hasFeature(Window.FEATURE_ACTION_BAR_OVERLAY);
          init(decor);
          if (!overlayMode) {
              mContentView = decor.findViewById(android.R.id.content);
          }
      }
  
      public WindowDecorActionBar(Dialog dialog) {
          mDialog = dialog;
          init(dialog.getWindow().getDecorView());
      }
  
      /**
       * Only for edit mode.
       * @hide
       */
      public WindowDecorActionBar(View layout) {
          assert layout.isInEditMode();
          init(layout);
      }
  
      private void init(View decor) {
          mOverlayLayout = (ActionBarOverlayLayout) decor.findViewById(
                  com.android.internal.R.id.decor_content_parent);
          if (mOverlayLayout != null) {
              mOverlayLayout.setActionBarVisibilityCallback(this);
          }
          mDecorToolbar = getDecorToolbar(decor.findViewById(com.android.internal.R.id.action_bar));
          mContextView = (ActionBarContextView) decor.findViewById(
                  com.android.internal.R.id.action_context_bar);
          mContainerView = (ActionBarContainer) decor.findViewById(
                  com.android.internal.R.id.action_bar_container);
          mSplitView = (ActionBarContainer) decor.findViewById(
                  com.android.internal.R.id.split_action_bar);
  
          if (mDecorToolbar == null || mContextView == null || mContainerView == null) {
              throw new IllegalStateException(getClass().getSimpleName() + " can only be used " +
                      "with a compatible window decor layout");
          }
  
          mContext = mDecorToolbar.getContext();
          mContextDisplayMode = mDecorToolbar.isSplit() ?
                  CONTEXT_DISPLAY_SPLIT : CONTEXT_DISPLAY_NORMAL;
  
          // This was initially read from the action bar style
          final int current = mDecorToolbar.getDisplayOptions();
          final boolean homeAsUp = (current & DISPLAY_HOME_AS_UP) != 0;
          if (homeAsUp) {
              mDisplayHomeAsUpSet = true;
          }
  
          ActionBarPolicy abp = ActionBarPolicy.get(mContext);
          setHomeButtonEnabled(abp.enableHomeButtonByDefault() || homeAsUp);
          setHasEmbeddedTabs(abp.hasEmbeddedTabs());
  
          final TypedArray a = mContext.obtainStyledAttributes(null,
                  com.android.internal.R.styleable.ActionBar,
                  com.android.internal.R.attr.actionBarStyle, 0);
          if (a.getBoolean(R.styleable.ActionBar_hideOnContentScroll, false)) {
              setHideOnContentScrollEnabled(true);
          }
          final int elevation = a.getDimensionPixelSize(R.styleable.ActionBar_elevation, 0);
          if (elevation != 0) {
              setElevation(elevation);
          }
          a.recycle();
      }
  
      private DecorToolbar getDecorToolbar(View view) {
          if (view instanceof DecorToolbar) {
              return (DecorToolbar) view;
          } else if (view instanceof Toolbar) {
              return ((Toolbar) view).getWrapper();
          } else {
              throw new IllegalStateException("Can't make a decor toolbar out of " +
                      view.getClass().getSimpleName());
          }
      }
  
      @Override
      public void setElevation(float elevation) {
          mContainerView.setElevation(elevation);
          if (mSplitView != null) {
              mSplitView.setElevation(elevation);
          }
      }
  
      @Override
      public float getElevation() {
          return mContainerView.getElevation();
      }
  
      public void onConfigurationChanged(Configuration newConfig) {
          setHasEmbeddedTabs(ActionBarPolicy.get(mContext).hasEmbeddedTabs());
      }
  
      private void setHasEmbeddedTabs(boolean hasEmbeddedTabs) {
          mHasEmbeddedTabs = hasEmbeddedTabs;
          // Switch tab layout configuration if needed
          if (!mHasEmbeddedTabs) {
              mDecorToolbar.setEmbeddedTabView(null);
              mContainerView.setTabContainer(mTabScrollView);
          } else {
              mContainerView.setTabContainer(null);
              mDecorToolbar.setEmbeddedTabView(mTabScrollView);
          }
          final boolean isInTabMode = getNavigationMode() == NAVIGATION_MODE_TABS;
          if (mTabScrollView != null) {
              if (isInTabMode) {
                  mTabScrollView.setVisibility(View.VISIBLE);
                  if (mOverlayLayout != null) {
                      mOverlayLayout.requestApplyInsets();
                  }
              } else {
                  mTabScrollView.setVisibility(View.GONE);
              }
          }
          mDecorToolbar.setCollapsible(!mHasEmbeddedTabs && isInTabMode);
          mOverlayLayout.setHasNonEmbeddedTabs(!mHasEmbeddedTabs && isInTabMode);
      }
  
      private void ensureTabsExist() {
          if (mTabScrollView != null) {
              return;
          }
  
          ScrollingTabContainerView tabScroller = new ScrollingTabContainerView(mContext);
  
          if (mHasEmbeddedTabs) {
              tabScroller.setVisibility(View.VISIBLE);
              mDecorToolbar.setEmbeddedTabView(tabScroller);
          } else {
              if (getNavigationMode() == NAVIGATION_MODE_TABS) {
                  tabScroller.setVisibility(View.VISIBLE);
                  if (mOverlayLayout != null) {
                      mOverlayLayout.requestApplyInsets();
                  }
              } else {
                  tabScroller.setVisibility(View.GONE);
              }
              mContainerView.setTabContainer(tabScroller);
          }
          mTabScrollView = tabScroller;
      }
  
      void completeDeferredDestroyActionMode() {
          if (mDeferredModeDestroyCallback != null) {
              mDeferredModeDestroyCallback.onDestroyActionMode(mDeferredDestroyActionMode);
              mDeferredDestroyActionMode = null;
              mDeferredModeDestroyCallback = null;
          }
      }
  
      public void onWindowVisibilityChanged(int visibility) {
          mCurWindowVisibility = visibility;
      }
  
      /**
       * Enables or disables animation between show/hide states.
       * If animation is disabled using this method, animations in progress
       * will be finished.
       *
       * @param enabled true to animate, false to not animate.
       */
      @UnsupportedAppUsage
      public void setShowHideAnimationEnabled(boolean enabled) {
          mShowHideAnimationEnabled = enabled;
          if (!enabled && mCurrentShowAnim != null) {
              mCurrentShowAnim.end();
          }
      }
  
      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);
          }
      }
  
      @Override
      public void setCustomView(int resId) {
          setCustomView(LayoutInflater.from(getThemedContext()).inflate(resId,
                  mDecorToolbar.getViewGroup(), false));
      }
  
      @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 setHomeButtonEnabled(boolean enable) {
          mDecorToolbar.setHomeButtonEnabled(enable);
      }
  
      @Override
      public void setTitle(int resId) {
          setTitle(mContext.getString(resId));
      }
  
      @Override
      public void setSubtitle(int resId) {
          setSubtitle(mContext.getString(resId));
      }
  
      public void setSelectedNavigationItem(int position) {
          switch (mDecorToolbar.getNavigationMode()) {
          case NAVIGATION_MODE_TABS:
              selectTab(mTabs.get(position));
              break;
          case NAVIGATION_MODE_LIST:
              mDecorToolbar.setDropdownSelectedPosition(position);
              break;
          default:
              throw new IllegalStateException(
                      "setSelectedNavigationIndex not valid for current navigation mode");
          }
      }
  
      public void removeAllTabs() {
          cleanupTabs();
      }
  
      private void cleanupTabs() {
          if (mSelectedTab != null) {
              selectTab(null);
          }
          mTabs.clear();
          if (mTabScrollView != null) {
              mTabScrollView.removeAllTabs();
          }
          mSavedTabPosition = INVALID_POSITION;
      }
  
      public void setTitle(CharSequence title) {
          mDecorToolbar.setTitle(title);
      }
  
      @Override
      public void setWindowTitle(CharSequence title) {
          mDecorToolbar.setWindowTitle(title);
      }
  
      public void setSubtitle(CharSequence subtitle) {
          mDecorToolbar.setSubtitle(subtitle);
      }
  
      public void setDisplayOptions(int options) {
          if ((options & DISPLAY_HOME_AS_UP) != 0) {
              mDisplayHomeAsUpSet = true;
          }
          mDecorToolbar.setDisplayOptions(options);
      }
  
      public void setDisplayOptions(int options, int mask) {
          final int current = mDecorToolbar.getDisplayOptions();
          if ((mask & DISPLAY_HOME_AS_UP) != 0) {
              mDisplayHomeAsUpSet = true;
          }
          mDecorToolbar.setDisplayOptions((options & mask) | (current & ~mask));
      }
  
      public void setBackgroundDrawable(Drawable d) {
          mContainerView.setPrimaryBackground(d);
      }
  
      public void setStackedBackgroundDrawable(Drawable d) {
          mContainerView.setStackedBackground(d);
      }
  
      public void setSplitBackgroundDrawable(Drawable d) {
          if (mSplitView != null) {
              mSplitView.setSplitBackground(d);
          }
      }
  
      public View getCustomView() {
          return mDecorToolbar.getCustomView();
      }
  
      public CharSequence getTitle() {
          return mDecorToolbar.getTitle();
      }
  
      public CharSequence getSubtitle() {
          return mDecorToolbar.getSubtitle();
      }
  
      public int getNavigationMode() {
          return mDecorToolbar.getNavigationMode();
      }
  
      public int getDisplayOptions() {
          return mDecorToolbar.getDisplayOptions();
      }
  
      public ActionMode startActionMode(ActionMode.Callback callback) {
          if (mActionMode != null) {
              mActionMode.finish();
          }
  
          mOverlayLayout.setHideOnContentScrollEnabled(false);
          mContextView.killMode();
          ActionModeImpl mode = new ActionModeImpl(mContextView.getContext(), callback);
          if (mode.dispatchOnCreate()) {
              // This needs to be set before invalidate() so that it calls
              // onPrepareActionMode()
              mActionMode = mode;
              mode.invalidate();
              mContextView.initForMode(mode);
              animateToMode(true);
              if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) {
                  // TODO animate this
                  if (mSplitView.getVisibility() != View.VISIBLE) {
                      mSplitView.setVisibility(View.VISIBLE);
                      if (mOverlayLayout != null) {
                          mOverlayLayout.requestApplyInsets();
                      }
                  }
              }
              mContextView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
              return mode;
          }
          return null;
      }
  
      private void configureTab(Tab tab, int position) {
          final TabImpl tabi = (TabImpl) tab;
          final ActionBar.TabListener callback = tabi.getCallback();
  
          if (callback == null) {
              throw new IllegalStateException("Action Bar Tab must have a Callback");
          }
  
          tabi.setPosition(position);
          mTabs.add(position, tabi);
  
          final int count = mTabs.size();
          for (int i = position + 1; i < count; i++) {
              mTabs.get(i).setPosition(i);
          }
      }
  
      @Override
      public void addTab(Tab tab) {
          addTab(tab, mTabs.isEmpty());
      }
  
      @Override
      public void addTab(Tab tab, int position) {
          addTab(tab, position, mTabs.isEmpty());
      }
  
      @Override
      public void addTab(Tab tab, boolean setSelected) {
          ensureTabsExist();
          mTabScrollView.addTab(tab, setSelected);
          configureTab(tab, mTabs.size());
          if (setSelected) {
              selectTab(tab);
          }
      }
  
      @Override
      public void addTab(Tab tab, int position, boolean setSelected) {
          ensureTabsExist();
          mTabScrollView.addTab(tab, position, setSelected);
          configureTab(tab, position);
          if (setSelected) {
              selectTab(tab);
          }
      }
  
      @Override
      public Tab newTab() {
          return new TabImpl();
      }
  
      @Override
      public void removeTab(Tab tab) {
          removeTabAt(tab.getPosition());
      }
  
      @Override
      public void removeTabAt(int position) {
          if (mTabScrollView == null) {
              // No tabs around to remove
              return;
          }
  
          int selectedTabPosition = mSelectedTab != null
                  ? mSelectedTab.getPosition() : mSavedTabPosition;
          mTabScrollView.removeTabAt(position);
          TabImpl removedTab = mTabs.remove(position);
          if (removedTab != null) {
              removedTab.setPosition(-1);
          }
  
          final int newTabCount = mTabs.size();
          for (int i = position; i < newTabCount; i++) {
              mTabs.get(i).setPosition(i);
          }
  
          if (selectedTabPosition == position) {
              selectTab(mTabs.isEmpty() ? null : mTabs.get(Math.max(0, position - 1)));
          }
      }
  
      @Override
      public void selectTab(Tab tab) {
          if (getNavigationMode() != NAVIGATION_MODE_TABS) {
              mSavedTabPosition = tab != null ? tab.getPosition() : INVALID_POSITION;
              return;
          }
  
          final FragmentTransaction trans = mDecorToolbar.getViewGroup().isInEditMode() ? null :
                  mActivity.getFragmentManager().beginTransaction().disallowAddToBackStack();
  
          if (mSelectedTab == tab) {
              if (mSelectedTab != null) {
                  mSelectedTab.getCallback().onTabReselected(mSelectedTab, trans);
                  mTabScrollView.animateToTab(tab.getPosition());
              }
          } else {
              mTabScrollView.setTabSelected(tab != null ? tab.getPosition() : Tab.INVALID_POSITION);
              if (mSelectedTab != null) {
                  mSelectedTab.getCallback().onTabUnselected(mSelectedTab, trans);
              }
              mSelectedTab = (TabImpl) tab;
              if (mSelectedTab != null) {
                  mSelectedTab.getCallback().onTabSelected(mSelectedTab, trans);
              }
          }
  
          if (trans != null && !trans.isEmpty()) {
              trans.commit();
          }
      }
  
      @Override
      public Tab getSelectedTab() {
          return mSelectedTab;
      }
  
      @Override
      public int getHeight() {
          return mContainerView.getHeight();
      }
  
      public void enableContentAnimations(boolean enabled) {
          mContentAnimations = enabled;
      }
  
      @Override
      public void show() {
          if (mHiddenByApp) {
              mHiddenByApp = false;
              updateVisibility(false);
          }
      }
  
      private void showForActionMode() {
          if (!mShowingForMode) {
              mShowingForMode = true;
              if (mOverlayLayout != null) {
                  mOverlayLayout.setShowingForActionMode(true);
              }
              updateVisibility(false);
          }
      }
  
      public void showForSystem() {
          if (mHiddenBySystem) {
              mHiddenBySystem = false;
              updateVisibility(true);
          }
      }
  
      @Override
      public void hide() {
          if (!mHiddenByApp) {
              mHiddenByApp = true;
              updateVisibility(false);
          }
      }
  
      private void hideForActionMode() {
          if (mShowingForMode) {
              mShowingForMode = false;
              if (mOverlayLayout != null) {
                  mOverlayLayout.setShowingForActionMode(false);
              }
              updateVisibility(false);
          }
      }
  
      public void hideForSystem() {
          if (!mHiddenBySystem) {
              mHiddenBySystem = true;
              updateVisibility(true);
          }
      }
  
      @Override
      public void setHideOnContentScrollEnabled(boolean hideOnContentScroll) {
          if (hideOnContentScroll && !mOverlayLayout.isInOverlayMode()) {
              throw new IllegalStateException("Action bar must be in overlay mode " +
                      "(Window.FEATURE_OVERLAY_ACTION_BAR) to enable hide on content scroll");
          }
          mHideOnContentScroll = hideOnContentScroll;
          mOverlayLayout.setHideOnContentScrollEnabled(hideOnContentScroll);
      }
  
      @Override
      public boolean isHideOnContentScrollEnabled() {
          return mOverlayLayout.isHideOnContentScrollEnabled();
      }
  
      @Override
      public int getHideOffset() {
          return mOverlayLayout.getActionBarHideOffset();
      }
  
      @Override
      public void setHideOffset(int offset) {
          if (offset != 0 && !mOverlayLayout.isInOverlayMode()) {
              throw new IllegalStateException("Action bar must be in overlay mode " +
                      "(Window.FEATURE_OVERLAY_ACTION_BAR) to set a non-zero hide offset");
          }
          mOverlayLayout.setActionBarHideOffset(offset);
      }
  
      private static boolean checkShowingFlags(boolean hiddenByApp, boolean hiddenBySystem,
              boolean showingForMode) {
          if (showingForMode) {
              return true;
          } else if (hiddenByApp || hiddenBySystem) {
              return false;
          } else {
              return true;
          }
      }
  
      private void updateVisibility(boolean fromSystem) {
          // Based on the current state, should we be hidden or shown?
          final boolean shown = checkShowingFlags(mHiddenByApp, mHiddenBySystem,
                  mShowingForMode);
  
          if (shown) {
              if (!mNowShowing) {
                  mNowShowing = true;
                  doShow(fromSystem);
              }
          } else {
              if (mNowShowing) {
                  mNowShowing = false;
                  doHide(fromSystem);
              }
          }
      }
  
      public void doShow(boolean fromSystem) {
          if (mCurrentShowAnim != null) {
              mCurrentShowAnim.end();
          }
          mContainerView.setVisibility(View.VISIBLE);
  
          if (mCurWindowVisibility == View.VISIBLE && (mShowHideAnimationEnabled
                  || fromSystem)) {
              mContainerView.setTranslationY(0); // because we're about to ask its window loc
              float startingY = -mContainerView.getHeight();
              if (fromSystem) {
                  int topLeft[] = {0, 0};
                  mContainerView.getLocationInWindow(topLeft);
                  startingY -= topLeft[1];
              }
              mContainerView.setTranslationY(startingY);
              AnimatorSet anim = new AnimatorSet();
              ObjectAnimator a = ObjectAnimator.ofFloat(mContainerView, View.TRANSLATION_Y, 0);
              a.addUpdateListener(mUpdateListener);
              AnimatorSet.Builder b = anim.play(a);
              if (mContentAnimations && mContentView != null) {
                  b.with(ObjectAnimator.ofFloat(mContentView, View.TRANSLATION_Y,
                          startingY, 0));
              }
              if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) {
                  mSplitView.setTranslationY(mSplitView.getHeight());
                  mSplitView.setVisibility(View.VISIBLE);
                  b.with(ObjectAnimator.ofFloat(mSplitView, View.TRANSLATION_Y, 0));
              }
              anim.setInterpolator(AnimationUtils.loadInterpolator(mContext,
                      com.android.internal.R.interpolator.decelerate_cubic));
              anim.setDuration(250);
              // If this is being shown from the system, add a small delay.
              // This is because we will also be animating in the status bar,
              // and these two elements can't be done in lock-step.  So we give
              // a little time for the status bar to start its animation before
              // the action bar animates.  (This corresponds to the corresponding
              // case when hiding, where the status bar has a small delay before
              // starting.)
              anim.addListener(mShowListener);
              mCurrentShowAnim = anim;
              anim.start();
          } else {
              mContainerView.setAlpha(1);
              mContainerView.setTranslationY(0);
              if (mContentAnimations && mContentView != null) {
                  mContentView.setTranslationY(0);
              }
              if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) {
                  mSplitView.setAlpha(1);
                  mSplitView.setTranslationY(0);
                  mSplitView.setVisibility(View.VISIBLE);
              }
              mShowListener.onAnimationEnd(null);
          }
          if (mOverlayLayout != null) {
              mOverlayLayout.requestApplyInsets();
          }
      }
  
      public void doHide(boolean fromSystem) {
          if (mCurrentShowAnim != null) {
              mCurrentShowAnim.end();
          }
  
          if (mCurWindowVisibility == View.VISIBLE && (mShowHideAnimationEnabled
                  || fromSystem)) {
              mContainerView.setAlpha(1);
              mContainerView.setTransitioning(true);
              AnimatorSet anim = new AnimatorSet();
              float endingY = -mContainerView.getHeight();
              if (fromSystem) {
                  int topLeft[] = {0, 0};
                  mContainerView.getLocationInWindow(topLeft);
                  endingY -= topLeft[1];
              }
              ObjectAnimator a = ObjectAnimator.ofFloat(mContainerView, View.TRANSLATION_Y, endingY);
              a.addUpdateListener(mUpdateListener);
              AnimatorSet.Builder b = anim.play(a);
              if (mContentAnimations && mContentView != null) {
                  b.with(ObjectAnimator.ofFloat(mContentView, View.TRANSLATION_Y,
                          0, endingY));
              }
              if (mSplitView != null && mSplitView.getVisibility() == View.VISIBLE) {
                  mSplitView.setAlpha(1);
                  b.with(ObjectAnimator.ofFloat(mSplitView, View.TRANSLATION_Y,
                          mSplitView.getHeight()));
              }
              anim.setInterpolator(AnimationUtils.loadInterpolator(mContext,
                      com.android.internal.R.interpolator.accelerate_cubic));
              anim.setDuration(250);
              anim.addListener(mHideListener);
              mCurrentShowAnim = anim;
              anim.start();
          } else {
              mHideListener.onAnimationEnd(null);
          }
      }
  
      public boolean isShowing() {
          final int height = getHeight();
          // Take into account the case where the bar has a 0 height due to not being measured yet.
          return mNowShowing && (height == 0 || getHideOffset() < height);
      }
  
      void animateToMode(boolean toActionMode) {
          if (toActionMode) {
              showForActionMode();
          } else {
              hideForActionMode();
          }
  
          if (shouldAnimateContextView()) {
              Animator fadeIn, fadeOut;
              if (toActionMode) {
                  fadeOut = mDecorToolbar.setupAnimatorToVisibility(View.GONE,
                          FADE_OUT_DURATION_MS);
                  fadeIn = mContextView.setupAnimatorToVisibility(View.VISIBLE,
                          FADE_IN_DURATION_MS);
              } else {
                  fadeIn = mDecorToolbar.setupAnimatorToVisibility(View.VISIBLE,
                          FADE_IN_DURATION_MS);
                  fadeOut = mContextView.setupAnimatorToVisibility(View.GONE,
                          FADE_OUT_DURATION_MS);
              }
              AnimatorSet set = new AnimatorSet();
              set.playSequentially(fadeOut, fadeIn);
              set.start();
          } else {
              if (toActionMode) {
                  mDecorToolbar.setVisibility(View.GONE);
                  mContextView.setVisibility(View.VISIBLE);
              } else {
                  mDecorToolbar.setVisibility(View.VISIBLE);
                  mContextView.setVisibility(View.GONE);
              }
          }
          // mTabScrollView's visibility is not affected by action mode.
      }
  
      private boolean shouldAnimateContextView() {
          // We only to animate the action mode in if the container view has already been laid out.
          // If it hasn't been laid out, it hasn't been drawn to screen yet.
          return mContainerView.isLaidOut();
      }
  
      public Context getThemedContext() {
          if (mThemedContext == null) {
              TypedValue outValue = new TypedValue();
              Resources.Theme currentTheme = mContext.getTheme();
              currentTheme.resolveAttribute(com.android.internal.R.attr.actionBarWidgetTheme,
                      outValue, true);
              final int targetThemeRes = outValue.resourceId;
  
              if (targetThemeRes != 0 && mContext.getThemeResId() != targetThemeRes) {
                  mThemedContext = new ContextThemeWrapper(mContext, targetThemeRes);
              } else {
                  mThemedContext = mContext;
              }
          }
          return mThemedContext;
      }
  
      @Override
      public boolean isTitleTruncated() {
          return mDecorToolbar != null && mDecorToolbar.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 setHomeActionContentDescription(int resId) {
          mDecorToolbar.setNavigationContentDescription(resId);
      }
  
      @Override
      public void onContentScrollStarted() {
          if (mCurrentShowAnim != null) {
              mCurrentShowAnim.cancel();
              mCurrentShowAnim = null;
          }
      }
  
      @Override
      public void onContentScrollStopped() {
      }
  
      @Override
      public boolean collapseActionView() {
          if (mDecorToolbar != null && mDecorToolbar.hasExpandedActionView()) {
              mDecorToolbar.collapseActionView();
              return true;
          }
          return false;
      }
  
      /**
       * @hide
       */
      public class ActionModeImpl extends ActionMode implements MenuBuilder.Callback {
          private final Context mActionModeContext;
          private final MenuBuilder mMenu;
  
          private ActionMode.Callback mCallback;
          private WeakReference<View> mCustomView;
  
          public ActionModeImpl(
                  Context context, ActionMode.Callback callback) {
              mActionModeContext = context;
              mCallback = callback;
              mMenu = new MenuBuilder(context)
                          .setDefaultShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
              mMenu.setCallback(this);
          }
  
          @Override
          public MenuInflater getMenuInflater() {
              return new MenuInflater(mActionModeContext);
          }
  
          @Override
          public Menu getMenu() {
              return mMenu;
          }
  
          @Override
          public void finish() {
              if (mActionMode != this) {
                  // Not the active action mode - no-op
                  return;
              }
  
              // If this change in state is going to cause the action bar
              // to be hidden, defer the onDestroy callback until the animation
              // is finished and associated relayout is about to happen. This lets
              // apps better anticipate visibility and layout behavior.
              if (!checkShowingFlags(mHiddenByApp, mHiddenBySystem, false)) {
                  // With the current state but the action bar hidden, our
                  // overall showing state is going to be false.
                  mDeferredDestroyActionMode = this;
                  mDeferredModeDestroyCallback = mCallback;
              } else {
                  mCallback.onDestroyActionMode(this);
              }
              mCallback = null;
              animateToMode(false);
  
              // Clear out the context mode views after the animation finishes
              mContextView.closeMode();
              mDecorToolbar.getViewGroup().sendAccessibilityEvent(
                      AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
              mOverlayLayout.setHideOnContentScrollEnabled(mHideOnContentScroll);
  
              mActionMode = null;
          }
  
          @Override
          public void invalidate() {
              if (mActionMode != this) {
                  // Not the active action mode - no-op. It's possible we are
                  // currently deferring onDestroy, so the app doesn't yet know we
                  // are going away and is trying to use us. That's also a no-op.
                  return;
              }
  
              mMenu.stopDispatchingItemsChanged();
              try {
                  mCallback.onPrepareActionMode(this, mMenu);
              } finally {
                  mMenu.startDispatchingItemsChanged();
              }
          }
  
          public boolean dispatchOnCreate() {
              mMenu.stopDispatchingItemsChanged();
              try {
                  return mCallback.onCreateActionMode(this, mMenu);
              } finally {
                  mMenu.startDispatchingItemsChanged();
              }
          }
  
          @Override
          public void setCustomView(View view) {
              mContextView.setCustomView(view);
              mCustomView = new WeakReference<View>(view);
          }
  
          @Override
          public void setSubtitle(CharSequence subtitle) {
              mContextView.setSubtitle(subtitle);
          }
  
          @Override
          public void setTitle(CharSequence title) {
              mContextView.setTitle(title);
          }
  
          @Override
          public void setTitle(int resId) {
              setTitle(mContext.getResources().getString(resId));
          }
  
          @Override
          public void setSubtitle(int resId) {
              setSubtitle(mContext.getResources().getString(resId));
          }
  
          @Override
          public CharSequence getTitle() {
              return mContextView.getTitle();
          }
  
          @Override
          public CharSequence getSubtitle() {
              return mContextView.getSubtitle();
          }
  
          @Override
          public void setTitleOptionalHint(boolean titleOptional) {
              super.setTitleOptionalHint(titleOptional);
              mContextView.setTitleOptional(titleOptional);
          }
  
          @Override
          public boolean isTitleOptional() {
              return mContextView.isTitleOptional();
          }
  
          @Override
          public View getCustomView() {
              return mCustomView != null ? mCustomView.get() : null;
          }
  
          public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
              if (mCallback != null) {
                  return mCallback.onActionItemClicked(this, item);
              } else {
                  return false;
              }
          }
  
          public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
          }
  
          public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
              if (mCallback == null) {
                  return false;
              }
  
              if (!subMenu.hasVisibleItems()) {
                  return true;
              }
  
              new MenuPopupHelper(getThemedContext(), subMenu).show();
              return true;
          }
  
          public void onCloseSubMenu(SubMenuBuilder menu) {
          }
  
          public void onMenuModeChange(MenuBuilder menu) {
              if (mCallback == null) {
                  return;
              }
              invalidate();
              mContextView.showOverflowMenu();
          }
      }
  
      /**
       * @hide
       */
      public class TabImpl extends ActionBar.Tab {
          @UnsupportedAppUsage
          private ActionBar.TabListener mCallback;
          private Object mTag;
          private Drawable mIcon;
          private CharSequence mText;
          private CharSequence mContentDesc;
          private int mPosition = -1;
          private View mCustomView;
  
          @Override
          public Object getTag() {
              return mTag;
          }
  
          @Override
          public Tab setTag(Object tag) {
              mTag = tag;
              return this;
          }
  
          public ActionBar.TabListener getCallback() {
              return mCallback;
          }
  
          @Override
          public Tab setTabListener(ActionBar.TabListener callback) {
              mCallback = callback;
              return this;
          }
  
          @Override
          public View getCustomView() {
              return mCustomView;
          }
  
          @Override
          public Tab setCustomView(View view) {
              mCustomView = view;
              if (mPosition >= 0) {
                  mTabScrollView.updateTab(mPosition);
              }
              return this;
          }
  
          @Override
          public Tab setCustomView(int layoutResId) {
              return setCustomView(LayoutInflater.from(getThemedContext())
                      .inflate(layoutResId, null));
          }
  
          @Override
          public Drawable getIcon() {
              return mIcon;
          }
  
          @Override
          public int getPosition() {
              return mPosition;
          }
  
          public void setPosition(int position) {
              mPosition = position;
          }
  
          @Override
          public CharSequence getText() {
              return mText;
          }
  
          @Override
          public Tab setIcon(Drawable icon) {
              mIcon = icon;
              if (mPosition >= 0) {
                  mTabScrollView.updateTab(mPosition);
              }
              return this;
          }
  
          @Override
          public Tab setIcon(int resId) {
              return setIcon(mContext.getDrawable(resId));
          }
  
          @Override
          public Tab setText(CharSequence text) {
              mText = text;
              if (mPosition >= 0) {
                  mTabScrollView.updateTab(mPosition);
              }
              return this;
          }
  
          @Override
          public Tab setText(int resId) {
              return setText(mContext.getResources().getText(resId));
          }
  
          @Override
          public void select() {
              selectTab(this);
          }
  
          @Override
          public Tab setContentDescription(int resId) {
              return setContentDescription(mContext.getResources().getText(resId));
          }
  
          @Override
          public Tab setContentDescription(CharSequence contentDesc) {
              mContentDesc = contentDesc;
              if (mPosition >= 0) {
                  mTabScrollView.updateTab(mPosition);
              }
              return this;
          }
  
          @Override
          public CharSequence getContentDescription() {
              return mContentDesc;
          }
      }
  
      @Override
      public void setCustomView(View view) {
          mDecorToolbar.setCustomView(view);
      }
  
      @Override
      public void setCustomView(View view, LayoutParams layoutParams) {
          view.setLayoutParams(layoutParams);
          mDecorToolbar.setCustomView(view);
      }
  
      @Override
      public void setListNavigationCallbacks(SpinnerAdapter adapter, OnNavigationListener callback) {
          mDecorToolbar.setDropdownParams(adapter, new NavItemSelectedListener(callback));
      }
  
      @Override
      public int getSelectedNavigationIndex() {
          switch (mDecorToolbar.getNavigationMode()) {
              case NAVIGATION_MODE_TABS:
                  return mSelectedTab != null ? mSelectedTab.getPosition() : -1;
              case NAVIGATION_MODE_LIST:
                  return mDecorToolbar.getDropdownSelectedPosition();
              default:
                  return -1;
          }
      }
  
      @Override
      public int getNavigationItemCount() {
          switch (mDecorToolbar.getNavigationMode()) {
              case NAVIGATION_MODE_TABS:
                  return mTabs.size();
              case NAVIGATION_MODE_LIST:
                  return mDecorToolbar.getDropdownItemCount();
              default:
                  return 0;
          }
      }
  
      @Override
      public int getTabCount() {
          return mTabs.size();
      }
  
      @Override
      public void setNavigationMode(int mode) {
          final int oldMode = mDecorToolbar.getNavigationMode();
          switch (oldMode) {
              case NAVIGATION_MODE_TABS:
                  mSavedTabPosition = getSelectedNavigationIndex();
                  selectTab(null);
                  mTabScrollView.setVisibility(View.GONE);
                  break;
          }
          if (oldMode != mode && !mHasEmbeddedTabs) {
              if (mOverlayLayout != null) {
                  mOverlayLayout.requestFitSystemWindows();
              }
          }
          mDecorToolbar.setNavigationMode(mode);
          switch (mode) {
              case NAVIGATION_MODE_TABS:
                  ensureTabsExist();
                  mTabScrollView.setVisibility(View.VISIBLE);
                  if (mSavedTabPosition != INVALID_POSITION) {
                      setSelectedNavigationItem(mSavedTabPosition);
                      mSavedTabPosition = INVALID_POSITION;
                  }
                  break;
          }
          mDecorToolbar.setCollapsible(mode == NAVIGATION_MODE_TABS && !mHasEmbeddedTabs);
          mOverlayLayout.setHasNonEmbeddedTabs(mode == NAVIGATION_MODE_TABS && !mHasEmbeddedTabs);
      }
  
      @Override
      public Tab getTabAt(int index) {
          return mTabs.get(index);
      }
  
  
      @Override
      public void setIcon(int resId) {
          mDecorToolbar.setIcon(resId);
      }
  
      @Override
      public void setIcon(Drawable icon) {
          mDecorToolbar.setIcon(icon);
      }
  
      public boolean hasIcon() {
          return mDecorToolbar.hasIcon();
      }
  
      @Override
      public void setLogo(int resId) {
          mDecorToolbar.setLogo(resId);
      }
  
      @Override
      public void setLogo(Drawable logo) {
          mDecorToolbar.setLogo(logo);
      }
  
      public boolean hasLogo() {
          return mDecorToolbar.hasLogo();
      }
  
      public void setDefaultDisplayHomeAsUpEnabled(boolean enable) {
          if (!mDisplayHomeAsUpSet) {
              setDisplayHomeAsUpEnabled(enable);
          }
      }
  
  }
  