| /* |
| * 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.widget; |
| |
| import com.android.internal.R; |
| import com.android.internal.view.menu.ActionMenuItem; |
| import com.android.internal.view.menu.ActionMenuPresenter; |
| import com.android.internal.view.menu.ActionMenuView; |
| import com.android.internal.view.menu.MenuBuilder; |
| import com.android.internal.view.menu.MenuItemImpl; |
| import com.android.internal.view.menu.MenuPresenter; |
| import com.android.internal.view.menu.MenuView; |
| import com.android.internal.view.menu.SubMenuBuilder; |
| |
| import android.animation.LayoutTransition; |
| import android.app.ActionBar; |
| import android.app.ActionBar.OnNavigationListener; |
| import android.app.Activity; |
| import android.content.Context; |
| import android.content.pm.ApplicationInfo; |
| import android.content.pm.PackageManager; |
| import android.content.pm.PackageManager.NameNotFoundException; |
| import android.content.res.Configuration; |
| import android.content.res.TypedArray; |
| import android.graphics.Rect; |
| import android.graphics.drawable.Drawable; |
| import android.os.Parcel; |
| import android.os.Parcelable; |
| import android.text.Layout; |
| import android.text.TextUtils; |
| import android.util.AttributeSet; |
| import android.util.Log; |
| import android.view.CollapsibleActionView; |
| import android.view.Gravity; |
| import android.view.LayoutInflater; |
| import android.view.Menu; |
| import android.view.MenuItem; |
| import android.view.MotionEvent; |
| import android.view.View; |
| import android.view.ViewGroup; |
| import android.view.ViewParent; |
| import android.view.Window; |
| import android.view.accessibility.AccessibilityEvent; |
| import android.widget.AdapterView; |
| import android.widget.FrameLayout; |
| import android.widget.ImageView; |
| import android.widget.LinearLayout; |
| import android.widget.ProgressBar; |
| import android.widget.Spinner; |
| import android.widget.SpinnerAdapter; |
| import android.widget.TextView; |
| |
| /** |
| * @hide |
| */ |
| public class ActionBarView extends AbsActionBarView { |
| private static final String TAG = "ActionBarView"; |
| |
| /** |
| * Display options applied by default |
| */ |
| public static final int DISPLAY_DEFAULT = 0; |
| |
| /** |
| * Display options that require re-layout as opposed to a simple invalidate |
| */ |
| private static final int DISPLAY_RELAYOUT_MASK = |
| ActionBar.DISPLAY_SHOW_HOME | |
| ActionBar.DISPLAY_USE_LOGO | |
| ActionBar.DISPLAY_HOME_AS_UP | |
| ActionBar.DISPLAY_SHOW_CUSTOM | |
| ActionBar.DISPLAY_SHOW_TITLE | |
| ActionBar.DISPLAY_TITLE_MULTIPLE_LINES; |
| |
| private static final int DEFAULT_CUSTOM_GRAVITY = Gravity.START | Gravity.CENTER_VERTICAL; |
| |
| private int mNavigationMode; |
| private int mDisplayOptions = -1; |
| private CharSequence mTitle; |
| private CharSequence mSubtitle; |
| private Drawable mIcon; |
| private Drawable mLogo; |
| |
| private HomeView mHomeLayout; |
| private HomeView mExpandedHomeLayout; |
| private LinearLayout mTitleLayout; |
| private TextView mTitleView; |
| private TextView mSubtitleView; |
| private View mTitleUpView; |
| private ViewGroup mUpGoerFive; |
| |
| private Spinner mSpinner; |
| private LinearLayout mListNavLayout; |
| private ScrollingTabContainerView mTabScrollView; |
| private View mCustomNavView; |
| private ProgressBar mProgressView; |
| private ProgressBar mIndeterminateProgressView; |
| |
| private int mProgressBarPadding; |
| private int mItemPadding; |
| |
| private int mTitleStyleRes; |
| private int mSubtitleStyleRes; |
| private int mProgressStyle; |
| private int mIndeterminateProgressStyle; |
| |
| private boolean mUserTitle; |
| private boolean mIncludeTabs; |
| private boolean mIsCollapsable; |
| private boolean mIsCollapsed; |
| private boolean mWasHomeEnabled; // Was it enabled before action view expansion? |
| |
| private MenuBuilder mOptionsMenu; |
| |
| private ActionBarContextView mContextView; |
| |
| private ActionMenuItem mLogoNavItem; |
| |
| private SpinnerAdapter mSpinnerAdapter; |
| private OnNavigationListener mCallback; |
| |
| private Runnable mTabSelector; |
| |
| private ExpandedActionViewMenuPresenter mExpandedMenuPresenter; |
| View mExpandedActionView; |
| |
| Window.Callback mWindowCallback; |
| |
| private final AdapterView.OnItemSelectedListener mNavItemSelectedListener = |
| new AdapterView.OnItemSelectedListener() { |
| public void onItemSelected(AdapterView parent, View view, int position, long id) { |
| if (mCallback != null) { |
| mCallback.onNavigationItemSelected(position, id); |
| } |
| } |
| public void onNothingSelected(AdapterView parent) { |
| // Do nothing |
| } |
| }; |
| |
| private final OnClickListener mExpandedActionViewUpListener = new OnClickListener() { |
| @Override |
| public void onClick(View v) { |
| final MenuItemImpl item = mExpandedMenuPresenter.mCurrentExpandedItem; |
| if (item != null) { |
| item.collapseActionView(); |
| } |
| } |
| }; |
| |
| private final OnClickListener mUpClickListener = new OnClickListener() { |
| public void onClick(View v) { |
| mWindowCallback.onMenuItemSelected(Window.FEATURE_OPTIONS_PANEL, mLogoNavItem); |
| } |
| }; |
| |
| public ActionBarView(Context context, AttributeSet attrs) { |
| super(context, attrs); |
| |
| // Background is always provided by the container. |
| setBackgroundResource(0); |
| |
| TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ActionBar, |
| com.android.internal.R.attr.actionBarStyle, 0); |
| |
| ApplicationInfo appInfo = context.getApplicationInfo(); |
| PackageManager pm = context.getPackageManager(); |
| mNavigationMode = a.getInt(R.styleable.ActionBar_navigationMode, |
| ActionBar.NAVIGATION_MODE_STANDARD); |
| mTitle = a.getText(R.styleable.ActionBar_title); |
| mSubtitle = a.getText(R.styleable.ActionBar_subtitle); |
| |
| mLogo = a.getDrawable(R.styleable.ActionBar_logo); |
| if (mLogo == null) { |
| if (context instanceof Activity) { |
| try { |
| mLogo = pm.getActivityLogo(((Activity) context).getComponentName()); |
| } catch (NameNotFoundException e) { |
| Log.e(TAG, "Activity component name not found!", e); |
| } |
| } |
| if (mLogo == null) { |
| mLogo = appInfo.loadLogo(pm); |
| } |
| } |
| |
| mIcon = a.getDrawable(R.styleable.ActionBar_icon); |
| if (mIcon == null) { |
| if (context instanceof Activity) { |
| try { |
| mIcon = pm.getActivityIcon(((Activity) context).getComponentName()); |
| } catch (NameNotFoundException e) { |
| Log.e(TAG, "Activity component name not found!", e); |
| } |
| } |
| if (mIcon == null) { |
| mIcon = appInfo.loadIcon(pm); |
| } |
| } |
| |
| final LayoutInflater inflater = LayoutInflater.from(context); |
| |
| final int homeResId = a.getResourceId( |
| com.android.internal.R.styleable.ActionBar_homeLayout, |
| com.android.internal.R.layout.action_bar_home); |
| |
| mUpGoerFive = (ViewGroup) inflater.inflate( |
| com.android.internal.R.layout.action_bar_up_container, this, false); |
| mHomeLayout = (HomeView) inflater.inflate(homeResId, mUpGoerFive, false); |
| |
| mExpandedHomeLayout = (HomeView) inflater.inflate(homeResId, mUpGoerFive, false); |
| mExpandedHomeLayout.setUp(true); |
| mExpandedHomeLayout.setOnClickListener(mExpandedActionViewUpListener); |
| mExpandedHomeLayout.setContentDescription(getResources().getText( |
| R.string.action_bar_up_description)); |
| |
| // This needs to highlight/be focusable on its own. |
| // TODO: Clean up the handoff between expanded/normal. |
| final Drawable upBackground = mUpGoerFive.getBackground(); |
| if (upBackground != null) { |
| mExpandedHomeLayout.setBackground(upBackground.getConstantState().newDrawable()); |
| } |
| mExpandedHomeLayout.setEnabled(true); |
| mExpandedHomeLayout.setFocusable(true); |
| |
| mTitleStyleRes = a.getResourceId(R.styleable.ActionBar_titleTextStyle, 0); |
| mSubtitleStyleRes = a.getResourceId(R.styleable.ActionBar_subtitleTextStyle, 0); |
| mProgressStyle = a.getResourceId(R.styleable.ActionBar_progressBarStyle, 0); |
| mIndeterminateProgressStyle = a.getResourceId( |
| R.styleable.ActionBar_indeterminateProgressStyle, 0); |
| |
| mProgressBarPadding = a.getDimensionPixelOffset(R.styleable.ActionBar_progressBarPadding, 0); |
| mItemPadding = a.getDimensionPixelOffset(R.styleable.ActionBar_itemPadding, 0); |
| |
| setDisplayOptions(a.getInt(R.styleable.ActionBar_displayOptions, DISPLAY_DEFAULT)); |
| |
| final int customNavId = a.getResourceId(R.styleable.ActionBar_customNavigationLayout, 0); |
| if (customNavId != 0) { |
| mCustomNavView = (View) inflater.inflate(customNavId, this, false); |
| mNavigationMode = ActionBar.NAVIGATION_MODE_STANDARD; |
| setDisplayOptions(mDisplayOptions | ActionBar.DISPLAY_SHOW_CUSTOM); |
| } |
| |
| mContentHeight = a.getLayoutDimension(R.styleable.ActionBar_height, 0); |
| |
| a.recycle(); |
| |
| mLogoNavItem = new ActionMenuItem(context, 0, android.R.id.home, 0, 0, mTitle); |
| |
| mUpGoerFive.setOnClickListener(mUpClickListener); |
| mUpGoerFive.setClickable(true); |
| mUpGoerFive.setFocusable(true); |
| |
| if (getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) { |
| setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES); |
| } |
| } |
| |
| @Override |
| protected void onConfigurationChanged(Configuration newConfig) { |
| super.onConfigurationChanged(newConfig); |
| |
| mTitleView = null; |
| mSubtitleView = null; |
| mTitleUpView = null; |
| if (mTitleLayout != null && mTitleLayout.getParent() == mUpGoerFive) { |
| mUpGoerFive.removeView(mTitleLayout); |
| } |
| mTitleLayout = null; |
| if ((mDisplayOptions & ActionBar.DISPLAY_SHOW_TITLE) != 0) { |
| initTitle(); |
| } |
| |
| if (mTabScrollView != null && mIncludeTabs) { |
| ViewGroup.LayoutParams lp = mTabScrollView.getLayoutParams(); |
| if (lp != null) { |
| lp.width = LayoutParams.WRAP_CONTENT; |
| lp.height = LayoutParams.MATCH_PARENT; |
| } |
| mTabScrollView.setAllowCollapse(true); |
| } |
| } |
| |
| /** |
| * Set the window callback used to invoke menu items; used for dispatching home button presses. |
| * @param cb Window callback to dispatch to |
| */ |
| public void setWindowCallback(Window.Callback cb) { |
| mWindowCallback = cb; |
| } |
| |
| @Override |
| public void onDetachedFromWindow() { |
| super.onDetachedFromWindow(); |
| removeCallbacks(mTabSelector); |
| if (mActionMenuPresenter != null) { |
| mActionMenuPresenter.hideOverflowMenu(); |
| mActionMenuPresenter.hideSubMenus(); |
| } |
| } |
| |
| @Override |
| public boolean shouldDelayChildPressedState() { |
| return false; |
| } |
| |
| public void initProgress() { |
| mProgressView = new ProgressBar(mContext, null, 0, mProgressStyle); |
| mProgressView.setId(R.id.progress_horizontal); |
| mProgressView.setMax(10000); |
| mProgressView.setVisibility(GONE); |
| addView(mProgressView); |
| } |
| |
| public void initIndeterminateProgress() { |
| mIndeterminateProgressView = new ProgressBar(mContext, null, 0, |
| mIndeterminateProgressStyle); |
| mIndeterminateProgressView.setId(R.id.progress_circular); |
| mIndeterminateProgressView.setVisibility(GONE); |
| addView(mIndeterminateProgressView); |
| } |
| |
| @Override |
| public void setSplitActionBar(boolean splitActionBar) { |
| if (mSplitActionBar != splitActionBar) { |
| if (mMenuView != null) { |
| final ViewGroup oldParent = (ViewGroup) mMenuView.getParent(); |
| if (oldParent != null) { |
| oldParent.removeView(mMenuView); |
| } |
| if (splitActionBar) { |
| if (mSplitView != null) { |
| mSplitView.addView(mMenuView); |
| } |
| mMenuView.getLayoutParams().width = LayoutParams.MATCH_PARENT; |
| } else { |
| addView(mMenuView); |
| mMenuView.getLayoutParams().width = LayoutParams.WRAP_CONTENT; |
| } |
| mMenuView.requestLayout(); |
| } |
| if (mSplitView != null) { |
| mSplitView.setVisibility(splitActionBar ? VISIBLE : GONE); |
| } |
| |
| if (mActionMenuPresenter != null) { |
| if (!splitActionBar) { |
| mActionMenuPresenter.setExpandedActionViewsExclusive( |
| getResources().getBoolean( |
| com.android.internal.R.bool.action_bar_expanded_action_views_exclusive)); |
| } else { |
| mActionMenuPresenter.setExpandedActionViewsExclusive(false); |
| // Allow full screen width in split mode. |
| mActionMenuPresenter.setWidthLimit( |
| getContext().getResources().getDisplayMetrics().widthPixels, true); |
| // No limit to the item count; use whatever will fit. |
| mActionMenuPresenter.setItemLimit(Integer.MAX_VALUE); |
| } |
| } |
| super.setSplitActionBar(splitActionBar); |
| } |
| } |
| |
| public boolean isSplitActionBar() { |
| return mSplitActionBar; |
| } |
| |
| public boolean hasEmbeddedTabs() { |
| return mIncludeTabs; |
| } |
| |
| public void setEmbeddedTabView(ScrollingTabContainerView tabs) { |
| if (mTabScrollView != null) { |
| removeView(mTabScrollView); |
| } |
| mTabScrollView = tabs; |
| mIncludeTabs = tabs != null; |
| if (mIncludeTabs && mNavigationMode == ActionBar.NAVIGATION_MODE_TABS) { |
| addView(mTabScrollView); |
| ViewGroup.LayoutParams lp = mTabScrollView.getLayoutParams(); |
| lp.width = LayoutParams.WRAP_CONTENT; |
| lp.height = LayoutParams.MATCH_PARENT; |
| tabs.setAllowCollapse(true); |
| } |
| } |
| |
| public void setCallback(OnNavigationListener callback) { |
| mCallback = callback; |
| } |
| |
| public void setMenu(Menu menu, MenuPresenter.Callback cb) { |
| if (menu == mOptionsMenu) return; |
| |
| if (mOptionsMenu != null) { |
| mOptionsMenu.removeMenuPresenter(mActionMenuPresenter); |
| mOptionsMenu.removeMenuPresenter(mExpandedMenuPresenter); |
| } |
| |
| MenuBuilder builder = (MenuBuilder) menu; |
| mOptionsMenu = builder; |
| if (mMenuView != null) { |
| final ViewGroup oldParent = (ViewGroup) mMenuView.getParent(); |
| if (oldParent != null) { |
| oldParent.removeView(mMenuView); |
| } |
| } |
| if (mActionMenuPresenter == null) { |
| mActionMenuPresenter = new ActionMenuPresenter(mContext); |
| mActionMenuPresenter.setCallback(cb); |
| mActionMenuPresenter.setId(com.android.internal.R.id.action_menu_presenter); |
| mExpandedMenuPresenter = new ExpandedActionViewMenuPresenter(); |
| } |
| |
| ActionMenuView menuView; |
| final LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, |
| LayoutParams.MATCH_PARENT); |
| if (!mSplitActionBar) { |
| mActionMenuPresenter.setExpandedActionViewsExclusive( |
| getResources().getBoolean( |
| com.android.internal.R.bool.action_bar_expanded_action_views_exclusive)); |
| configPresenters(builder); |
| menuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this); |
| final ViewGroup oldParent = (ViewGroup) menuView.getParent(); |
| if (oldParent != null && oldParent != this) { |
| oldParent.removeView(menuView); |
| } |
| addView(menuView, layoutParams); |
| } else { |
| mActionMenuPresenter.setExpandedActionViewsExclusive(false); |
| // Allow full screen width in split mode. |
| mActionMenuPresenter.setWidthLimit( |
| getContext().getResources().getDisplayMetrics().widthPixels, true); |
| // No limit to the item count; use whatever will fit. |
| mActionMenuPresenter.setItemLimit(Integer.MAX_VALUE); |
| // Span the whole width |
| layoutParams.width = LayoutParams.MATCH_PARENT; |
| configPresenters(builder); |
| menuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this); |
| if (mSplitView != null) { |
| final ViewGroup oldParent = (ViewGroup) menuView.getParent(); |
| if (oldParent != null && oldParent != mSplitView) { |
| oldParent.removeView(menuView); |
| } |
| menuView.setVisibility(getAnimatedVisibility()); |
| mSplitView.addView(menuView, layoutParams); |
| } else { |
| // We'll add this later if we missed it this time. |
| menuView.setLayoutParams(layoutParams); |
| } |
| } |
| mMenuView = menuView; |
| } |
| |
| private void configPresenters(MenuBuilder builder) { |
| if (builder != null) { |
| builder.addMenuPresenter(mActionMenuPresenter); |
| builder.addMenuPresenter(mExpandedMenuPresenter); |
| } else { |
| mActionMenuPresenter.initForMenu(mContext, null); |
| mExpandedMenuPresenter.initForMenu(mContext, null); |
| mActionMenuPresenter.updateMenuView(true); |
| mExpandedMenuPresenter.updateMenuView(true); |
| } |
| } |
| |
| public boolean hasExpandedActionView() { |
| return mExpandedMenuPresenter != null && |
| mExpandedMenuPresenter.mCurrentExpandedItem != null; |
| } |
| |
| public void collapseActionView() { |
| final MenuItemImpl item = mExpandedMenuPresenter == null ? null : |
| mExpandedMenuPresenter.mCurrentExpandedItem; |
| if (item != null) { |
| item.collapseActionView(); |
| } |
| } |
| |
| public void setCustomNavigationView(View view) { |
| final boolean showCustom = (mDisplayOptions & ActionBar.DISPLAY_SHOW_CUSTOM) != 0; |
| if (mCustomNavView != null && showCustom) { |
| removeView(mCustomNavView); |
| } |
| mCustomNavView = view; |
| if (mCustomNavView != null && showCustom) { |
| addView(mCustomNavView); |
| } |
| } |
| |
| public CharSequence getTitle() { |
| return mTitle; |
| } |
| |
| /** |
| * Set the action bar title. This will always replace or override window titles. |
| * @param title Title to set |
| * |
| * @see #setWindowTitle(CharSequence) |
| */ |
| public void setTitle(CharSequence title) { |
| mUserTitle = true; |
| setTitleImpl(title); |
| } |
| |
| /** |
| * Set the window title. A window title will always be replaced or overridden by a user title. |
| * @param title Title to set |
| * |
| * @see #setTitle(CharSequence) |
| */ |
| public void setWindowTitle(CharSequence title) { |
| if (!mUserTitle) { |
| setTitleImpl(title); |
| } |
| } |
| |
| private void setTitleImpl(CharSequence title) { |
| mTitle = title; |
| if (mTitleView != null) { |
| mTitleView.setText(title); |
| final boolean visible = mExpandedActionView == null && |
| (mDisplayOptions & ActionBar.DISPLAY_SHOW_TITLE) != 0 && |
| (!TextUtils.isEmpty(mTitle) || !TextUtils.isEmpty(mSubtitle)); |
| mTitleLayout.setVisibility(visible ? VISIBLE : GONE); |
| } |
| if (mLogoNavItem != null) { |
| mLogoNavItem.setTitle(title); |
| } |
| } |
| |
| public CharSequence getSubtitle() { |
| return mSubtitle; |
| } |
| |
| public void setSubtitle(CharSequence subtitle) { |
| mSubtitle = subtitle; |
| if (mSubtitleView != null) { |
| mSubtitleView.setText(subtitle); |
| mSubtitleView.setVisibility(subtitle != null ? VISIBLE : GONE); |
| final boolean visible = mExpandedActionView == null && |
| (mDisplayOptions & ActionBar.DISPLAY_SHOW_TITLE) != 0 && |
| (!TextUtils.isEmpty(mTitle) || !TextUtils.isEmpty(mSubtitle)); |
| mTitleLayout.setVisibility(visible ? VISIBLE : GONE); |
| } |
| } |
| |
| public void setHomeButtonEnabled(boolean enable) { |
| setHomeButtonEnabled(enable, true); |
| } |
| |
| private void setHomeButtonEnabled(boolean enable, boolean recordState) { |
| if (recordState) { |
| mWasHomeEnabled = enable; |
| } |
| |
| if (mExpandedActionView != null) { |
| // There's an action view currently showing and we want to keep the state |
| // configured for the action view at the moment. If we needed to record the |
| // new state for later we will have done so above. |
| return; |
| } |
| |
| mUpGoerFive.setEnabled(enable); |
| mUpGoerFive.setFocusable(enable); |
| // Make sure the home button has an accurate content description for accessibility. |
| if (!enable) { |
| mUpGoerFive.setContentDescription(null); |
| mUpGoerFive.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO); |
| } else { |
| mUpGoerFive.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_AUTO); |
| if ((mDisplayOptions & ActionBar.DISPLAY_HOME_AS_UP) != 0) { |
| mUpGoerFive.setContentDescription(mContext.getResources().getText( |
| R.string.action_bar_up_description)); |
| } else { |
| mUpGoerFive.setContentDescription(mContext.getResources().getText( |
| R.string.action_bar_home_description)); |
| } |
| } |
| } |
| |
| public void setDisplayOptions(int options) { |
| final int flagsChanged = mDisplayOptions == -1 ? -1 : options ^ mDisplayOptions; |
| mDisplayOptions = options; |
| |
| if ((flagsChanged & DISPLAY_RELAYOUT_MASK) != 0) { |
| final boolean showHome = (options & ActionBar.DISPLAY_SHOW_HOME) != 0; |
| final int vis = showHome && mExpandedActionView == null ? VISIBLE : GONE; |
| mHomeLayout.setVisibility(vis); |
| |
| if ((flagsChanged & ActionBar.DISPLAY_HOME_AS_UP) != 0) { |
| final boolean setUp = (options & ActionBar.DISPLAY_HOME_AS_UP) != 0; |
| mHomeLayout.setUp(setUp); |
| |
| // Showing home as up implicitly enables interaction with it. |
| // In honeycomb it was always enabled, so make this transition |
| // a bit easier for developers in the common case. |
| // (It would be silly to show it as up without responding to it.) |
| if (setUp) { |
| setHomeButtonEnabled(true); |
| } |
| } |
| |
| if ((flagsChanged & ActionBar.DISPLAY_USE_LOGO) != 0) { |
| final boolean logoVis = mLogo != null && (options & ActionBar.DISPLAY_USE_LOGO) != 0; |
| mHomeLayout.setIcon(logoVis ? mLogo : mIcon); |
| } |
| |
| if ((flagsChanged & ActionBar.DISPLAY_SHOW_TITLE) != 0) { |
| if ((options & ActionBar.DISPLAY_SHOW_TITLE) != 0) { |
| initTitle(); |
| } else { |
| mUpGoerFive.removeView(mTitleLayout); |
| } |
| } |
| |
| if (mTitleLayout != null && (flagsChanged & |
| (ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME)) != 0) { |
| final boolean homeAsUp = (mDisplayOptions & ActionBar.DISPLAY_HOME_AS_UP) != 0; |
| mTitleUpView.setVisibility(!showHome ? (homeAsUp ? VISIBLE : INVISIBLE) : GONE); |
| } |
| |
| if ((flagsChanged & ActionBar.DISPLAY_SHOW_CUSTOM) != 0 && mCustomNavView != null) { |
| if ((options & ActionBar.DISPLAY_SHOW_CUSTOM) != 0) { |
| addView(mCustomNavView); |
| } else { |
| removeView(mCustomNavView); |
| } |
| } |
| |
| if (mTitleLayout != null && |
| (flagsChanged & ActionBar.DISPLAY_TITLE_MULTIPLE_LINES) != 0) { |
| if ((options & ActionBar.DISPLAY_TITLE_MULTIPLE_LINES) != 0) { |
| mTitleView.setSingleLine(false); |
| mTitleView.setMaxLines(2); |
| } else { |
| mTitleView.setMaxLines(1); |
| mTitleView.setSingleLine(true); |
| } |
| } |
| |
| requestLayout(); |
| } else { |
| invalidate(); |
| } |
| |
| // Make sure the home button has an accurate content description for accessibility. |
| if (!mHomeLayout.isEnabled()) { |
| mHomeLayout.setContentDescription(null); |
| mHomeLayout.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO); |
| } else { |
| mHomeLayout.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_AUTO); |
| if ((options & ActionBar.DISPLAY_HOME_AS_UP) != 0) { |
| mHomeLayout.setContentDescription(mContext.getResources().getText( |
| R.string.action_bar_up_description)); |
| } else { |
| mHomeLayout.setContentDescription(mContext.getResources().getText( |
| R.string.action_bar_home_description)); |
| } |
| } |
| } |
| |
| public void setIcon(Drawable icon) { |
| mIcon = icon; |
| if (icon != null && |
| ((mDisplayOptions & ActionBar.DISPLAY_USE_LOGO) == 0 || mLogo == null)) { |
| mHomeLayout.setIcon(icon); |
| } |
| if (mExpandedActionView != null) { |
| mExpandedHomeLayout.setIcon(mIcon.getConstantState().newDrawable(getResources())); |
| } |
| } |
| |
| public void setIcon(int resId) { |
| setIcon(mContext.getResources().getDrawable(resId)); |
| } |
| |
| public void setLogo(Drawable logo) { |
| mLogo = logo; |
| if (logo != null && (mDisplayOptions & ActionBar.DISPLAY_USE_LOGO) != 0) { |
| mHomeLayout.setIcon(logo); |
| } |
| } |
| |
| public void setLogo(int resId) { |
| setLogo(mContext.getResources().getDrawable(resId)); |
| } |
| |
| public void setNavigationMode(int mode) { |
| final int oldMode = mNavigationMode; |
| if (mode != oldMode) { |
| switch (oldMode) { |
| case ActionBar.NAVIGATION_MODE_LIST: |
| if (mListNavLayout != null) { |
| removeView(mListNavLayout); |
| } |
| break; |
| case ActionBar.NAVIGATION_MODE_TABS: |
| if (mTabScrollView != null && mIncludeTabs) { |
| removeView(mTabScrollView); |
| } |
| } |
| |
| switch (mode) { |
| case ActionBar.NAVIGATION_MODE_LIST: |
| if (mSpinner == null) { |
| mSpinner = new Spinner(mContext, null, |
| com.android.internal.R.attr.actionDropDownStyle); |
| mListNavLayout = new LinearLayout(mContext, null, |
| com.android.internal.R.attr.actionBarTabBarStyle); |
| LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( |
| LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT); |
| params.gravity = Gravity.CENTER; |
| mListNavLayout.addView(mSpinner, params); |
| } |
| if (mSpinner.getAdapter() != mSpinnerAdapter) { |
| mSpinner.setAdapter(mSpinnerAdapter); |
| } |
| mSpinner.setOnItemSelectedListener(mNavItemSelectedListener); |
| addView(mListNavLayout); |
| break; |
| case ActionBar.NAVIGATION_MODE_TABS: |
| if (mTabScrollView != null && mIncludeTabs) { |
| addView(mTabScrollView); |
| } |
| break; |
| } |
| mNavigationMode = mode; |
| requestLayout(); |
| } |
| } |
| |
| public void setDropdownAdapter(SpinnerAdapter adapter) { |
| mSpinnerAdapter = adapter; |
| if (mSpinner != null) { |
| mSpinner.setAdapter(adapter); |
| } |
| } |
| |
| public SpinnerAdapter getDropdownAdapter() { |
| return mSpinnerAdapter; |
| } |
| |
| public void setDropdownSelectedPosition(int position) { |
| mSpinner.setSelection(position); |
| } |
| |
| public int getDropdownSelectedPosition() { |
| return mSpinner.getSelectedItemPosition(); |
| } |
| |
| public View getCustomNavigationView() { |
| return mCustomNavView; |
| } |
| |
| public int getNavigationMode() { |
| return mNavigationMode; |
| } |
| |
| public int getDisplayOptions() { |
| return mDisplayOptions; |
| } |
| |
| @Override |
| protected ViewGroup.LayoutParams generateDefaultLayoutParams() { |
| // Used by custom nav views if they don't supply layout params. Everything else |
| // added to an ActionBarView should have them already. |
| return new ActionBar.LayoutParams(DEFAULT_CUSTOM_GRAVITY); |
| } |
| |
| @Override |
| protected void onFinishInflate() { |
| super.onFinishInflate(); |
| |
| mUpGoerFive.addView(mHomeLayout, 0); |
| addView(mUpGoerFive); |
| |
| if (mCustomNavView != null && (mDisplayOptions & ActionBar.DISPLAY_SHOW_CUSTOM) != 0) { |
| final ViewParent parent = mCustomNavView.getParent(); |
| if (parent != this) { |
| if (parent instanceof ViewGroup) { |
| ((ViewGroup) parent).removeView(mCustomNavView); |
| } |
| addView(mCustomNavView); |
| } |
| } |
| } |
| |
| private void initTitle() { |
| if (mTitleLayout == null) { |
| LayoutInflater inflater = LayoutInflater.from(getContext()); |
| mTitleLayout = (LinearLayout) inflater.inflate(R.layout.action_bar_title_item, |
| this, false); |
| mTitleView = (TextView) mTitleLayout.findViewById(R.id.action_bar_title); |
| mSubtitleView = (TextView) mTitleLayout.findViewById(R.id.action_bar_subtitle); |
| mTitleUpView = (View) mTitleLayout.findViewById(R.id.up); |
| |
| if (mTitleStyleRes != 0) { |
| mTitleView.setTextAppearance(mContext, mTitleStyleRes); |
| } |
| if (mTitle != null) { |
| mTitleView.setText(mTitle); |
| } |
| |
| if (mSubtitleStyleRes != 0) { |
| mSubtitleView.setTextAppearance(mContext, mSubtitleStyleRes); |
| } |
| if (mSubtitle != null) { |
| mSubtitleView.setText(mSubtitle); |
| mSubtitleView.setVisibility(VISIBLE); |
| } |
| |
| final boolean homeAsUp = (mDisplayOptions & ActionBar.DISPLAY_HOME_AS_UP) != 0; |
| final boolean showHome = (mDisplayOptions & ActionBar.DISPLAY_SHOW_HOME) != 0; |
| final boolean showTitleUp = !showHome; |
| mTitleUpView.setVisibility(showTitleUp ? (homeAsUp ? VISIBLE : INVISIBLE) : GONE); |
| } |
| |
| mUpGoerFive.addView(mTitleLayout); |
| if (mExpandedActionView != null || |
| (TextUtils.isEmpty(mTitle) && TextUtils.isEmpty(mSubtitle))) { |
| // Don't show while in expanded mode or with empty text |
| mTitleLayout.setVisibility(GONE); |
| } |
| } |
| |
| public void setContextView(ActionBarContextView view) { |
| mContextView = view; |
| } |
| |
| public void setCollapsable(boolean collapsable) { |
| mIsCollapsable = collapsable; |
| } |
| |
| public boolean isCollapsed() { |
| return mIsCollapsed; |
| } |
| |
| /** |
| * @return True if any characters in the title were truncated |
| */ |
| public boolean isTitleTruncated() { |
| if (mTitleView == null) { |
| return false; |
| } |
| |
| final Layout titleLayout = mTitleView.getLayout(); |
| if (titleLayout == null) { |
| return false; |
| } |
| |
| final int lineCount = titleLayout.getLineCount(); |
| for (int i = 0; i < lineCount; i++) { |
| if (titleLayout.getEllipsisCount(i) > 0) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| @Override |
| protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { |
| final int childCount = getChildCount(); |
| if (mIsCollapsable) { |
| int visibleChildren = 0; |
| for (int i = 0; i < childCount; i++) { |
| final View child = getChildAt(i); |
| if (child.getVisibility() != GONE && |
| !(child == mMenuView && mMenuView.getChildCount() == 0) && |
| child != mUpGoerFive) { |
| visibleChildren++; |
| } |
| } |
| |
| final int upChildCount = mUpGoerFive.getChildCount(); |
| for (int i = 0; i < upChildCount; i++) { |
| final View child = mUpGoerFive.getChildAt(i); |
| if (child.getVisibility() != GONE) { |
| visibleChildren++; |
| } |
| } |
| |
| if (visibleChildren == 0) { |
| // No size for an empty action bar when collapsable. |
| setMeasuredDimension(0, 0); |
| mIsCollapsed = true; |
| return; |
| } |
| } |
| mIsCollapsed = false; |
| |
| int widthMode = MeasureSpec.getMode(widthMeasureSpec); |
| if (widthMode != MeasureSpec.EXACTLY) { |
| throw new IllegalStateException(getClass().getSimpleName() + " can only be used " + |
| "with android:layout_width=\"match_parent\" (or fill_parent)"); |
| } |
| |
| int heightMode = MeasureSpec.getMode(heightMeasureSpec); |
| if (heightMode != MeasureSpec.AT_MOST) { |
| throw new IllegalStateException(getClass().getSimpleName() + " can only be used " + |
| "with android:layout_height=\"wrap_content\""); |
| } |
| |
| int contentWidth = MeasureSpec.getSize(widthMeasureSpec); |
| |
| int maxHeight = mContentHeight >= 0 ? |
| mContentHeight : MeasureSpec.getSize(heightMeasureSpec); |
| |
| final int verticalPadding = getPaddingTop() + getPaddingBottom(); |
| final int paddingLeft = getPaddingLeft(); |
| final int paddingRight = getPaddingRight(); |
| final int height = maxHeight - verticalPadding; |
| final int childSpecHeight = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST); |
| final int exactHeightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY); |
| |
| int availableWidth = contentWidth - paddingLeft - paddingRight; |
| int leftOfCenter = availableWidth / 2; |
| int rightOfCenter = leftOfCenter; |
| |
| HomeView homeLayout = mExpandedActionView != null ? mExpandedHomeLayout : mHomeLayout; |
| |
| int homeWidth = 0; |
| if (homeLayout.getVisibility() != GONE && homeLayout.getParent() == mUpGoerFive) { |
| final ViewGroup.LayoutParams lp = homeLayout.getLayoutParams(); |
| int homeWidthSpec; |
| if (lp.width < 0) { |
| homeWidthSpec = MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST); |
| } else { |
| homeWidthSpec = MeasureSpec.makeMeasureSpec(lp.width, MeasureSpec.EXACTLY); |
| } |
| |
| /* |
| * This is a little weird. |
| * We're only measuring the *home* affordance within the Up container here |
| * on purpose, because we want to give the available space to all other views before |
| * the title text. We'll remeasure the whole up container again later. |
| */ |
| homeLayout.measure(homeWidthSpec, exactHeightSpec); |
| homeWidth = homeLayout.getMeasuredWidth(); |
| final int homeOffsetWidth = homeWidth + homeLayout.getStartOffset(); |
| availableWidth = Math.max(0, availableWidth - homeOffsetWidth); |
| leftOfCenter = Math.max(0, availableWidth - homeOffsetWidth); |
| } |
| |
| if (mMenuView != null && mMenuView.getParent() == this) { |
| availableWidth = measureChildView(mMenuView, availableWidth, exactHeightSpec, 0); |
| rightOfCenter = Math.max(0, rightOfCenter - mMenuView.getMeasuredWidth()); |
| } |
| |
| if (mIndeterminateProgressView != null && |
| mIndeterminateProgressView.getVisibility() != GONE) { |
| availableWidth = measureChildView(mIndeterminateProgressView, availableWidth, |
| childSpecHeight, 0); |
| rightOfCenter = Math.max(0, |
| rightOfCenter - mIndeterminateProgressView.getMeasuredWidth()); |
| } |
| |
| final boolean showTitle = mTitleLayout != null && mTitleLayout.getVisibility() != GONE && |
| (mDisplayOptions & ActionBar.DISPLAY_SHOW_TITLE) != 0; |
| |
| if (mExpandedActionView == null) { |
| switch (mNavigationMode) { |
| case ActionBar.NAVIGATION_MODE_LIST: |
| if (mListNavLayout != null) { |
| final int itemPaddingSize = showTitle ? mItemPadding * 2 : mItemPadding; |
| availableWidth = Math.max(0, availableWidth - itemPaddingSize); |
| leftOfCenter = Math.max(0, leftOfCenter - itemPaddingSize); |
| mListNavLayout.measure( |
| MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST), |
| MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)); |
| final int listNavWidth = mListNavLayout.getMeasuredWidth(); |
| availableWidth = Math.max(0, availableWidth - listNavWidth); |
| leftOfCenter = Math.max(0, leftOfCenter - listNavWidth); |
| } |
| break; |
| case ActionBar.NAVIGATION_MODE_TABS: |
| if (mTabScrollView != null) { |
| final int itemPaddingSize = showTitle ? mItemPadding * 2 : mItemPadding; |
| availableWidth = Math.max(0, availableWidth - itemPaddingSize); |
| leftOfCenter = Math.max(0, leftOfCenter - itemPaddingSize); |
| mTabScrollView.measure( |
| MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST), |
| MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)); |
| final int tabWidth = mTabScrollView.getMeasuredWidth(); |
| availableWidth = Math.max(0, availableWidth - tabWidth); |
| leftOfCenter = Math.max(0, leftOfCenter - tabWidth); |
| } |
| break; |
| } |
| } |
| |
| View customView = null; |
| if (mExpandedActionView != null) { |
| customView = mExpandedActionView; |
| } else if ((mDisplayOptions & ActionBar.DISPLAY_SHOW_CUSTOM) != 0 && |
| mCustomNavView != null) { |
| customView = mCustomNavView; |
| } |
| |
| if (customView != null) { |
| final ViewGroup.LayoutParams lp = generateLayoutParams(customView.getLayoutParams()); |
| final ActionBar.LayoutParams ablp = lp instanceof ActionBar.LayoutParams ? |
| (ActionBar.LayoutParams) lp : null; |
| |
| int horizontalMargin = 0; |
| int verticalMargin = 0; |
| if (ablp != null) { |
| horizontalMargin = ablp.leftMargin + ablp.rightMargin; |
| verticalMargin = ablp.topMargin + ablp.bottomMargin; |
| } |
| |
| // If the action bar is wrapping to its content height, don't allow a custom |
| // view to MATCH_PARENT. |
| int customNavHeightMode; |
| if (mContentHeight <= 0) { |
| customNavHeightMode = MeasureSpec.AT_MOST; |
| } else { |
| customNavHeightMode = lp.height != LayoutParams.WRAP_CONTENT ? |
| MeasureSpec.EXACTLY : MeasureSpec.AT_MOST; |
| } |
| final int customNavHeight = Math.max(0, |
| (lp.height >= 0 ? Math.min(lp.height, height) : height) - verticalMargin); |
| |
| final int customNavWidthMode = lp.width != LayoutParams.WRAP_CONTENT ? |
| MeasureSpec.EXACTLY : MeasureSpec.AT_MOST; |
| int customNavWidth = Math.max(0, |
| (lp.width >= 0 ? Math.min(lp.width, availableWidth) : availableWidth) |
| - horizontalMargin); |
| final int hgrav = (ablp != null ? ablp.gravity : DEFAULT_CUSTOM_GRAVITY) & |
| Gravity.HORIZONTAL_GRAVITY_MASK; |
| |
| // Centering a custom view is treated specially; we try to center within the whole |
| // action bar rather than in the available space. |
| if (hgrav == Gravity.CENTER_HORIZONTAL && lp.width == LayoutParams.MATCH_PARENT) { |
| customNavWidth = Math.min(leftOfCenter, rightOfCenter) * 2; |
| } |
| |
| customView.measure( |
| MeasureSpec.makeMeasureSpec(customNavWidth, customNavWidthMode), |
| MeasureSpec.makeMeasureSpec(customNavHeight, customNavHeightMode)); |
| availableWidth -= horizontalMargin + customView.getMeasuredWidth(); |
| } |
| |
| /* |
| * Measure the whole up container now, allowing for the full home+title sections. |
| * (This will re-measure the home view.) |
| */ |
| availableWidth = measureChildView(mUpGoerFive, availableWidth + homeWidth, |
| MeasureSpec.makeMeasureSpec(mContentHeight, MeasureSpec.EXACTLY), 0); |
| if (mTitleLayout != null) { |
| leftOfCenter = Math.max(0, leftOfCenter - mTitleLayout.getMeasuredWidth()); |
| } |
| |
| if (mContentHeight <= 0) { |
| int measuredHeight = 0; |
| for (int i = 0; i < childCount; i++) { |
| View v = getChildAt(i); |
| int paddedViewHeight = v.getMeasuredHeight() + verticalPadding; |
| if (paddedViewHeight > measuredHeight) { |
| measuredHeight = paddedViewHeight; |
| } |
| } |
| setMeasuredDimension(contentWidth, measuredHeight); |
| } else { |
| setMeasuredDimension(contentWidth, maxHeight); |
| } |
| |
| if (mContextView != null) { |
| mContextView.setContentHeight(getMeasuredHeight()); |
| } |
| |
| if (mProgressView != null && mProgressView.getVisibility() != GONE) { |
| mProgressView.measure(MeasureSpec.makeMeasureSpec( |
| contentWidth - mProgressBarPadding * 2, MeasureSpec.EXACTLY), |
| MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.AT_MOST)); |
| } |
| } |
| |
| @Override |
| protected void onLayout(boolean changed, int l, int t, int r, int b) { |
| final int contentHeight = b - t - getPaddingTop() - getPaddingBottom(); |
| |
| if (contentHeight <= 0) { |
| // Nothing to do if we can't see anything. |
| return; |
| } |
| |
| final boolean isLayoutRtl = isLayoutRtl(); |
| final int direction = isLayoutRtl ? +1 : -1; |
| int menuStart = isLayoutRtl ? getPaddingLeft() : r - l - getPaddingRight(); |
| // In LTR mode, we start from left padding and go to the right; in RTL mode, we start |
| // from the padding right and go to the left (in reverse way) |
| int x = isLayoutRtl ? r - l - getPaddingRight() : getPaddingLeft(); |
| final int y = getPaddingTop(); |
| |
| HomeView homeLayout = mExpandedActionView != null ? mExpandedHomeLayout : mHomeLayout; |
| final int startOffset = homeLayout.getVisibility() != GONE && |
| homeLayout.getParent() == mUpGoerFive ? homeLayout.getStartOffset() : 0; |
| |
| // Position the up container based on where the edge of the home layout should go. |
| x += positionChild(mUpGoerFive, |
| next(x, startOffset, isLayoutRtl), y, contentHeight, isLayoutRtl); |
| x = next(x, startOffset, isLayoutRtl); |
| |
| if (mExpandedActionView == null) { |
| final boolean showTitle = mTitleLayout != null && mTitleLayout.getVisibility() != GONE && |
| (mDisplayOptions & ActionBar.DISPLAY_SHOW_TITLE) != 0; |
| |
| switch (mNavigationMode) { |
| case ActionBar.NAVIGATION_MODE_STANDARD: |
| break; |
| case ActionBar.NAVIGATION_MODE_LIST: |
| if (mListNavLayout != null) { |
| if (showTitle) { |
| x = next(x, mItemPadding, isLayoutRtl); |
| } |
| x += positionChild(mListNavLayout, x, y, contentHeight, isLayoutRtl); |
| x = next(x, mItemPadding, isLayoutRtl); |
| } |
| break; |
| case ActionBar.NAVIGATION_MODE_TABS: |
| if (mTabScrollView != null) { |
| if (showTitle) x = next(x, mItemPadding, isLayoutRtl); |
| x += positionChild(mTabScrollView, x, y, contentHeight, isLayoutRtl); |
| x = next(x, mItemPadding, isLayoutRtl); |
| } |
| break; |
| } |
| } |
| |
| if (mMenuView != null && mMenuView.getParent() == this) { |
| positionChild(mMenuView, menuStart, y, contentHeight, !isLayoutRtl); |
| menuStart += direction * mMenuView.getMeasuredWidth(); |
| } |
| |
| if (mIndeterminateProgressView != null && |
| mIndeterminateProgressView.getVisibility() != GONE) { |
| positionChild(mIndeterminateProgressView, menuStart, y, contentHeight, !isLayoutRtl); |
| menuStart += direction * mIndeterminateProgressView.getMeasuredWidth(); |
| } |
| |
| View customView = null; |
| if (mExpandedActionView != null) { |
| customView = mExpandedActionView; |
| } else if ((mDisplayOptions & ActionBar.DISPLAY_SHOW_CUSTOM) != 0 && |
| mCustomNavView != null) { |
| customView = mCustomNavView; |
| } |
| if (customView != null) { |
| final int layoutDirection = getLayoutDirection(); |
| ViewGroup.LayoutParams lp = customView.getLayoutParams(); |
| final ActionBar.LayoutParams ablp = lp instanceof ActionBar.LayoutParams ? |
| (ActionBar.LayoutParams) lp : null; |
| final int gravity = ablp != null ? ablp.gravity : DEFAULT_CUSTOM_GRAVITY; |
| final int navWidth = customView.getMeasuredWidth(); |
| |
| int topMargin = 0; |
| int bottomMargin = 0; |
| if (ablp != null) { |
| x = next(x, ablp.getMarginStart(), isLayoutRtl); |
| menuStart += direction * ablp.getMarginEnd(); |
| topMargin = ablp.topMargin; |
| bottomMargin = ablp.bottomMargin; |
| } |
| |
| int hgravity = gravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK; |
| // See if we actually have room to truly center; if not push against left or right. |
| if (hgravity == Gravity.CENTER_HORIZONTAL) { |
| final int centeredLeft = ((mRight - mLeft) - navWidth) / 2; |
| if (isLayoutRtl) { |
| final int centeredStart = centeredLeft + navWidth; |
| final int centeredEnd = centeredLeft; |
| if (centeredStart > x) { |
| hgravity = Gravity.RIGHT; |
| } else if (centeredEnd < menuStart) { |
| hgravity = Gravity.LEFT; |
| } |
| } else { |
| final int centeredStart = centeredLeft; |
| final int centeredEnd = centeredLeft + navWidth; |
| if (centeredStart < x) { |
| hgravity = Gravity.LEFT; |
| } else if (centeredEnd > menuStart) { |
| hgravity = Gravity.RIGHT; |
| } |
| } |
| } else if (gravity == Gravity.NO_GRAVITY) { |
| hgravity = Gravity.START; |
| } |
| |
| int xpos = 0; |
| switch (Gravity.getAbsoluteGravity(hgravity, layoutDirection)) { |
| case Gravity.CENTER_HORIZONTAL: |
| xpos = ((mRight - mLeft) - navWidth) / 2; |
| break; |
| case Gravity.LEFT: |
| xpos = isLayoutRtl ? menuStart : x; |
| break; |
| case Gravity.RIGHT: |
| xpos = isLayoutRtl ? x - navWidth : menuStart - navWidth; |
| break; |
| } |
| |
| int vgravity = gravity & Gravity.VERTICAL_GRAVITY_MASK; |
| |
| if (gravity == Gravity.NO_GRAVITY) { |
| vgravity = Gravity.CENTER_VERTICAL; |
| } |
| |
| int ypos = 0; |
| switch (vgravity) { |
| case Gravity.CENTER_VERTICAL: |
| final int paddedTop = getPaddingTop(); |
| final int paddedBottom = mBottom - mTop - getPaddingBottom(); |
| ypos = ((paddedBottom - paddedTop) - customView.getMeasuredHeight()) / 2; |
| break; |
| case Gravity.TOP: |
| ypos = getPaddingTop() + topMargin; |
| break; |
| case Gravity.BOTTOM: |
| ypos = getHeight() - getPaddingBottom() - customView.getMeasuredHeight() |
| - bottomMargin; |
| break; |
| } |
| final int customWidth = customView.getMeasuredWidth(); |
| customView.layout(xpos, ypos, xpos + customWidth, |
| ypos + customView.getMeasuredHeight()); |
| x = next(x, customWidth, isLayoutRtl); |
| } |
| |
| if (mProgressView != null) { |
| mProgressView.bringToFront(); |
| final int halfProgressHeight = mProgressView.getMeasuredHeight() / 2; |
| mProgressView.layout(mProgressBarPadding, -halfProgressHeight, |
| mProgressBarPadding + mProgressView.getMeasuredWidth(), halfProgressHeight); |
| } |
| } |
| |
| @Override |
| public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) { |
| return new ActionBar.LayoutParams(getContext(), attrs); |
| } |
| |
| @Override |
| public ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) { |
| if (lp == null) { |
| lp = generateDefaultLayoutParams(); |
| } |
| return lp; |
| } |
| |
| @Override |
| public Parcelable onSaveInstanceState() { |
| Parcelable superState = super.onSaveInstanceState(); |
| SavedState state = new SavedState(superState); |
| |
| if (mExpandedMenuPresenter != null && mExpandedMenuPresenter.mCurrentExpandedItem != null) { |
| state.expandedMenuItemId = mExpandedMenuPresenter.mCurrentExpandedItem.getItemId(); |
| } |
| |
| state.isOverflowOpen = isOverflowMenuShowing(); |
| |
| return state; |
| } |
| |
| @Override |
| public void onRestoreInstanceState(Parcelable p) { |
| SavedState state = (SavedState) p; |
| |
| super.onRestoreInstanceState(state.getSuperState()); |
| |
| if (state.expandedMenuItemId != 0 && |
| mExpandedMenuPresenter != null && mOptionsMenu != null) { |
| final MenuItem item = mOptionsMenu.findItem(state.expandedMenuItemId); |
| if (item != null) { |
| item.expandActionView(); |
| } |
| } |
| |
| if (state.isOverflowOpen) { |
| postShowOverflowMenu(); |
| } |
| } |
| |
| static class SavedState extends BaseSavedState { |
| int expandedMenuItemId; |
| boolean isOverflowOpen; |
| |
| SavedState(Parcelable superState) { |
| super(superState); |
| } |
| |
| private SavedState(Parcel in) { |
| super(in); |
| expandedMenuItemId = in.readInt(); |
| isOverflowOpen = in.readInt() != 0; |
| } |
| |
| @Override |
| public void writeToParcel(Parcel out, int flags) { |
| super.writeToParcel(out, flags); |
| out.writeInt(expandedMenuItemId); |
| out.writeInt(isOverflowOpen ? 1 : 0); |
| } |
| |
| public static final Parcelable.Creator<SavedState> CREATOR = |
| new Parcelable.Creator<SavedState>() { |
| public SavedState createFromParcel(Parcel in) { |
| return new SavedState(in); |
| } |
| |
| public SavedState[] newArray(int size) { |
| return new SavedState[size]; |
| } |
| }; |
| } |
| |
| private static class HomeView extends FrameLayout { |
| private View mUpView; |
| private ImageView mIconView; |
| private int mUpWidth; |
| |
| private static final long DEFAULT_TRANSITION_DURATION = 150; |
| |
| public HomeView(Context context) { |
| this(context, null); |
| } |
| |
| public HomeView(Context context, AttributeSet attrs) { |
| super(context, attrs); |
| LayoutTransition t = getLayoutTransition(); |
| if (t != null) { |
| // Set a lower duration than the default |
| t.setDuration(DEFAULT_TRANSITION_DURATION); |
| } |
| } |
| |
| public void setUp(boolean isUp) { |
| mUpView.setVisibility(isUp ? VISIBLE : GONE); |
| } |
| |
| public void setIcon(Drawable icon) { |
| mIconView.setImageDrawable(icon); |
| } |
| |
| @Override |
| public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { |
| onPopulateAccessibilityEvent(event); |
| return true; |
| } |
| |
| @Override |
| public void onPopulateAccessibilityEvent(AccessibilityEvent event) { |
| super.onPopulateAccessibilityEvent(event); |
| final CharSequence cdesc = getContentDescription(); |
| if (!TextUtils.isEmpty(cdesc)) { |
| event.getText().add(cdesc); |
| } |
| } |
| |
| @Override |
| public boolean dispatchHoverEvent(MotionEvent event) { |
| // Don't allow children to hover; we want this to be treated as a single component. |
| return onHoverEvent(event); |
| } |
| |
| @Override |
| protected void onFinishInflate() { |
| mUpView = findViewById(com.android.internal.R.id.up); |
| mIconView = (ImageView) findViewById(com.android.internal.R.id.home); |
| } |
| |
| public int getStartOffset() { |
| return mUpView.getVisibility() == GONE ? mUpWidth : 0; |
| } |
| |
| @Override |
| protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { |
| measureChildWithMargins(mUpView, widthMeasureSpec, 0, heightMeasureSpec, 0); |
| final LayoutParams upLp = (LayoutParams) mUpView.getLayoutParams(); |
| mUpWidth = upLp.leftMargin + mUpView.getMeasuredWidth() + upLp.rightMargin; |
| int width = mUpView.getVisibility() == GONE ? 0 : mUpWidth; |
| int height = upLp.topMargin + mUpView.getMeasuredHeight() + upLp.bottomMargin; |
| measureChildWithMargins(mIconView, widthMeasureSpec, width, heightMeasureSpec, 0); |
| final LayoutParams iconLp = (LayoutParams) mIconView.getLayoutParams(); |
| width += iconLp.leftMargin + mIconView.getMeasuredWidth() + iconLp.rightMargin; |
| height = Math.max(height, |
| iconLp.topMargin + mIconView.getMeasuredHeight() + iconLp.bottomMargin); |
| |
| final int widthMode = MeasureSpec.getMode(widthMeasureSpec); |
| final int heightMode = MeasureSpec.getMode(heightMeasureSpec); |
| final int widthSize = MeasureSpec.getSize(widthMeasureSpec); |
| final int heightSize = MeasureSpec.getSize(heightMeasureSpec); |
| |
| switch (widthMode) { |
| case MeasureSpec.AT_MOST: |
| width = Math.min(width, widthSize); |
| break; |
| case MeasureSpec.EXACTLY: |
| width = widthSize; |
| break; |
| case MeasureSpec.UNSPECIFIED: |
| default: |
| break; |
| } |
| switch (heightMode) { |
| case MeasureSpec.AT_MOST: |
| height = Math.min(height, heightSize); |
| break; |
| case MeasureSpec.EXACTLY: |
| height = heightSize; |
| break; |
| case MeasureSpec.UNSPECIFIED: |
| default: |
| break; |
| } |
| setMeasuredDimension(width, height); |
| } |
| |
| @Override |
| protected void onLayout(boolean changed, int l, int t, int r, int b) { |
| final int vCenter = (b - t) / 2; |
| final boolean isLayoutRtl = isLayoutRtl(); |
| final int width = getWidth(); |
| int upOffset = 0; |
| if (mUpView.getVisibility() != GONE) { |
| final LayoutParams upLp = (LayoutParams) mUpView.getLayoutParams(); |
| final int upHeight = mUpView.getMeasuredHeight(); |
| final int upWidth = mUpView.getMeasuredWidth(); |
| upOffset = upLp.leftMargin + upWidth + upLp.rightMargin; |
| final int upTop = vCenter - upHeight / 2; |
| final int upBottom = upTop + upHeight; |
| final int upRight; |
| final int upLeft; |
| if (isLayoutRtl) { |
| upRight = width; |
| upLeft = upRight - upWidth; |
| r -= upOffset; |
| } else { |
| upRight = upWidth; |
| upLeft = 0; |
| l += upOffset; |
| } |
| mUpView.layout(upLeft, upTop, upRight, upBottom); |
| } |
| |
| final LayoutParams iconLp = (LayoutParams) mIconView.getLayoutParams(); |
| final int iconHeight = mIconView.getMeasuredHeight(); |
| final int iconWidth = mIconView.getMeasuredWidth(); |
| final int hCenter = (r - l) / 2; |
| final int iconTop = Math.max(iconLp.topMargin, vCenter - iconHeight / 2); |
| final int iconBottom = iconTop + iconHeight; |
| final int iconLeft; |
| final int iconRight; |
| int marginStart = iconLp.getMarginStart(); |
| final int delta = Math.max(marginStart, hCenter - iconWidth / 2); |
| if (isLayoutRtl) { |
| iconRight = width - upOffset - delta; |
| iconLeft = iconRight - iconWidth; |
| } else { |
| iconLeft = upOffset + delta; |
| iconRight = iconLeft + iconWidth; |
| } |
| mIconView.layout(iconLeft, iconTop, iconRight, iconBottom); |
| } |
| } |
| |
| private class ExpandedActionViewMenuPresenter implements MenuPresenter { |
| MenuBuilder mMenu; |
| MenuItemImpl mCurrentExpandedItem; |
| |
| @Override |
| public void initForMenu(Context context, MenuBuilder menu) { |
| // Clear the expanded action view when menus change. |
| if (mMenu != null && mCurrentExpandedItem != null) { |
| mMenu.collapseItemActionView(mCurrentExpandedItem); |
| } |
| mMenu = menu; |
| } |
| |
| @Override |
| public MenuView getMenuView(ViewGroup root) { |
| return null; |
| } |
| |
| @Override |
| public void updateMenuView(boolean cleared) { |
| // Make sure the expanded item we have is still there. |
| if (mCurrentExpandedItem != null) { |
| boolean found = false; |
| |
| if (mMenu != null) { |
| final int count = mMenu.size(); |
| for (int i = 0; i < count; i++) { |
| final MenuItem item = mMenu.getItem(i); |
| if (item == mCurrentExpandedItem) { |
| found = true; |
| break; |
| } |
| } |
| } |
| |
| if (!found) { |
| // The item we had expanded disappeared. Collapse. |
| collapseItemActionView(mMenu, mCurrentExpandedItem); |
| } |
| } |
| } |
| |
| @Override |
| public void setCallback(Callback cb) { |
| } |
| |
| @Override |
| public boolean onSubMenuSelected(SubMenuBuilder subMenu) { |
| return false; |
| } |
| |
| @Override |
| public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) { |
| } |
| |
| @Override |
| public boolean flagActionItems() { |
| return false; |
| } |
| |
| @Override |
| public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item) { |
| mExpandedActionView = item.getActionView(); |
| mExpandedHomeLayout.setIcon(mIcon.getConstantState().newDrawable(getResources())); |
| mCurrentExpandedItem = item; |
| if (mExpandedActionView.getParent() != ActionBarView.this) { |
| addView(mExpandedActionView); |
| } |
| if (mExpandedHomeLayout.getParent() != mUpGoerFive) { |
| mUpGoerFive.addView(mExpandedHomeLayout); |
| } |
| mHomeLayout.setVisibility(GONE); |
| if (mTitleLayout != null) mTitleLayout.setVisibility(GONE); |
| if (mTabScrollView != null) mTabScrollView.setVisibility(GONE); |
| if (mSpinner != null) mSpinner.setVisibility(GONE); |
| if (mCustomNavView != null) mCustomNavView.setVisibility(GONE); |
| setHomeButtonEnabled(false, false); |
| requestLayout(); |
| item.setActionViewExpanded(true); |
| |
| if (mExpandedActionView instanceof CollapsibleActionView) { |
| ((CollapsibleActionView) mExpandedActionView).onActionViewExpanded(); |
| } |
| |
| return true; |
| } |
| |
| @Override |
| public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item) { |
| // Do this before detaching the actionview from the hierarchy, in case |
| // it needs to dismiss the soft keyboard, etc. |
| if (mExpandedActionView instanceof CollapsibleActionView) { |
| ((CollapsibleActionView) mExpandedActionView).onActionViewCollapsed(); |
| } |
| |
| removeView(mExpandedActionView); |
| mUpGoerFive.removeView(mExpandedHomeLayout); |
| mExpandedActionView = null; |
| if ((mDisplayOptions & ActionBar.DISPLAY_SHOW_HOME) != 0) { |
| mHomeLayout.setVisibility(VISIBLE); |
| } |
| if ((mDisplayOptions & ActionBar.DISPLAY_SHOW_TITLE) != 0) { |
| if (mTitleLayout == null) { |
| initTitle(); |
| } else { |
| mTitleLayout.setVisibility(VISIBLE); |
| } |
| } |
| if (mTabScrollView != null && mNavigationMode == ActionBar.NAVIGATION_MODE_TABS) { |
| mTabScrollView.setVisibility(VISIBLE); |
| } |
| if (mSpinner != null && mNavigationMode == ActionBar.NAVIGATION_MODE_LIST) { |
| mSpinner.setVisibility(VISIBLE); |
| } |
| if (mCustomNavView != null && (mDisplayOptions & ActionBar.DISPLAY_SHOW_CUSTOM) != 0) { |
| mCustomNavView.setVisibility(VISIBLE); |
| } |
| mExpandedHomeLayout.setIcon(null); |
| mCurrentExpandedItem = null; |
| setHomeButtonEnabled(mWasHomeEnabled); // Set by expandItemActionView above |
| requestLayout(); |
| item.setActionViewExpanded(false); |
| |
| return true; |
| } |
| |
| @Override |
| public int getId() { |
| return 0; |
| } |
| |
| @Override |
| public Parcelable onSaveInstanceState() { |
| return null; |
| } |
| |
| @Override |
| public void onRestoreInstanceState(Parcelable state) { |
| } |
| } |
| } |