mirror of https://github.com/tasks/tasks
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1549 lines
60 KiB
Java
1549 lines
60 KiB
Java
/*
|
|
* 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.actionbarsherlock.internal.widget;
|
|
|
|
import org.xmlpull.v1.XmlPullParser;
|
|
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.AssetManager;
|
|
import android.content.res.Configuration;
|
|
import android.content.res.TypedArray;
|
|
import android.content.res.XmlResourceParser;
|
|
import android.graphics.drawable.Drawable;
|
|
import android.os.Build;
|
|
import android.os.Parcel;
|
|
import android.os.Parcelable;
|
|
import android.text.TextUtils;
|
|
import android.util.AttributeSet;
|
|
import android.util.Log;
|
|
import android.view.Gravity;
|
|
import android.view.LayoutInflater;
|
|
import android.view.MotionEvent;
|
|
import android.view.View;
|
|
import android.view.ViewGroup;
|
|
import android.view.ViewParent;
|
|
import android.view.accessibility.AccessibilityEvent;
|
|
import android.widget.FrameLayout;
|
|
import android.widget.ImageView;
|
|
import android.widget.LinearLayout;
|
|
import android.widget.SpinnerAdapter;
|
|
import android.widget.TextView;
|
|
|
|
import com.actionbarsherlock.R;
|
|
import com.actionbarsherlock.app.ActionBar;
|
|
import com.actionbarsherlock.app.ActionBar.OnNavigationListener;
|
|
import com.actionbarsherlock.internal.ActionBarSherlockCompat;
|
|
import com.actionbarsherlock.internal.view.menu.ActionMenuItem;
|
|
import com.actionbarsherlock.internal.view.menu.ActionMenuPresenter;
|
|
import com.actionbarsherlock.internal.view.menu.ActionMenuView;
|
|
import com.actionbarsherlock.internal.view.menu.MenuBuilder;
|
|
import com.actionbarsherlock.internal.view.menu.MenuItemImpl;
|
|
import com.actionbarsherlock.internal.view.menu.MenuPresenter;
|
|
import com.actionbarsherlock.internal.view.menu.MenuView;
|
|
import com.actionbarsherlock.internal.view.menu.SubMenuBuilder;
|
|
import com.actionbarsherlock.view.CollapsibleActionView;
|
|
import com.actionbarsherlock.view.Menu;
|
|
import com.actionbarsherlock.view.MenuItem;
|
|
import com.actionbarsherlock.view.Window;
|
|
|
|
import static com.actionbarsherlock.internal.ResourcesCompat.getResources_getBoolean;
|
|
|
|
/**
|
|
* @hide
|
|
*/
|
|
public class ActionBarView extends AbsActionBarView {
|
|
private static final String TAG = "ActionBarView";
|
|
private static final boolean DEBUG = false;
|
|
|
|
/**
|
|
* 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;
|
|
|
|
private static final int DEFAULT_CUSTOM_GRAVITY = Gravity.LEFT | 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 IcsSpinner mSpinner;
|
|
private IcsLinearLayout mListNavLayout;
|
|
private ScrollingTabContainerView mTabScrollView;
|
|
private View mCustomNavView;
|
|
private IcsProgressBar mProgressView;
|
|
private IcsProgressBar 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 MenuBuilder mOptionsMenu;
|
|
|
|
private ActionBarContextView mContextView;
|
|
|
|
private ActionMenuItem mLogoNavItem;
|
|
|
|
private SpinnerAdapter mSpinnerAdapter;
|
|
private OnNavigationListener mCallback;
|
|
|
|
//UNUSED private Runnable mTabSelector;
|
|
|
|
private ExpandedActionViewMenuPresenter mExpandedMenuPresenter;
|
|
View mExpandedActionView;
|
|
|
|
Window.Callback mWindowCallback;
|
|
|
|
@SuppressWarnings("rawtypes")
|
|
private final IcsAdapterView.OnItemSelectedListener mNavItemSelectedListener =
|
|
new IcsAdapterView.OnItemSelectedListener() {
|
|
public void onItemSelected(IcsAdapterView parent, View view, int position, long id) {
|
|
if (mCallback != null) {
|
|
mCallback.onNavigationItemSelected(position, id);
|
|
}
|
|
}
|
|
public void onNothingSelected(IcsAdapterView 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.SherlockActionBar,
|
|
R.attr.actionBarStyle, 0);
|
|
|
|
ApplicationInfo appInfo = context.getApplicationInfo();
|
|
PackageManager pm = context.getPackageManager();
|
|
mNavigationMode = a.getInt(R.styleable.SherlockActionBar_navigationMode,
|
|
ActionBar.NAVIGATION_MODE_STANDARD);
|
|
mTitle = a.getText(R.styleable.SherlockActionBar_title);
|
|
mSubtitle = a.getText(R.styleable.SherlockActionBar_subtitle);
|
|
|
|
mLogo = a.getDrawable(R.styleable.SherlockActionBar_logo);
|
|
if (mLogo == null) {
|
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
|
|
if (context instanceof Activity) {
|
|
//Even though native methods existed in API 9 and 10 they don't work
|
|
//so just parse the manifest to look for the logo pre-Honeycomb
|
|
final int resId = loadLogoFromManifest((Activity) context);
|
|
if (resId != 0) {
|
|
mLogo = context.getResources().getDrawable(resId);
|
|
}
|
|
}
|
|
} else {
|
|
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.SherlockActionBar_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(
|
|
R.styleable.SherlockActionBar_homeLayout,
|
|
R.layout.abs__action_bar_home);
|
|
|
|
mHomeLayout = (HomeView) inflater.inflate(homeResId, this, false);
|
|
|
|
mExpandedHomeLayout = (HomeView) inflater.inflate(homeResId, this, false);
|
|
mExpandedHomeLayout.setUp(true);
|
|
mExpandedHomeLayout.setOnClickListener(mExpandedActionViewUpListener);
|
|
mExpandedHomeLayout.setContentDescription(getResources().getText(
|
|
R.string.abs__action_bar_up_description));
|
|
|
|
mTitleStyleRes = a.getResourceId(R.styleable.SherlockActionBar_titleTextStyle, 0);
|
|
mSubtitleStyleRes = a.getResourceId(R.styleable.SherlockActionBar_subtitleTextStyle, 0);
|
|
mProgressStyle = a.getResourceId(R.styleable.SherlockActionBar_progressBarStyle, 0);
|
|
mIndeterminateProgressStyle = a.getResourceId(
|
|
R.styleable.SherlockActionBar_indeterminateProgressStyle, 0);
|
|
|
|
mProgressBarPadding = a.getDimensionPixelOffset(R.styleable.SherlockActionBar_progressBarPadding, 0);
|
|
mItemPadding = a.getDimensionPixelOffset(R.styleable.SherlockActionBar_itemPadding, 0);
|
|
|
|
setDisplayOptions(a.getInt(R.styleable.SherlockActionBar_displayOptions, DISPLAY_DEFAULT));
|
|
|
|
final int customNavId = a.getResourceId(R.styleable.SherlockActionBar_customNavigationLayout, 0);
|
|
if (customNavId != 0) {
|
|
mCustomNavView = inflater.inflate(customNavId, this, false);
|
|
mNavigationMode = ActionBar.NAVIGATION_MODE_STANDARD;
|
|
setDisplayOptions(mDisplayOptions | ActionBar.DISPLAY_SHOW_CUSTOM);
|
|
}
|
|
|
|
mContentHeight = a.getLayoutDimension(R.styleable.SherlockActionBar_height, 0);
|
|
|
|
a.recycle();
|
|
|
|
mLogoNavItem = new ActionMenuItem(context, 0, android.R.id.home, 0, 0, mTitle);
|
|
mHomeLayout.setOnClickListener(mUpClickListener);
|
|
mHomeLayout.setClickable(true);
|
|
mHomeLayout.setFocusable(true);
|
|
}
|
|
|
|
/**
|
|
* Attempt to programmatically load the logo from the manifest file of an
|
|
* activity by using an XML pull parser. This should allow us to read the
|
|
* logo attribute regardless of the platform it is being run on.
|
|
*
|
|
* @param activity Activity instance.
|
|
* @return Logo resource ID.
|
|
*/
|
|
private static int loadLogoFromManifest(Activity activity) {
|
|
int logo = 0;
|
|
try {
|
|
final String thisPackage = activity.getClass().getName();
|
|
if (DEBUG) Log.i(TAG, "Parsing AndroidManifest.xml for " + thisPackage);
|
|
|
|
final String packageName = activity.getApplicationInfo().packageName;
|
|
final AssetManager am = activity.createPackageContext(packageName, 0).getAssets();
|
|
final XmlResourceParser xml = am.openXmlResourceParser("AndroidManifest.xml");
|
|
|
|
int eventType = xml.getEventType();
|
|
while (eventType != XmlPullParser.END_DOCUMENT) {
|
|
if (eventType == XmlPullParser.START_TAG) {
|
|
String name = xml.getName();
|
|
|
|
if ("application".equals(name)) {
|
|
//Check if the <application> has the attribute
|
|
if (DEBUG) Log.d(TAG, "Got <application>");
|
|
|
|
for (int i = xml.getAttributeCount() - 1; i >= 0; i--) {
|
|
if (DEBUG) Log.d(TAG, xml.getAttributeName(i) + ": " + xml.getAttributeValue(i));
|
|
|
|
if ("logo".equals(xml.getAttributeName(i))) {
|
|
logo = xml.getAttributeResourceValue(i, 0);
|
|
break; //out of for loop
|
|
}
|
|
}
|
|
} else if ("activity".equals(name)) {
|
|
//Check if the <activity> is us and has the attribute
|
|
if (DEBUG) Log.d(TAG, "Got <activity>");
|
|
Integer activityLogo = null;
|
|
String activityPackage = null;
|
|
boolean isOurActivity = false;
|
|
|
|
for (int i = xml.getAttributeCount() - 1; i >= 0; i--) {
|
|
if (DEBUG) Log.d(TAG, xml.getAttributeName(i) + ": " + xml.getAttributeValue(i));
|
|
|
|
//We need both uiOptions and name attributes
|
|
String attrName = xml.getAttributeName(i);
|
|
if ("logo".equals(attrName)) {
|
|
activityLogo = xml.getAttributeResourceValue(i, 0);
|
|
} else if ("name".equals(attrName)) {
|
|
activityPackage = ActionBarSherlockCompat.cleanActivityName(packageName, xml.getAttributeValue(i));
|
|
if (!thisPackage.equals(activityPackage)) {
|
|
break; //on to the next
|
|
}
|
|
isOurActivity = true;
|
|
}
|
|
|
|
//Make sure we have both attributes before processing
|
|
if ((activityLogo != null) && (activityPackage != null)) {
|
|
//Our activity, logo specified, override with our value
|
|
logo = activityLogo.intValue();
|
|
}
|
|
}
|
|
if (isOurActivity) {
|
|
//If we matched our activity but it had no logo don't
|
|
//do any more processing of the manifest
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
eventType = xml.nextToken();
|
|
}
|
|
} catch (Exception e) {
|
|
e.printStackTrace();
|
|
}
|
|
if (DEBUG) Log.i(TAG, "Returning " + Integer.toHexString(logo));
|
|
return logo;
|
|
}
|
|
|
|
/*
|
|
* Must be public so we can dispatch pre-2.2 via ActionBarImpl.
|
|
*/
|
|
@Override
|
|
public void onConfigurationChanged(Configuration newConfig) {
|
|
super.onConfigurationChanged(newConfig);
|
|
|
|
mTitleView = null;
|
|
mSubtitleView = null;
|
|
mTitleUpView = null;
|
|
if (mTitleLayout != null && mTitleLayout.getParent() == this) {
|
|
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();
|
|
//UNUSED removeCallbacks(mTabSelector);
|
|
if (mActionMenuPresenter != null) {
|
|
mActionMenuPresenter.hideOverflowMenu();
|
|
mActionMenuPresenter.hideSubMenus();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean shouldDelayChildPressedState() {
|
|
return false;
|
|
}
|
|
|
|
public void initProgress() {
|
|
mProgressView = new IcsProgressBar(mContext, null, 0, mProgressStyle);
|
|
mProgressView.setId(R.id.abs__progress_horizontal);
|
|
mProgressView.setMax(10000);
|
|
addView(mProgressView);
|
|
}
|
|
|
|
public void initIndeterminateProgress() {
|
|
mIndeterminateProgressView = new IcsProgressBar(mContext, null, 0, mIndeterminateProgressStyle);
|
|
mIndeterminateProgressView.setId(R.id.abs__progress_circular);
|
|
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);
|
|
}
|
|
} else {
|
|
addView(mMenuView);
|
|
}
|
|
}
|
|
if (mSplitView != null) {
|
|
mSplitView.setVisibility(splitActionBar ? VISIBLE : GONE);
|
|
}
|
|
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(R.id.abs__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(getContext(),
|
|
R.bool.abs__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) {
|
|
mHomeLayout.setEnabled(enable);
|
|
mHomeLayout.setFocusable(enable);
|
|
// Make sure the home button has an accurate content description for accessibility.
|
|
if (!enable) {
|
|
mHomeLayout.setContentDescription(null);
|
|
} else if ((mDisplayOptions & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
|
|
mHomeLayout.setContentDescription(mContext.getResources().getText(
|
|
R.string.abs__action_bar_up_description));
|
|
} else {
|
|
mHomeLayout.setContentDescription(mContext.getResources().getText(
|
|
R.string.abs__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 {
|
|
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);
|
|
mTitleLayout.setEnabled(!showHome && homeAsUp);
|
|
}
|
|
|
|
if ((flagsChanged & ActionBar.DISPLAY_SHOW_CUSTOM) != 0 && mCustomNavView != null) {
|
|
if ((options & ActionBar.DISPLAY_SHOW_CUSTOM) != 0) {
|
|
addView(mCustomNavView);
|
|
} else {
|
|
removeView(mCustomNavView);
|
|
}
|
|
}
|
|
|
|
requestLayout();
|
|
} else {
|
|
invalidate();
|
|
}
|
|
|
|
// Make sure the home button has an accurate content description for accessibility.
|
|
if (!mHomeLayout.isEnabled()) {
|
|
mHomeLayout.setContentDescription(null);
|
|
} else if ((options & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
|
|
mHomeLayout.setContentDescription(mContext.getResources().getText(
|
|
R.string.abs__action_bar_up_description));
|
|
} else {
|
|
mHomeLayout.setContentDescription(mContext.getResources().getText(
|
|
R.string.abs__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);
|
|
}
|
|
}
|
|
|
|
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 IcsSpinner(mContext, null,
|
|
R.attr.actionDropDownStyle);
|
|
mListNavLayout = (IcsLinearLayout) LayoutInflater.from(mContext)
|
|
.inflate(R.layout.abs__action_bar_tab_bar_view, null);
|
|
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();
|
|
|
|
addView(mHomeLayout);
|
|
|
|
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.abs__action_bar_title_item,
|
|
this, false);
|
|
mTitleView = (TextView) mTitleLayout.findViewById(R.id.abs__action_bar_title);
|
|
mSubtitleView = (TextView) mTitleLayout.findViewById(R.id.abs__action_bar_subtitle);
|
|
mTitleUpView = mTitleLayout.findViewById(R.id.abs__up);
|
|
|
|
mTitleLayout.setOnClickListener(mUpClickListener);
|
|
|
|
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;
|
|
mTitleUpView.setVisibility(!showHome ? (homeAsUp ? VISIBLE : INVISIBLE) : GONE);
|
|
mTitleLayout.setEnabled(homeAsUp && !showHome);
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
@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)) {
|
|
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);
|
|
|
|
int availableWidth = contentWidth - paddingLeft - paddingRight;
|
|
int leftOfCenter = availableWidth / 2;
|
|
int rightOfCenter = leftOfCenter;
|
|
|
|
HomeView homeLayout = mExpandedActionView != null ? mExpandedHomeLayout : mHomeLayout;
|
|
|
|
if (homeLayout.getVisibility() != GONE) {
|
|
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);
|
|
}
|
|
homeLayout.measure(homeWidthSpec,
|
|
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
|
|
final int homeWidth = homeLayout.getMeasuredWidth() + homeLayout.getLeftOffset();
|
|
availableWidth = Math.max(0, availableWidth - homeWidth);
|
|
leftOfCenter = Math.max(0, availableWidth - homeWidth);
|
|
}
|
|
|
|
if (mMenuView != null && mMenuView.getParent() == this) {
|
|
availableWidth = measureChildView(mMenuView, availableWidth,
|
|
childSpecHeight, 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();
|
|
}
|
|
|
|
if (mExpandedActionView == null && showTitle) {
|
|
availableWidth = measureChildView(mTitleLayout, availableWidth,
|
|
MeasureSpec.makeMeasureSpec(mContentHeight, MeasureSpec.EXACTLY), 0);
|
|
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) {
|
|
int x = getPaddingLeft();
|
|
final int y = getPaddingTop();
|
|
final int contentHeight = b - t - getPaddingTop() - getPaddingBottom();
|
|
|
|
if (contentHeight <= 0) {
|
|
// Nothing to do if we can't see anything.
|
|
return;
|
|
}
|
|
|
|
HomeView homeLayout = mExpandedActionView != null ? mExpandedHomeLayout : mHomeLayout;
|
|
if (homeLayout.getVisibility() != GONE) {
|
|
final int leftOffset = homeLayout.getLeftOffset();
|
|
x += positionChild(homeLayout, x + leftOffset, y, contentHeight) + leftOffset;
|
|
}
|
|
|
|
if (mExpandedActionView == null) {
|
|
final boolean showTitle = mTitleLayout != null && mTitleLayout.getVisibility() != GONE &&
|
|
(mDisplayOptions & ActionBar.DISPLAY_SHOW_TITLE) != 0;
|
|
if (showTitle) {
|
|
x += positionChild(mTitleLayout, x, y, contentHeight);
|
|
}
|
|
|
|
switch (mNavigationMode) {
|
|
case ActionBar.NAVIGATION_MODE_STANDARD:
|
|
break;
|
|
case ActionBar.NAVIGATION_MODE_LIST:
|
|
if (mListNavLayout != null) {
|
|
if (showTitle) x += mItemPadding;
|
|
x += positionChild(mListNavLayout, x, y, contentHeight) + mItemPadding;
|
|
}
|
|
break;
|
|
case ActionBar.NAVIGATION_MODE_TABS:
|
|
if (mTabScrollView != null) {
|
|
if (showTitle) x += mItemPadding;
|
|
x += positionChild(mTabScrollView, x, y, contentHeight) + mItemPadding;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
int menuLeft = r - l - getPaddingRight();
|
|
if (mMenuView != null && mMenuView.getParent() == this) {
|
|
positionChildInverse(mMenuView, menuLeft, y, contentHeight);
|
|
menuLeft -= mMenuView.getMeasuredWidth();
|
|
}
|
|
|
|
if (mIndeterminateProgressView != null &&
|
|
mIndeterminateProgressView.getVisibility() != GONE) {
|
|
positionChildInverse(mIndeterminateProgressView, menuLeft, y, contentHeight);
|
|
menuLeft -= 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) {
|
|
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 += ablp.leftMargin;
|
|
menuLeft -= ablp.rightMargin;
|
|
topMargin = ablp.topMargin;
|
|
bottomMargin = ablp.bottomMargin;
|
|
}
|
|
|
|
int hgravity = gravity & Gravity.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 = ((getRight() - getLeft()) - navWidth) / 2;
|
|
if (centeredLeft < x) {
|
|
hgravity = Gravity.LEFT;
|
|
} else if (centeredLeft + navWidth > menuLeft) {
|
|
hgravity = Gravity.RIGHT;
|
|
}
|
|
} else if (gravity == -1) {
|
|
hgravity = Gravity.LEFT;
|
|
}
|
|
|
|
int xpos = 0;
|
|
switch (hgravity) {
|
|
case Gravity.CENTER_HORIZONTAL:
|
|
xpos = ((getRight() - getLeft()) - navWidth) / 2;
|
|
break;
|
|
case Gravity.LEFT:
|
|
xpos = x;
|
|
break;
|
|
case Gravity.RIGHT:
|
|
xpos = menuLeft - navWidth;
|
|
break;
|
|
}
|
|
|
|
int vgravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;
|
|
|
|
if (gravity == -1) {
|
|
vgravity = Gravity.CENTER_VERTICAL;
|
|
}
|
|
|
|
int ypos = 0;
|
|
switch (vgravity) {
|
|
case Gravity.CENTER_VERTICAL:
|
|
final int paddedTop = getPaddingTop();
|
|
final int paddedBottom = getBottom() - getTop() - 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 += customWidth;
|
|
}
|
|
|
|
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];
|
|
}
|
|
};
|
|
}
|
|
|
|
public static class HomeView extends FrameLayout {
|
|
private View mUpView;
|
|
private ImageView mIconView;
|
|
private int mUpWidth;
|
|
|
|
public HomeView(Context context) {
|
|
this(context, null);
|
|
}
|
|
|
|
public HomeView(Context context, AttributeSet attrs) {
|
|
super(context, attrs);
|
|
}
|
|
|
|
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) {
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
|
|
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(R.id.abs__up);
|
|
mIconView = (ImageView) findViewById(R.id.abs__home);
|
|
}
|
|
|
|
public int getLeftOffset() {
|
|
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;
|
|
//UNUSED int width = r - l;
|
|
int upOffset = 0;
|
|
if (mUpView.getVisibility() != GONE) {
|
|
final LayoutParams upLp = (LayoutParams) mUpView.getLayoutParams();
|
|
final int upHeight = mUpView.getMeasuredHeight();
|
|
final int upWidth = mUpView.getMeasuredWidth();
|
|
final int upTop = vCenter - upHeight / 2;
|
|
mUpView.layout(0, upTop, upWidth, upTop + upHeight);
|
|
upOffset = upLp.leftMargin + upWidth + upLp.rightMargin;
|
|
//UNUSED width -= upOffset;
|
|
l += upOffset;
|
|
}
|
|
final LayoutParams iconLp = (LayoutParams) mIconView.getLayoutParams();
|
|
final int iconHeight = mIconView.getMeasuredHeight();
|
|
final int iconWidth = mIconView.getMeasuredWidth();
|
|
final int hCenter = (r - l) / 2;
|
|
final int iconLeft = upOffset + Math.max(iconLp.leftMargin, hCenter - iconWidth / 2);
|
|
final int iconTop = Math.max(iconLp.topMargin, vCenter - iconHeight / 2);
|
|
mIconView.layout(iconLeft, iconTop, iconLeft + iconWidth, iconTop + iconHeight);
|
|
}
|
|
}
|
|
|
|
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(/* TODO getResources() */));
|
|
mCurrentExpandedItem = item;
|
|
if (mExpandedActionView.getParent() != ActionBarView.this) {
|
|
addView(mExpandedActionView);
|
|
}
|
|
if (mExpandedHomeLayout.getParent() != ActionBarView.this) {
|
|
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);
|
|
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);
|
|
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;
|
|
requestLayout();
|
|
item.setActionViewExpanded(false);
|
|
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public int getId() {
|
|
return 0;
|
|
}
|
|
|
|
@Override
|
|
public Parcelable onSaveInstanceState() {
|
|
return null;
|
|
}
|
|
|
|
@Override
|
|
public void onRestoreInstanceState(Parcelable state) {
|
|
}
|
|
}
|
|
}
|