content: /*
   * Copyright (C) 2011 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.actionbarsherlock.internal.widget;
  
  import android.content.Context;
  import android.content.res.Configuration;
  import android.content.res.TypedArray;
  import android.graphics.drawable.Drawable;
  import android.text.TextUtils.TruncateAt;
  import android.util.AttributeSet;
  import android.view.Gravity;
  import android.view.LayoutInflater;
  import android.view.View;
  import android.view.ViewGroup;
  import android.view.ViewParent;
  import android.view.animation.DecelerateInterpolator;
  import android.view.animation.Interpolator;
  import android.widget.BaseAdapter;
  import android.widget.ImageView;
  import android.widget.LinearLayout;
  import android.widget.ListView;
  import com.actionbarsherlock.R;
  import com.actionbarsherlock.app.ActionBar;
  import com.actionbarsherlock.internal.nineoldandroids.animation.Animator;
  import com.actionbarsherlock.internal.nineoldandroids.animation.ObjectAnimator;
  import com.actionbarsherlock.internal.nineoldandroids.widget.NineHorizontalScrollView;
  
  /**
   * This widget implements the dynamic action bar tab behavior that can change
   * across different configurations or circumstances.
   */
  public class ScrollingTabContainerView extends NineHorizontalScrollView
          implements IcsAdapterView.OnItemSelectedListener {
      //UNUSED private static final String TAG = "ScrollingTabContainerView";
      Runnable mTabSelector;
      private TabClickListener mTabClickListener;
  
      private IcsLinearLayout mTabLayout;
      private IcsSpinner mTabSpinner;
      private boolean mAllowCollapse;
  
      private LayoutInflater mInflater;
  
      int mMaxTabWidth;
      private int mContentHeight;
      private int mSelectedTabIndex;
  
      protected Animator mVisibilityAnim;
      protected final VisibilityAnimListener mVisAnimListener = new VisibilityAnimListener();
  
      private static final /*Time*/Interpolator sAlphaInterpolator = new DecelerateInterpolator();
  
      private static final int FADE_DURATION = 200;
  
      public ScrollingTabContainerView(Context context) {
          super(context);
          setHorizontalScrollBarEnabled(false);
  
          TypedArray a = getContext().obtainStyledAttributes(null, R.styleable.SherlockActionBar,
                  R.attr.actionBarStyle, 0);
          setContentHeight(a.getLayoutDimension(R.styleable.SherlockActionBar_height, 0));
          a.recycle();
  
          mInflater = LayoutInflater.from(context);
  
          mTabLayout = createTabLayout();
          addView(mTabLayout, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
                  ViewGroup.LayoutParams.MATCH_PARENT));
      }
  
      @Override
      public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
          final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
          final boolean lockedExpanded = widthMode == MeasureSpec.EXACTLY;
          setFillViewport(lockedExpanded);
  
          final int childCount = mTabLayout.getChildCount();
          if (childCount > 1 &&
                  (widthMode == MeasureSpec.EXACTLY || widthMode == MeasureSpec.AT_MOST)) {
              if (childCount > 2) {
                  mMaxTabWidth = (int) (MeasureSpec.getSize(widthMeasureSpec) * 0.4f);
              } else {
                  mMaxTabWidth = MeasureSpec.getSize(widthMeasureSpec) / 2;
              }
          } else {
              mMaxTabWidth = -1;
          }
  
          heightMeasureSpec = MeasureSpec.makeMeasureSpec(mContentHeight, MeasureSpec.EXACTLY);
  
          final boolean canCollapse = !lockedExpanded && mAllowCollapse;
  
          if (canCollapse) {
              // See if we should expand
              mTabLayout.measure(MeasureSpec.UNSPECIFIED, heightMeasureSpec);
              if (mTabLayout.getMeasuredWidth() > MeasureSpec.getSize(widthMeasureSpec)) {
                  performCollapse();
              } else {
                  performExpand();
              }
          } else {
              performExpand();
          }
  
          final int oldWidth = getMeasuredWidth();
          super.onMeasure(widthMeasureSpec, heightMeasureSpec);
          final int newWidth = getMeasuredWidth();
  
          if (lockedExpanded && oldWidth != newWidth) {
              // Recenter the tab display if we're at a new (scrollable) size.
              setTabSelected(mSelectedTabIndex);
          }
      }
  
      /**
       * Indicates whether this view is collapsed into a dropdown menu instead
       * of traditional tabs.
       * @return true if showing as a spinner
       */
      private boolean isCollapsed() {
          return mTabSpinner != null && mTabSpinner.getParent() == this;
      }
  
      public void setAllowCollapse(boolean allowCollapse) {
          mAllowCollapse = allowCollapse;
      }
  
      private void performCollapse() {
          if (isCollapsed()) return;
  
          if (mTabSpinner == null) {
              mTabSpinner = createSpinner();
          }
          removeView(mTabLayout);
          addView(mTabSpinner, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
                  ViewGroup.LayoutParams.MATCH_PARENT));
          if (mTabSpinner.getAdapter() == null) {
              mTabSpinner.setAdapter(new TabAdapter());
          }
          if (mTabSelector != null) {
              removeCallbacks(mTabSelector);
              mTabSelector = null;
          }
          mTabSpinner.setSelection(mSelectedTabIndex);
      }
  
      private boolean performExpand() {
          if (!isCollapsed()) return false;
  
          removeView(mTabSpinner);
          addView(mTabLayout, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
                  ViewGroup.LayoutParams.MATCH_PARENT));
          setTabSelected(mTabSpinner.getSelectedItemPosition());
          return false;
      }
  
      public void setTabSelected(int position) {
          mSelectedTabIndex = position;
          final int tabCount = mTabLayout.getChildCount();
          for (int i = 0; i < tabCount; i++) {
              final View child = mTabLayout.getChildAt(i);
              final boolean isSelected = i == position;
              child.setSelected(isSelected);
              if (isSelected) {
                  animateToTab(position);
              }
          }
      }
  
      public void setContentHeight(int contentHeight) {
          mContentHeight = contentHeight;
          requestLayout();
      }
  
      private IcsLinearLayout createTabLayout() {
          final TabsLinearLayout tabLayout = (TabsLinearLayout) LayoutInflater.from(getContext())
                  .inflate(R.layout.abs__action_bar_tab_bar_view, null);
          tabLayout.setMeasureWithLargestChildEnabled(true);
          tabLayout.setLayoutParams(new LinearLayout.LayoutParams(
                  LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.MATCH_PARENT));
          return tabLayout;
      }
  
      private IcsSpinner createSpinner() {
          final IcsSpinner spinner = new IcsSpinner(getContext(), null,
                  R.attr.actionDropDownStyle);
          spinner.setLayoutParams(new LinearLayout.LayoutParams(
                  LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.MATCH_PARENT));
          spinner.setOnItemSelectedListener(this);
          return spinner;
      }
  
      @Override
      protected void onConfigurationChanged(Configuration newConfig) {
          super.onConfigurationChanged(newConfig);
  
          // Action bar can change size on configuration changes.
          // Reread the desired height from the theme-specified style.
          TypedArray a = getContext().obtainStyledAttributes(null, R.styleable.SherlockActionBar,
                  R.attr.actionBarStyle, 0);
          setContentHeight(a.getLayoutDimension(R.styleable.SherlockActionBar_height, 0));
          a.recycle();
      }
  
      public void animateToVisibility(int visibility) {
          if (mVisibilityAnim != null) {
              mVisibilityAnim.cancel();
          }
          if (visibility == VISIBLE) {
              if (getVisibility() != VISIBLE) {
                  setAlpha(0);
              }
              ObjectAnimator anim = ObjectAnimator.ofFloat(this, "alpha", 1);
              anim.setDuration(FADE_DURATION);
              anim.setInterpolator(sAlphaInterpolator);
  
              anim.addListener(mVisAnimListener.withFinalVisibility(visibility));
              anim.start();
          } else {
              ObjectAnimator anim = ObjectAnimator.ofFloat(this, "alpha", 0);
              anim.setDuration(FADE_DURATION);
              anim.setInterpolator(sAlphaInterpolator);
  
              anim.addListener(mVisAnimListener.withFinalVisibility(visibility));
              anim.start();
          }
      }
  
      public void animateToTab(final int position) {
          final View tabView = mTabLayout.getChildAt(position);
          if (mTabSelector != null) {
              removeCallbacks(mTabSelector);
          }
          mTabSelector = new Runnable() {
              public void run() {
                  final int scrollPos = tabView.getLeft() - (getWidth() - tabView.getWidth()) / 2;
                  smoothScrollTo(scrollPos, 0);
                  mTabSelector = null;
              }
          };
          post(mTabSelector);
      }
  
      @Override
      public void onAttachedToWindow() {
          super.onAttachedToWindow();
          if (mTabSelector != null) {
              // Re-post the selector we saved
              post(mTabSelector);
          }
      }
  
      @Override
      public void onDetachedFromWindow() {
          super.onDetachedFromWindow();
          if (mTabSelector != null) {
              removeCallbacks(mTabSelector);
          }
      }
  
      private TabView createTabView(ActionBar.Tab tab, boolean forAdapter) {
          //Workaround for not being able to pass a defStyle on pre-3.0
          final TabView tabView = (TabView)mInflater.inflate(R.layout.abs__action_bar_tab, null);
          tabView.init(this, tab, forAdapter);
  
          if (forAdapter) {
              tabView.setBackgroundDrawable(null);
              tabView.setLayoutParams(new ListView.LayoutParams(ListView.LayoutParams.MATCH_PARENT,
                      mContentHeight));
          } else {
              tabView.setFocusable(true);
  
              if (mTabClickListener == null) {
                  mTabClickListener = new TabClickListener();
              }
              tabView.setOnClickListener(mTabClickListener);
          }
          return tabView;
      }
  
      public void addTab(ActionBar.Tab tab, boolean setSelected) {
          TabView tabView = createTabView(tab, false);
          mTabLayout.addView(tabView, new IcsLinearLayout.LayoutParams(0,
                  LayoutParams.MATCH_PARENT, 1));
          if (mTabSpinner != null) {
              ((TabAdapter) mTabSpinner.getAdapter()).notifyDataSetChanged();
          }
          if (setSelected) {
              tabView.setSelected(true);
          }
          if (mAllowCollapse) {
              requestLayout();
          }
      }
  
      public void addTab(ActionBar.Tab tab, int position, boolean setSelected) {
          final TabView tabView = createTabView(tab, false);
          mTabLayout.addView(tabView, position, new IcsLinearLayout.LayoutParams(
                  0, LayoutParams.MATCH_PARENT, 1));
          if (mTabSpinner != null) {
              ((TabAdapter) mTabSpinner.getAdapter()).notifyDataSetChanged();
          }
          if (setSelected) {
              tabView.setSelected(true);
          }
          if (mAllowCollapse) {
              requestLayout();
          }
      }
  
      public void updateTab(int position) {
          ((TabView) mTabLayout.getChildAt(position)).update();
          if (mTabSpinner != null) {
              ((TabAdapter) mTabSpinner.getAdapter()).notifyDataSetChanged();
          }
          if (mAllowCollapse) {
              requestLayout();
          }
      }
  
      public void removeTabAt(int position) {
          mTabLayout.removeViewAt(position);
          if (mTabSpinner != null) {
              ((TabAdapter) mTabSpinner.getAdapter()).notifyDataSetChanged();
          }
          if (mAllowCollapse) {
              requestLayout();
          }
      }
  
      public void removeAllTabs() {
          mTabLayout.removeAllViews();
          if (mTabSpinner != null) {
              ((TabAdapter) mTabSpinner.getAdapter()).notifyDataSetChanged();
          }
          if (mAllowCollapse) {
              requestLayout();
          }
      }
  
      @Override
      public void onItemSelected(IcsAdapterView<?> parent, View view, int position, long id) {
          TabView tabView = (TabView) view;
          tabView.getTab().select();
      }
  
      @Override
      public void onNothingSelected(IcsAdapterView<?> parent) {
      }
  
      public static class TabView extends LinearLayout {
          private ScrollingTabContainerView mParent;
          private ActionBar.Tab mTab;
          private CapitalizingTextView mTextView;
          private ImageView mIconView;
          private View mCustomView;
  
          public TabView(Context context, AttributeSet attrs) {
              //TODO super(context, null, R.attr.actionBarTabStyle);
              super(context, attrs);
          }
  
          public void init(ScrollingTabContainerView parent, ActionBar.Tab tab, boolean forList) {
              mParent = parent;
              mTab = tab;
  
              if (forList) {
                  setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL);
              }
  
              update();
          }
  
          public void bindTab(ActionBar.Tab tab) {
              mTab = tab;
              update();
          }
  
          @Override
          public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
              super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  
              // Re-measure if we went beyond our maximum size.
              if (mParent.mMaxTabWidth > 0 && getMeasuredWidth() > mParent.mMaxTabWidth) {
                  super.onMeasure(MeasureSpec.makeMeasureSpec(mParent.mMaxTabWidth, MeasureSpec.EXACTLY),
                          heightMeasureSpec);
              }
          }
  
          public void update() {
              final ActionBar.Tab tab = mTab;
              final View custom = tab.getCustomView();
              if (custom != null) {
                  final ViewParent customParent = custom.getParent();
                  if (customParent != this) {
                      if (customParent != null) ((ViewGroup) customParent).removeView(custom);
                      addView(custom);
                  }
                  mCustomView = custom;
                  if (mTextView != null) mTextView.setVisibility(GONE);
                  if (mIconView != null) {
                      mIconView.setVisibility(GONE);
                      mIconView.setImageDrawable(null);
                  }
              } else {
                  if (mCustomView != null) {
                      removeView(mCustomView);
                      mCustomView = null;
                  }
  
                  final Drawable icon = tab.getIcon();
                  final CharSequence text = tab.getText();
  
                  if (icon != null) {
                      if (mIconView == null) {
                          ImageView iconView = new ImageView(getContext());
                          LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT,
                                  LayoutParams.WRAP_CONTENT);
                          lp.gravity = Gravity.CENTER_VERTICAL;
                          iconView.setLayoutParams(lp);
                          addView(iconView, 0);
                          mIconView = iconView;
                      }
                      mIconView.setImageDrawable(icon);
                      mIconView.setVisibility(VISIBLE);
                  } else if (mIconView != null) {
                      mIconView.setVisibility(GONE);
                      mIconView.setImageDrawable(null);
                  }
  
                  if (text != null) {
                      if (mTextView == null) {
                          CapitalizingTextView textView = new CapitalizingTextView(getContext(), null,
                                  R.attr.actionBarTabTextStyle);
                          textView.setEllipsize(TruncateAt.END);
                          LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT,
                                  LayoutParams.WRAP_CONTENT);
                          lp.gravity = Gravity.CENTER_VERTICAL;
                          textView.setLayoutParams(lp);
                          addView(textView);
                          mTextView = textView;
                      }
                      mTextView.setTextCompat(text);
                      mTextView.setVisibility(VISIBLE);
                  } else if (mTextView != null) {
                      mTextView.setVisibility(GONE);
                      mTextView.setText(null);
                  }
  
                  if (mIconView != null) {
                      mIconView.setContentDescription(tab.getContentDescription());
                  }
              }
          }
  
          public ActionBar.Tab getTab() {
              return mTab;
          }
      }
  
      private class TabAdapter extends BaseAdapter {
          @Override
          public int getCount() {
              return mTabLayout.getChildCount();
          }
  
          @Override
          public Object getItem(int position) {
              return ((TabView) mTabLayout.getChildAt(position)).getTab();
          }
  
          @Override
          public long getItemId(int position) {
              return position;
          }
  
          @Override
          public View getView(int position, View convertView, ViewGroup parent) {
              if (convertView == null) {
                  convertView = createTabView((ActionBar.Tab) getItem(position), true);
              } else {
                  ((TabView) convertView).bindTab((ActionBar.Tab) getItem(position));
              }
              return convertView;
          }
      }
  
      private class TabClickListener implements OnClickListener {
          public void onClick(View view) {
              TabView tabView = (TabView) view;
              tabView.getTab().select();
              final int tabCount = mTabLayout.getChildCount();
              for (int i = 0; i < tabCount; i++) {
                  final View child = mTabLayout.getChildAt(i);
                  child.setSelected(child == view);
              }
          }
      }
  
      protected class VisibilityAnimListener implements Animator.AnimatorListener {
          private boolean mCanceled = false;
          private int mFinalVisibility;
  
          public VisibilityAnimListener withFinalVisibility(int visibility) {
              mFinalVisibility = visibility;
              return this;
          }
  
          @Override
          public void onAnimationStart(Animator animation) {
              setVisibility(VISIBLE);
              mVisibilityAnim = animation;
              mCanceled = false;
          }
  
          @Override
          public void onAnimationEnd(Animator animation) {
              if (mCanceled) return;
  
              mVisibilityAnim = null;
              setVisibility(mFinalVisibility);
          }
  
          @Override
          public void onAnimationCancel(Animator animation) {
              mCanceled = true;
          }
  
          @Override
          public void onAnimationRepeat(Animator animation) {
          }
      }
  }
  