Merge "Toolbar factoring and ActionBar functionality integration" into lmp-preview-dev

This commit is contained in:
Adam Powell
2014-05-28 21:44:01 +00:00
committed by Android (Google) Code Review
21 changed files with 1438 additions and 214 deletions

View File

@@ -35847,10 +35847,14 @@ package android.widget {
public class ActionMenuView extends android.widget.LinearLayout {
ctor public ActionMenuView(android.content.Context);
ctor public ActionMenuView(android.content.Context, android.util.AttributeSet);
method public void dismissPopupMenus();
method public android.view.Menu getMenu();
method public boolean hideOverflowMenu();
method public boolean isOverflowMenuShowing();
method public void onConfigurationChanged(android.content.res.Configuration);
method public void onDetachedFromWindow();
method public void setOnMenuItemClickListener(android.widget.ActionMenuView.OnMenuItemClickListener);
method public boolean showOverflowMenu();
}
public static class ActionMenuView.LayoutParams extends android.widget.LinearLayout.LayoutParams {
@@ -38028,6 +38032,8 @@ package android.widget {
ctor public Toolbar(android.content.Context, android.util.AttributeSet);
ctor public Toolbar(android.content.Context, android.util.AttributeSet, int);
ctor public Toolbar(android.content.Context, android.util.AttributeSet, int, int);
method public void collapseActionView();
method public void dismissPopupMenus();
method public int getContentInsetEnd();
method public int getContentInsetLeft();
method public int getContentInsetRight();
@@ -38038,7 +38044,10 @@ package android.widget {
method public android.graphics.drawable.Drawable getNavigationIcon();
method public java.lang.CharSequence getSubtitle();
method public java.lang.CharSequence getTitle();
method public boolean hasExpandedActionView();
method public boolean hideOverflowMenu();
method public void inflateMenu(int);
method public boolean isOverflowMenuShowing();
method protected void onLayout(boolean, int, int, int, int);
method public void setContentInsetsAbsolute(int, int);
method public void setContentInsetsRelative(int, int);
@@ -38046,6 +38055,8 @@ package android.widget {
method public void setLogo(android.graphics.drawable.Drawable);
method public void setLogoDescription(int);
method public void setLogoDescription(java.lang.CharSequence);
method public void setNavigationContentDescription(java.lang.CharSequence);
method public void setNavigationContentDescription(int);
method public void setNavigationDescription(int);
method public void setNavigationDescription(java.lang.CharSequence);
method public void setNavigationIcon(int);
@@ -38056,17 +38067,18 @@ package android.widget {
method public void setSubtitle(java.lang.CharSequence);
method public void setTitle(int);
method public void setTitle(java.lang.CharSequence);
method public boolean showOverflowMenu();
}
public static class Toolbar.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
public static class Toolbar.LayoutParams extends android.app.ActionBar.LayoutParams {
ctor public Toolbar.LayoutParams(android.content.Context, android.util.AttributeSet);
ctor public Toolbar.LayoutParams(int, int);
ctor public Toolbar.LayoutParams(int, int, int);
ctor public Toolbar.LayoutParams(int);
ctor public Toolbar.LayoutParams(android.widget.Toolbar.LayoutParams);
ctor public Toolbar.LayoutParams(android.app.ActionBar.LayoutParams);
ctor public Toolbar.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
ctor public Toolbar.LayoutParams(android.view.ViewGroup.LayoutParams);
field public int gravity;
}
public static abstract interface Toolbar.OnMenuItemClickListener {

View File

@@ -1291,6 +1291,7 @@ public abstract class ActionBar {
public LayoutParams(int width, int height) {
super(width, height);
this.gravity = Gravity.CENTER_VERTICAL | Gravity.START;
}
public LayoutParams(int width, int height, int gravity) {
@@ -1305,6 +1306,7 @@ public abstract class ActionBar {
public LayoutParams(LayoutParams source) {
super(source);
this.gravity = source.gravity;
}
public LayoutParams(ViewGroup.LayoutParams source) {

View File

@@ -544,6 +544,7 @@ public class ActionMenuPresenter extends BaseMenuPresenter
public void setMenuView(ActionMenuView menuView) {
mMenuView = menuView;
menuView.initialize(mMenu);
}
private static class SavedState implements Parcelable {

View File

@@ -69,6 +69,7 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo
/** @hide */
public void setPresenter(ActionMenuPresenter presenter) {
mPresenter = presenter;
mPresenter.setMenuView(this);
}
@Override
@@ -488,7 +489,7 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo
@Override
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
mPresenter.dismissPopupMenus();
dismissPopupMenus();
}
/** @hide */
@@ -577,6 +578,56 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo
return mMenu;
}
/**
* Returns the current menu or null if one has not yet been configured.
* @hide Internal use only for action bar integration
*/
public MenuBuilder peekMenu() {
return mMenu;
}
/**
* Show the overflow items from the associated menu.
*
* @return true if the menu was able to be shown, false otherwise
*/
public boolean showOverflowMenu() {
return mPresenter != null && mPresenter.showOverflowMenu();
}
/**
* Hide the overflow items from the associated menu.
*
* @return true if the menu was able to be hidden, false otherwise
*/
public boolean hideOverflowMenu() {
return mPresenter != null && mPresenter.hideOverflowMenu();
}
/**
* Check whether the overflow menu is currently showing. This may not reflect
* a pending show operation in progress.
*
* @return true if the overflow menu is currently showing
*/
public boolean isOverflowMenuShowing() {
return mPresenter != null && mPresenter.isOverflowMenuShowing();
}
/** @hide */
public boolean isOverflowMenuShowPending() {
return mPresenter != null && mPresenter.isOverflowMenuShowPending();
}
/**
* Dismiss any popups associated with this menu view.
*/
public void dismissPopupMenus() {
if (mPresenter != null) {
mPresenter.dismissPopupMenus();
}
}
/**
* @hide Private LinearLayout (superclass) API. Un-hide if LinearLayout API is made public.
*/

View File

@@ -18,13 +18,17 @@
package android.widget;
import android.annotation.NonNull;
import android.app.ActionBar;
import android.content.Context;
import android.content.res.TypedArray;
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.Menu;
import android.view.MenuInflater;
@@ -32,7 +36,15 @@ import android.view.MenuItem;
import android.view.View;
import android.view.ViewDebug;
import android.view.ViewGroup;
import android.view.Window;
import com.android.internal.R;
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 com.android.internal.widget.DecorToolbar;
import com.android.internal.widget.ToolbarWidgetWrapper;
import java.util.ArrayList;
import java.util.List;
@@ -80,14 +92,25 @@ import java.util.List;
* layout is discouraged on API 21 devices and newer.</p>
*/
public class Toolbar extends ViewGroup {
private static final String TAG = "Toolbar";
private ActionMenuView mMenuView;
private TextView mTitleTextView;
private TextView mSubtitleTextView;
private ImageButton mNavButtonView;
private ImageView mLogoView;
private Drawable mCollapseIcon;
private ImageButton mCollapseButtonView;
View mExpandedActionView;
private int mTitleTextAppearance;
private int mSubtitleTextAppearance;
private int mNavButtonStyle;
private int mButtonGravity;
private int mMaxButtonHeight;
private int mTitleMarginStart;
private int mTitleMarginEnd;
@@ -117,6 +140,10 @@ public class Toolbar extends ViewGroup {
}
};
private ToolbarWidgetWrapper mWrapper;
private ActionMenuPresenter mOuterActionMenuPresenter;
private ExpandedActionViewMenuPresenter mExpandedMenuPresenter;
public Toolbar(Context context) {
this(context, null);
}
@@ -137,7 +164,9 @@ public class Toolbar extends ViewGroup {
mTitleTextAppearance = a.getResourceId(R.styleable.Toolbar_titleTextAppearance, 0);
mSubtitleTextAppearance = a.getResourceId(R.styleable.Toolbar_subtitleTextAppearance, 0);
mNavButtonStyle = a.getResourceId(R.styleable.Toolbar_navigationButtonStyle, 0);
mGravity = a.getInteger(R.styleable.Toolbar_gravity, mGravity);
mButtonGravity = a.getInteger(R.styleable.Toolbar_buttonGravity, Gravity.TOP);
mTitleMarginStart = mTitleMarginEnd = mTitleMarginTop = mTitleMarginBottom =
a.getDimensionPixelOffset(R.styleable.Toolbar_titleMargins, 0);
@@ -162,6 +191,8 @@ public class Toolbar extends ViewGroup {
mTitleMarginBottom = marginBottom;
}
mMaxButtonHeight = a.getDimensionPixelSize(R.styleable.Toolbar_maxButtonHeight, -1);
final int contentInsetStart =
a.getDimensionPixelOffset(R.styleable.Toolbar_contentInsetStart,
RtlSpacingHelper.UNDEFINED);
@@ -180,6 +211,8 @@ public class Toolbar extends ViewGroup {
mContentInsets.setRelative(contentInsetStart, contentInsetEnd);
}
mCollapseIcon = a.getDrawable(R.styleable.Toolbar_collapseIcon);
final CharSequence title = a.getText(R.styleable.Toolbar_title);
if (!TextUtils.isEmpty(title)) {
setTitle(title);
@@ -211,6 +244,110 @@ public class Toolbar extends ViewGroup {
setLogo(getContext().getDrawable(resId));
}
/** @hide */
public boolean canShowOverflowMenu() {
return getVisibility() == VISIBLE && mMenuView != null && mMenuView.isOverflowReserved();
}
/**
* Check whether the overflow menu is currently showing. This may not reflect
* a pending show operation in progress.
*
* @return true if the overflow menu is currently showing
*/
public boolean isOverflowMenuShowing() {
return mMenuView != null && mMenuView.isOverflowMenuShowing();
}
/** @hide */
public boolean isOverflowMenuShowPending() {
return mMenuView != null && mMenuView.isOverflowMenuShowPending();
}
/**
* Show the overflow items from the associated menu.
*
* @return true if the menu was able to be shown, false otherwise
*/
public boolean showOverflowMenu() {
return mMenuView != null && mMenuView.showOverflowMenu();
}
/**
* Hide the overflow items from the associated menu.
*
* @return true if the menu was able to be hidden, false otherwise
*/
public boolean hideOverflowMenu() {
return mMenuView != null && mMenuView.hideOverflowMenu();
}
/** @hide */
public void setMenu(MenuBuilder menu, ActionMenuPresenter outerPresenter) {
if (menu == null && mMenuView == null) {
return;
}
ensureMenuView();
final MenuBuilder oldMenu = mMenuView.peekMenu();
if (oldMenu == menu) {
return;
}
if (oldMenu != null) {
oldMenu.removeMenuPresenter(mOuterActionMenuPresenter);
oldMenu.removeMenuPresenter(mExpandedMenuPresenter);
}
final Context context = getContext();
if (mExpandedMenuPresenter == null) {
mExpandedMenuPresenter = new ExpandedActionViewMenuPresenter();
}
outerPresenter.setExpandedActionViewsExclusive(true);
if (menu != null) {
menu.addMenuPresenter(outerPresenter);
menu.addMenuPresenter(mExpandedMenuPresenter);
} else {
outerPresenter.initForMenu(context, null);
mExpandedMenuPresenter.initForMenu(context, null);
outerPresenter.updateMenuView(true);
mExpandedMenuPresenter.updateMenuView(true);
}
mMenuView.setPresenter(outerPresenter);
mOuterActionMenuPresenter = outerPresenter;
}
/**
* Dismiss all currently showing popup menus, including overflow or submenus.
*/
public void dismissPopupMenus() {
if (mMenuView != null) {
mMenuView.dismissPopupMenus();
}
}
/** @hide */
public boolean isTitleTruncated() {
if (mTitleTextView == null) {
return false;
}
final Layout titleLayout = mTitleTextView.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;
}
/**
* Set a logo drawable.
*
@@ -222,9 +359,7 @@ public class Toolbar extends ViewGroup {
*/
public void setLogo(Drawable drawable) {
if (drawable != null) {
if (mLogoView == null) {
mLogoView = new ImageView(getContext());
}
ensureLogoView();
if (mLogoView.getParent() == null) {
addSystemView(mLogoView);
}
@@ -268,8 +403,8 @@ public class Toolbar extends ViewGroup {
* @param description Description to set
*/
public void setLogoDescription(CharSequence description) {
if (!TextUtils.isEmpty(description) && mLogoView == null) {
mLogoView = new ImageView(getContext());
if (!TextUtils.isEmpty(description)) {
ensureLogoView();
}
if (mLogoView != null) {
mLogoView.setContentDescription(description);
@@ -285,10 +420,48 @@ public class Toolbar extends ViewGroup {
return mLogoView != null ? mLogoView.getContentDescription() : null;
}
private void ensureLogoView() {
if (mLogoView == null) {
mLogoView = new ImageView(getContext());
}
}
/**
* Return the current title displayed in the toolbar.
* Check whether this Toolbar is currently hosting an expanded action view.
*
* @return The current title
* <p>An action view may be expanded either directly from the
* {@link android.view.MenuItem MenuItem} it belongs to or by user action. If the Toolbar
* has an expanded action view it can be collapsed using the {@link #collapseActionView()}
* method.</p>
*
* @return true if the Toolbar has an expanded action view
*/
public boolean hasExpandedActionView() {
return mExpandedMenuPresenter != null &&
mExpandedMenuPresenter.mCurrentExpandedItem != null;
}
/**
* Collapse a currently expanded action view. If this Toolbar does not have an
* expanded action view this method has no effect.
*
* <p>An action view may be expanded either directly from the
* {@link android.view.MenuItem MenuItem} it belongs to or by user action.</p>
*
* @see #hasExpandedActionView()
*/
public void collapseActionView() {
final MenuItemImpl item = mExpandedMenuPresenter == null ? null :
mExpandedMenuPresenter.mCurrentExpandedItem;
if (item != null) {
item.collapseActionView();
}
}
/**
* Returns the title of this toolbar.
*
* @return The current title.
*/
public CharSequence getTitle() {
return mTitleText;
@@ -319,6 +492,8 @@ public class Toolbar extends ViewGroup {
if (mTitleTextView == null) {
final Context context = getContext();
mTitleTextView = new TextView(context);
mTitleTextView.setSingleLine();
mTitleTextView.setEllipsize(TextUtils.TruncateAt.END);
mTitleTextView.setTextAppearance(context, mTitleTextAppearance);
}
if (mTitleTextView.getParent() == null) {
@@ -365,6 +540,8 @@ public class Toolbar extends ViewGroup {
if (mSubtitleTextView == null) {
final Context context = getContext();
mSubtitleTextView = new TextView(context);
mSubtitleTextView.setSingleLine();
mSubtitleTextView.setEllipsize(TextUtils.TruncateAt.END);
mSubtitleTextView.setTextAppearance(context, mSubtitleTextAppearance);
}
if (mSubtitleTextView.getParent() == null) {
@@ -394,6 +571,30 @@ public class Toolbar extends ViewGroup {
setNavigationIcon(getContext().getDrawable(resId));
}
/**
* Set a content description for the navigation button if one is present. The content
* description will be read via screen readers or other accessibility systems to explain
* the action of the navigation button.
*
* @param description Content description to set
*/
public void setNavigationContentDescription(CharSequence description) {
ensureNavButtonView();
mNavButtonView.setContentDescription(description);
}
/**
* Set a content description for the navigation button if one is present. The content
* description will be read via screen readers or other accessibility systems to explain
* the action of the navigation button.
*
* @param resId Resource ID of a content description string to set
*/
public void setNavigationContentDescription(int resId) {
ensureNavButtonView();
mNavButtonView.setContentDescription(getContext().getText(resId));
}
/**
* Set the icon to use for the toolbar's navigation button.
*
@@ -480,12 +681,19 @@ public class Toolbar extends ViewGroup {
* @return The toolbar's Menu
*/
public Menu getMenu() {
ensureMenuView();
return mMenuView.getMenu();
}
private void ensureMenuView() {
if (mMenuView == null) {
mMenuView = new ActionMenuView(getContext());
mMenuView.setOnMenuItemClickListener(mMenuViewItemClickListener);
final LayoutParams lp = generateDefaultLayoutParams();
lp.gravity = Gravity.END | (mButtonGravity & Gravity.VERTICAL_GRAVITY_MASK);
mMenuView.setLayoutParams(lp);
addSystemView(mMenuView);
}
return mMenuView.getMenu();
}
private MenuInflater getMenuInflater() {
@@ -634,7 +842,27 @@ public class Toolbar extends ViewGroup {
private void ensureNavButtonView() {
if (mNavButtonView == null) {
mNavButtonView = new ImageButton(getContext(), null, R.attr.borderlessButtonStyle);
mNavButtonView = new ImageButton(getContext(), null, 0, mNavButtonStyle);
final LayoutParams lp = generateDefaultLayoutParams();
lp.gravity = Gravity.START | (mButtonGravity & Gravity.VERTICAL_GRAVITY_MASK);
mNavButtonView.setLayoutParams(lp);
}
}
private void ensureCollapseButtonView() {
if (mCollapseButtonView == null) {
mCollapseButtonView = new ImageButton(getContext(), null, 0, mNavButtonStyle);
mCollapseButtonView.setImageDrawable(mCollapseIcon);
final LayoutParams lp = generateDefaultLayoutParams();
lp.gravity = Gravity.START | (mButtonGravity & Gravity.VERTICAL_GRAVITY_MASK);
lp.mViewType = LayoutParams.EXPANDED;
mCollapseButtonView.setLayoutParams(lp);
mCollapseButtonView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
collapseActionView();
}
});
}
}
@@ -657,6 +885,27 @@ public class Toolbar extends ViewGroup {
super.onRestoreInstanceState(ss.getSuperState());
}
private void measureChildConstrained(View child, int parentWidthSpec, int widthUsed,
int parentHeightSpec, int heightUsed, int heightConstraint) {
final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
int childWidthSpec = getChildMeasureSpec(parentWidthSpec,
mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin
+ widthUsed, lp.width);
int childHeightSpec = getChildMeasureSpec(parentHeightSpec,
mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin
+ heightUsed, lp.height);
final int childHeightMode = MeasureSpec.getMode(childHeightSpec);
if (childHeightMode != MeasureSpec.EXACTLY && heightConstraint >= 0) {
final int size = childHeightMode != MeasureSpec.UNSPECIFIED ?
Math.min(MeasureSpec.getSize(childHeightSpec), heightConstraint) :
heightConstraint;
childHeightSpec = MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY);
}
child.measure(childWidthSpec, childHeightSpec);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = 0;
@@ -667,18 +916,30 @@ public class Toolbar extends ViewGroup {
int navWidth = 0;
if (shouldLayout(mNavButtonView)) {
measureChildWithMargins(mNavButtonView, widthMeasureSpec, width, heightMeasureSpec, 0);
measureChildConstrained(mNavButtonView, widthMeasureSpec, width, heightMeasureSpec, 0,
mMaxButtonHeight);
navWidth = mNavButtonView.getMeasuredWidth() + getHorizontalMargins(mNavButtonView);
height = Math.max(height, mNavButtonView.getMeasuredHeight() +
getVerticalMargins(mNavButtonView));
childState = combineMeasuredStates(childState, mNavButtonView.getMeasuredState());
}
if (shouldLayout(mCollapseButtonView)) {
measureChildConstrained(mCollapseButtonView, widthMeasureSpec, width,
heightMeasureSpec, 0, mMaxButtonHeight);
navWidth = mCollapseButtonView.getMeasuredWidth() +
getHorizontalMargins(mCollapseButtonView);
height = Math.max(height, mCollapseButtonView.getMeasuredHeight() +
getVerticalMargins(mCollapseButtonView));
childState = combineMeasuredStates(childState, mCollapseButtonView.getMeasuredState());
}
width += Math.max(getContentInsetStart(), navWidth);
int menuWidth = 0;
if (shouldLayout(mMenuView)) {
measureChildWithMargins(mMenuView, widthMeasureSpec, width, heightMeasureSpec, 0);
measureChildConstrained(mMenuView, widthMeasureSpec, width, heightMeasureSpec, 0,
mMaxButtonHeight);
menuWidth = mMenuView.getMeasuredWidth() + getHorizontalMargins(mMenuView);
height = Math.max(height, mMenuView.getMeasuredHeight() +
getVerticalMargins(mMenuView));
@@ -687,6 +948,16 @@ public class Toolbar extends ViewGroup {
width += Math.max(getContentInsetEnd(), menuWidth);
if (shouldLayout(mExpandedActionView)) {
measureChildWithMargins(mExpandedActionView, widthMeasureSpec, width,
heightMeasureSpec, 0);
width += mExpandedActionView.getMeasuredWidth() +
getHorizontalMargins(mExpandedActionView);
height = Math.max(height, mExpandedActionView.getMeasuredHeight() +
getVerticalMargins(mExpandedActionView));
childState = combineMeasuredStates(childState, mExpandedActionView.getMeasuredState());
}
if (shouldLayout(mLogoView)) {
measureChildWithMargins(mLogoView, widthMeasureSpec, width, heightMeasureSpec, 0);
width += mLogoView.getMeasuredWidth() + getHorizontalMargins(mLogoView);
@@ -723,7 +994,7 @@ public class Toolbar extends ViewGroup {
for (int i = 0; i < childCount; i++) {
final View child = getChildAt(i);
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
if (lp.mViewType == LayoutParams.SYSTEM || !shouldLayout(child)) {
if (lp.mViewType != LayoutParams.CUSTOM || !shouldLayout(child)) {
// We already got all system views above. Skip them and GONE views.
continue;
}
@@ -768,6 +1039,14 @@ public class Toolbar extends ViewGroup {
}
}
if (shouldLayout(mCollapseButtonView)) {
if (isRtl) {
right = layoutChildRight(mCollapseButtonView, right);
} else {
left = layoutChildLeft(mCollapseButtonView, left);
}
}
if (shouldLayout(mMenuView)) {
if (isRtl) {
left = layoutChildLeft(mMenuView, left);
@@ -779,6 +1058,14 @@ public class Toolbar extends ViewGroup {
left = Math.max(left, getContentInsetLeft());
right = Math.min(right, width - paddingRight - getContentInsetRight());
if (shouldLayout(mExpandedActionView)) {
if (isRtl) {
right = layoutChildRight(mExpandedActionView, right);
} else {
left = layoutChildLeft(mExpandedActionView, left);
}
}
if (shouldLayout(mLogoView)) {
if (isRtl) {
right = layoutChildRight(mLogoView, right);
@@ -801,40 +1088,42 @@ public class Toolbar extends ViewGroup {
if (layoutTitle || layoutSubtitle) {
int titleTop;
final View topChild = layoutTitle ? mTitleTextView : mSubtitleTextView;
final View bottomChild = layoutSubtitle ? mSubtitleTextView : mTitleTextView;
final LayoutParams toplp = (LayoutParams) topChild.getLayoutParams();
final LayoutParams bottomlp = (LayoutParams) bottomChild.getLayoutParams();
switch (mGravity & Gravity.VERTICAL_GRAVITY_MASK) {
case Gravity.TOP:
titleTop = getPaddingTop();
titleTop = getPaddingTop() + toplp.topMargin + mTitleMarginTop;
break;
default:
case Gravity.CENTER_VERTICAL:
final View child = layoutTitle ? mTitleTextView : mSubtitleTextView;
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
final int space = height - paddingTop - paddingBottom;
int spaceAbove = (space - titleHeight) / 2;
if (spaceAbove < lp.topMargin + mTitleMarginTop) {
spaceAbove = lp.topMargin + mTitleMarginTop;
if (spaceAbove < toplp.topMargin + mTitleMarginTop) {
spaceAbove = toplp.topMargin + mTitleMarginTop;
} else {
final int spaceBelow = height - paddingBottom - titleHeight -
spaceAbove - paddingTop;
if (spaceBelow < lp.bottomMargin + mTitleMarginBottom) {
if (spaceBelow < toplp.bottomMargin + mTitleMarginBottom) {
spaceAbove = Math.max(0, spaceAbove -
(lp.bottomMargin + mTitleMarginBottom - spaceBelow));
(bottomlp.bottomMargin + mTitleMarginBottom - spaceBelow));
}
}
titleTop = paddingTop + spaceAbove;
break;
case Gravity.BOTTOM:
titleTop = height - paddingBottom - titleHeight;
titleTop = height - paddingBottom - bottomlp.bottomMargin - mTitleMarginBottom -
titleHeight;
break;
}
if (isRtl) {
int titleRight = right;
int subtitleRight = right;
titleTop += mTitleMarginTop;
if (layoutTitle) {
final LayoutParams lp = (LayoutParams) mTitleTextView.getLayoutParams();
titleRight -= lp.rightMargin + mTitleMarginStart;
titleTop += lp.topMargin;
final int titleLeft = titleRight - mTitleTextView.getMeasuredWidth();
final int titleBottom = titleTop + mTitleTextView.getMeasuredHeight();
mTitleTextView.layout(titleLeft, titleTop, titleRight, titleBottom);
@@ -855,11 +1144,9 @@ public class Toolbar extends ViewGroup {
} else {
int titleLeft = left;
int subtitleLeft = left;
titleTop += mTitleMarginTop;
if (layoutTitle) {
final LayoutParams lp = (LayoutParams) mTitleTextView.getLayoutParams();
titleLeft += lp.leftMargin + mTitleMarginStart;
titleTop += lp.topMargin;
final int titleRight = titleLeft + mTitleTextView.getMeasuredWidth();
final int titleBottom = titleTop + mTitleTextView.getMeasuredHeight();
mTitleTextView.layout(titleLeft, titleTop, titleRight, titleBottom);
@@ -897,7 +1184,7 @@ public class Toolbar extends ViewGroup {
// Centered views try to center with respect to the whole bar, but views pinned
// to the left or right can push the mass of centered views to one side or the other.
addCustomViewsWithGravity(mTempViews, Gravity.CENTER);
addCustomViewsWithGravity(mTempViews, Gravity.CENTER_HORIZONTAL);
final int centerViewsWidth = getViewListMeasuredWidth(mTempViews);
final int parentCenter = paddingLeft + (width - paddingLeft - paddingRight) / 2;
final int halfCenterViewsWidth = centerViewsWidth / 2;
@@ -1007,17 +1294,16 @@ public class Toolbar extends ViewGroup {
for (int i = childCount - 1; i >= 0; i--) {
final View child = getChildAt(i);
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
if (lp.mViewType != LayoutParams.SYSTEM && shouldLayout(child) &&
if (lp.mViewType == LayoutParams.CUSTOM && shouldLayout(child) &&
getChildHorizontalGravity(lp.gravity) == absGrav) {
views.add(child);
}
}
} else {
for (int i = 0; i < childCount; i++) {
final View child = getChildAt(i);
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
if (lp.mViewType != LayoutParams.SYSTEM && shouldLayout(child) &&
if (lp.mViewType == LayoutParams.CUSTOM && shouldLayout(child) &&
getChildHorizontalGravity(lp.gravity) == absGrav) {
views.add(child);
}
@@ -1054,14 +1340,16 @@ public class Toolbar extends ViewGroup {
}
@Override
public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
return super.generateLayoutParams(attrs);
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new LayoutParams(getContext(), attrs);
}
@Override
protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
if (p instanceof LayoutParams) {
return new LayoutParams((LayoutParams) p);
} else if (p instanceof ActionBar.LayoutParams) {
return new LayoutParams((ActionBar.LayoutParams) p);
} else if (p instanceof MarginLayoutParams) {
return new LayoutParams((MarginLayoutParams) p);
} else {
@@ -1070,7 +1358,7 @@ public class Toolbar extends ViewGroup {
}
@Override
protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
protected LayoutParams generateDefaultLayoutParams() {
return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
}
@@ -1083,6 +1371,25 @@ public class Toolbar extends ViewGroup {
return ((LayoutParams) child.getLayoutParams()).mViewType == LayoutParams.CUSTOM;
}
/** @hide */
public DecorToolbar getWrapper() {
if (mWrapper == null) {
mWrapper = new ToolbarWidgetWrapper(this);
}
return mWrapper;
}
private void setChildVisibilityForExpandedActionView(boolean expand) {
final int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = getChildAt(i);
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
if (lp.mViewType != LayoutParams.EXPANDED && child != mMenuView) {
child.setVisibility(expand ? GONE : VISIBLE);
}
}
}
/**
* Interface responsible for receiving menu item click events if the items themselves
* do not have individual item click listeners.
@@ -1103,44 +1410,15 @@ public class Toolbar extends ViewGroup {
*
* @attr ref android.R.styleable#Toolbar_LayoutParams_layout_gravity
*/
public static class LayoutParams extends MarginLayoutParams {
/**
* Gravity for the view associated with these LayoutParams.
*
* @see android.view.Gravity
*/
@ViewDebug.ExportedProperty(category = "layout", mapping = {
@ViewDebug.IntToString(from = -1, to = "NONE"),
@ViewDebug.IntToString(from = Gravity.NO_GRAVITY, to = "NONE"),
@ViewDebug.IntToString(from = Gravity.TOP, to = "TOP"),
@ViewDebug.IntToString(from = Gravity.BOTTOM, to = "BOTTOM"),
@ViewDebug.IntToString(from = Gravity.LEFT, to = "LEFT"),
@ViewDebug.IntToString(from = Gravity.RIGHT, to = "RIGHT"),
@ViewDebug.IntToString(from = Gravity.START, to = "START"),
@ViewDebug.IntToString(from = Gravity.END, to = "END"),
@ViewDebug.IntToString(from = Gravity.CENTER_VERTICAL, to = "CENTER_VERTICAL"),
@ViewDebug.IntToString(from = Gravity.FILL_VERTICAL, to = "FILL_VERTICAL"),
@ViewDebug.IntToString(from = Gravity.CENTER_HORIZONTAL, to = "CENTER_HORIZONTAL"),
@ViewDebug.IntToString(from = Gravity.FILL_HORIZONTAL, to = "FILL_HORIZONTAL"),
@ViewDebug.IntToString(from = Gravity.CENTER, to = "CENTER"),
@ViewDebug.IntToString(from = Gravity.FILL, to = "FILL")
})
public int gravity = Gravity.NO_GRAVITY;
public static class LayoutParams extends ActionBar.LayoutParams {
static final int CUSTOM = 0;
static final int SYSTEM = 1;
static final int EXPANDED = 2;
int mViewType = CUSTOM;
public LayoutParams(@NonNull Context c, AttributeSet attrs) {
super(c, attrs);
TypedArray a = c.obtainStyledAttributes(attrs,
com.android.internal.R.styleable.Toolbar_LayoutParams);
gravity = a.getInt(
com.android.internal.R.styleable.Toolbar_LayoutParams_layout_gravity,
Gravity.NO_GRAVITY);
a.recycle();
}
public LayoutParams(int width, int height) {
@@ -1160,7 +1438,11 @@ public class Toolbar extends ViewGroup {
public LayoutParams(LayoutParams source) {
super(source);
this.gravity = source.gravity;
mViewType = source.mViewType;
}
public LayoutParams(ActionBar.LayoutParams source) {
super(source);
}
public LayoutParams(MarginLayoutParams source) {
@@ -1199,4 +1481,126 @@ public class Toolbar extends ViewGroup {
}
};
}
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) {
ensureCollapseButtonView();
if (mCollapseButtonView.getParent() != Toolbar.this) {
addView(mCollapseButtonView);
}
mExpandedActionView = item.getActionView();
mCurrentExpandedItem = item;
if (mExpandedActionView.getParent() != Toolbar.this) {
final LayoutParams lp = generateDefaultLayoutParams();
lp.gravity = Gravity.START | (mButtonGravity & Gravity.VERTICAL_GRAVITY_MASK);
lp.mViewType = LayoutParams.EXPANDED;
mExpandedActionView.setLayoutParams(lp);
addView(mExpandedActionView);
}
setChildVisibilityForExpandedActionView(true);
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(mCollapseButtonView);
mExpandedActionView = null;
setChildVisibilityForExpandedActionView(false);
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) {
}
}
}

View File

@@ -18,7 +18,10 @@ package com.android.internal.app;
import android.animation.ValueAnimator;
import android.content.res.TypedArray;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.AdapterView;
import android.widget.Toolbar;
import com.android.internal.R;
import com.android.internal.view.ActionBarPolicy;
import com.android.internal.view.menu.MenuBuilder;
@@ -28,6 +31,7 @@ import com.android.internal.widget.ActionBarContainer;
import com.android.internal.widget.ActionBarContextView;
import com.android.internal.widget.ActionBarOverlayLayout;
import com.android.internal.widget.ActionBarView;
import com.android.internal.widget.DecorToolbar;
import com.android.internal.widget.ScrollingTabContainerView;
import android.animation.Animator;
@@ -55,6 +59,7 @@ import android.view.Window;
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.AnimationUtils;
import android.widget.SpinnerAdapter;
import com.android.internal.widget.ToolbarWidgetWrapper;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
@@ -77,7 +82,7 @@ public class WindowDecorActionBar extends ActionBar implements
private ActionBarOverlayLayout mOverlayLayout;
private ActionBarContainer mContainerView;
private ActionBarView mActionView;
private DecorToolbar mDecorToolbar;
private ActionBarContextView mContextView;
private ActionBarContainer mSplitView;
private View mContentView;
@@ -187,7 +192,7 @@ public class WindowDecorActionBar extends ActionBar implements
if (mOverlayLayout != null) {
mOverlayLayout.setActionBarVisibilityCallback(this);
}
mActionView = (ActionBarView) decor.findViewById(com.android.internal.R.id.action_bar);
mDecorToolbar = getDecorToolbar(decor.findViewById(com.android.internal.R.id.action_bar));
mContextView = (ActionBarContextView) decor.findViewById(
com.android.internal.R.id.action_context_bar);
mContainerView = (ActionBarContainer) decor.findViewById(
@@ -195,18 +200,17 @@ public class WindowDecorActionBar extends ActionBar implements
mSplitView = (ActionBarContainer) decor.findViewById(
com.android.internal.R.id.split_action_bar);
if (mActionView == null || mContextView == null || mContainerView == null) {
if (mDecorToolbar == null || mContextView == null || mContainerView == null) {
throw new IllegalStateException(getClass().getSimpleName() + " can only be used " +
"with a compatible window decor layout");
}
mContext = mActionView.getContext();
mActionView.setContextView(mContextView);
mContextDisplayMode = mActionView.isSplitActionBar() ?
mContext = mDecorToolbar.getContext();
mContextDisplayMode = mDecorToolbar.isSplit() ?
CONTEXT_DISPLAY_SPLIT : CONTEXT_DISPLAY_NORMAL;
// This was initially read from the action bar style
final int current = mActionView.getDisplayOptions();
final int current = mDecorToolbar.getDisplayOptions();
final boolean homeAsUp = (current & DISPLAY_HOME_AS_UP) != 0;
if (homeAsUp) {
mDisplayHomeAsUpSet = true;
@@ -225,6 +229,17 @@ public class WindowDecorActionBar extends ActionBar implements
a.recycle();
}
private DecorToolbar getDecorToolbar(View view) {
if (view instanceof DecorToolbar) {
return (DecorToolbar) view;
} else if (view instanceof Toolbar) {
return ((Toolbar) view).getWrapper();
} else {
throw new IllegalStateException("Can't make a decor toolbar out of " +
view.getClass().getSimpleName());
}
}
public void onConfigurationChanged(Configuration newConfig) {
setHasEmbeddedTabs(ActionBarPolicy.get(mContext).hasEmbeddedTabs());
}
@@ -233,11 +248,11 @@ public class WindowDecorActionBar extends ActionBar implements
mHasEmbeddedTabs = hasEmbeddedTabs;
// Switch tab layout configuration if needed
if (!mHasEmbeddedTabs) {
mActionView.setEmbeddedTabView(null);
mDecorToolbar.setEmbeddedTabView(null);
mContainerView.setTabContainer(mTabScrollView);
} else {
mContainerView.setTabContainer(null);
mActionView.setEmbeddedTabView(mTabScrollView);
mDecorToolbar.setEmbeddedTabView(mTabScrollView);
}
final boolean isInTabMode = getNavigationMode() == NAVIGATION_MODE_TABS;
if (mTabScrollView != null) {
@@ -250,7 +265,7 @@ public class WindowDecorActionBar extends ActionBar implements
mTabScrollView.setVisibility(View.GONE);
}
}
mActionView.setCollapsable(!mHasEmbeddedTabs && isInTabMode);
mDecorToolbar.setCollapsible(!mHasEmbeddedTabs && isInTabMode);
mOverlayLayout.setHasNonEmbeddedTabs(!mHasEmbeddedTabs && isInTabMode);
}
@@ -263,7 +278,7 @@ public class WindowDecorActionBar extends ActionBar implements
if (mHasEmbeddedTabs) {
tabScroller.setVisibility(View.VISIBLE);
mActionView.setEmbeddedTabView(tabScroller);
mDecorToolbar.setEmbeddedTabView(tabScroller);
} else {
if (getNavigationMode() == NAVIGATION_MODE_TABS) {
tabScroller.setVisibility(View.VISIBLE);
@@ -326,7 +341,8 @@ public class WindowDecorActionBar extends ActionBar implements
@Override
public void setCustomView(int resId) {
setCustomView(LayoutInflater.from(getThemedContext()).inflate(resId, mActionView, false));
setCustomView(LayoutInflater.from(getThemedContext()).inflate(resId,
(ViewGroup) mDecorToolbar, false));
}
@Override
@@ -356,7 +372,7 @@ public class WindowDecorActionBar extends ActionBar implements
@Override
public void setHomeButtonEnabled(boolean enable) {
mActionView.setHomeButtonEnabled(enable);
mDecorToolbar.setHomeButtonEnabled(enable);
}
@Override
@@ -370,12 +386,12 @@ public class WindowDecorActionBar extends ActionBar implements
}
public void setSelectedNavigationItem(int position) {
switch (mActionView.getNavigationMode()) {
switch (mDecorToolbar.getNavigationMode()) {
case NAVIGATION_MODE_TABS:
selectTab(mTabs.get(position));
break;
case NAVIGATION_MODE_LIST:
mActionView.setDropdownSelectedPosition(position);
mDecorToolbar.setDropdownSelectedPosition(position);
break;
default:
throw new IllegalStateException(
@@ -399,26 +415,26 @@ public class WindowDecorActionBar extends ActionBar implements
}
public void setTitle(CharSequence title) {
mActionView.setTitle(title);
mDecorToolbar.setTitle(title);
}
public void setSubtitle(CharSequence subtitle) {
mActionView.setSubtitle(subtitle);
mDecorToolbar.setSubtitle(subtitle);
}
public void setDisplayOptions(int options) {
if ((options & DISPLAY_HOME_AS_UP) != 0) {
mDisplayHomeAsUpSet = true;
}
mActionView.setDisplayOptions(options);
mDecorToolbar.setDisplayOptions(options);
}
public void setDisplayOptions(int options, int mask) {
final int current = mActionView.getDisplayOptions();
final int current = mDecorToolbar.getDisplayOptions();
if ((mask & DISPLAY_HOME_AS_UP) != 0) {
mDisplayHomeAsUpSet = true;
}
mActionView.setDisplayOptions((options & mask) | (current & ~mask));
mDecorToolbar.setDisplayOptions((options & mask) | (current & ~mask));
}
public void setBackgroundDrawable(Drawable d) {
@@ -436,23 +452,23 @@ public class WindowDecorActionBar extends ActionBar implements
}
public View getCustomView() {
return mActionView.getCustomNavigationView();
return mDecorToolbar.getCustomView();
}
public CharSequence getTitle() {
return mActionView.getTitle();
return mDecorToolbar.getTitle();
}
public CharSequence getSubtitle() {
return mActionView.getSubtitle();
return mDecorToolbar.getSubtitle();
}
public int getNavigationMode() {
return mActionView.getNavigationMode();
return mDecorToolbar.getNavigationMode();
}
public int getDisplayOptions() {
return mActionView.getDisplayOptions();
return mDecorToolbar.getDisplayOptions();
}
public ActionMode startActionMode(ActionMode.Callback callback) {
@@ -572,7 +588,7 @@ public class WindowDecorActionBar extends ActionBar implements
return;
}
final FragmentTransaction trans = mActionView.isInEditMode() ? null :
final FragmentTransaction trans = ((View) mDecorToolbar).isInEditMode() ? null :
mActivity.getFragmentManager().beginTransaction().disallowAddToBackStack();
if (mSelectedTab == tab) {
@@ -828,13 +844,18 @@ public class WindowDecorActionBar extends ActionBar implements
hideForActionMode();
}
mActionView.animateToVisibility(toActionMode ? View.GONE : View.VISIBLE);
mDecorToolbar.animateToVisibility(toActionMode ? View.GONE : View.VISIBLE);
mContextView.animateToVisibility(toActionMode ? View.VISIBLE : View.GONE);
if (mTabScrollView != null && !mActionView.hasEmbeddedTabs() && mActionView.isCollapsed()) {
if (mTabScrollView != null && !mDecorToolbar.hasEmbeddedTabs() &&
isCollapsed((View) mDecorToolbar)) {
mTabScrollView.animateToVisibility(toActionMode ? View.GONE : View.VISIBLE);
}
}
private boolean isCollapsed(View view) {
return view == null || view.getVisibility() == View.GONE || view.getMeasuredHeight() == 0;
}
public Context getThemedContext() {
if (mThemedContext == null) {
TypedValue outValue = new TypedValue();
@@ -854,27 +875,27 @@ public class WindowDecorActionBar extends ActionBar implements
@Override
public boolean isTitleTruncated() {
return mActionView != null && mActionView.isTitleTruncated();
return mDecorToolbar != null && mDecorToolbar.isTitleTruncated();
}
@Override
public void setHomeAsUpIndicator(Drawable indicator) {
mActionView.setHomeAsUpIndicator(indicator);
mDecorToolbar.setNavigationIcon(indicator);
}
@Override
public void setHomeAsUpIndicator(int resId) {
mActionView.setHomeAsUpIndicator(resId);
mDecorToolbar.setNavigationIcon(resId);
}
@Override
public void setHomeActionContentDescription(CharSequence description) {
mActionView.setHomeActionContentDescription(description);
mDecorToolbar.setNavigationContentDescription(description);
}
@Override
public void setHomeActionContentDescription(int resId) {
mActionView.setHomeActionContentDescription(resId);
mDecorToolbar.setNavigationContentDescription(resId);
}
@Override
@@ -938,7 +959,8 @@ public class WindowDecorActionBar extends ActionBar implements
// Clear out the context mode views after the animation finishes
mContextView.closeMode();
mActionView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
((View) mDecorToolbar).sendAccessibilityEvent(
AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
mOverlayLayout.setHideOnContentScrollEnabled(mHideOnContentScroll);
mActionMode = null;
@@ -1178,28 +1200,27 @@ public class WindowDecorActionBar extends ActionBar implements
@Override
public void setCustomView(View view) {
mActionView.setCustomNavigationView(view);
mDecorToolbar.setCustomView(view);
}
@Override
public void setCustomView(View view, LayoutParams layoutParams) {
view.setLayoutParams(layoutParams);
mActionView.setCustomNavigationView(view);
mDecorToolbar.setCustomView(view);
}
@Override
public void setListNavigationCallbacks(SpinnerAdapter adapter, OnNavigationListener callback) {
mActionView.setDropdownAdapter(adapter);
mActionView.setCallback(callback);
mDecorToolbar.setDropdownParams(adapter, new NavItemSelectedListener(callback));
}
@Override
public int getSelectedNavigationIndex() {
switch (mActionView.getNavigationMode()) {
switch (mDecorToolbar.getNavigationMode()) {
case NAVIGATION_MODE_TABS:
return mSelectedTab != null ? mSelectedTab.getPosition() : -1;
case NAVIGATION_MODE_LIST:
return mActionView.getDropdownSelectedPosition();
return mDecorToolbar.getDropdownSelectedPosition();
default:
return -1;
}
@@ -1207,12 +1228,11 @@ public class WindowDecorActionBar extends ActionBar implements
@Override
public int getNavigationItemCount() {
switch (mActionView.getNavigationMode()) {
switch (mDecorToolbar.getNavigationMode()) {
case NAVIGATION_MODE_TABS:
return mTabs.size();
case NAVIGATION_MODE_LIST:
SpinnerAdapter adapter = mActionView.getDropdownAdapter();
return adapter != null ? adapter.getCount() : 0;
return mDecorToolbar.getDropdownItemCount();
default:
return 0;
}
@@ -1225,7 +1245,7 @@ public class WindowDecorActionBar extends ActionBar implements
@Override
public void setNavigationMode(int mode) {
final int oldMode = mActionView.getNavigationMode();
final int oldMode = mDecorToolbar.getNavigationMode();
switch (oldMode) {
case NAVIGATION_MODE_TABS:
mSavedTabPosition = getSelectedNavigationIndex();
@@ -1238,7 +1258,7 @@ public class WindowDecorActionBar extends ActionBar implements
mOverlayLayout.requestFitSystemWindows();
}
}
mActionView.setNavigationMode(mode);
mDecorToolbar.setNavigationMode(mode);
switch (mode) {
case NAVIGATION_MODE_TABS:
ensureTabsExist();
@@ -1249,7 +1269,7 @@ public class WindowDecorActionBar extends ActionBar implements
}
break;
}
mActionView.setCollapsable(mode == NAVIGATION_MODE_TABS && !mHasEmbeddedTabs);
mDecorToolbar.setCollapsible(mode == NAVIGATION_MODE_TABS && !mHasEmbeddedTabs);
mOverlayLayout.setHasNonEmbeddedTabs(mode == NAVIGATION_MODE_TABS && !mHasEmbeddedTabs);
}
@@ -1261,30 +1281,30 @@ public class WindowDecorActionBar extends ActionBar implements
@Override
public void setIcon(int resId) {
mActionView.setIcon(resId);
mDecorToolbar.setIcon(resId);
}
@Override
public void setIcon(Drawable icon) {
mActionView.setIcon(icon);
mDecorToolbar.setIcon(icon);
}
public boolean hasIcon() {
return mActionView.hasIcon();
return mDecorToolbar.hasIcon();
}
@Override
public void setLogo(int resId) {
mActionView.setLogo(resId);
mDecorToolbar.setLogo(resId);
}
@Override
public void setLogo(Drawable logo) {
mActionView.setLogo(logo);
mDecorToolbar.setLogo(logo);
}
public boolean hasLogo() {
return mActionView.hasLogo();
return mDecorToolbar.hasLogo();
}
public void setDefaultDisplayHomeAsUpEnabled(boolean enable) {
@@ -1292,4 +1312,24 @@ public class WindowDecorActionBar extends ActionBar implements
setDisplayHomeAsUpEnabled(enable);
}
}
static class NavItemSelectedListener implements AdapterView.OnItemSelectedListener {
private final OnNavigationListener mListener;
public NavItemSelectedListener(OnNavigationListener listener) {
mListener = listener;
}
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if (mListener != null) {
mListener.onNavigationItemSelected(position, id);
}
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
// Do nothing
}
}
}

View File

@@ -34,7 +34,7 @@ import android.view.animation.DecelerateInterpolator;
public abstract class AbsActionBarView extends ViewGroup {
protected ActionMenuView mMenuView;
protected ActionMenuPresenter mActionMenuPresenter;
protected ActionBarContainer mSplitView;
protected ViewGroup mSplitView;
protected boolean mSplitActionBar;
protected boolean mSplitWhenNarrow;
protected int mContentHeight;
@@ -74,7 +74,7 @@ public abstract class AbsActionBarView extends ViewGroup {
setContentHeight(a.getLayoutDimension(R.styleable.ActionBar_height, 0));
a.recycle();
if (mSplitWhenNarrow) {
setSplitActionBar(getContext().getResources().getBoolean(
setSplitToolbar(getContext().getResources().getBoolean(
com.android.internal.R.bool.split_action_bar_is_narrow));
}
if (mActionMenuPresenter != null) {
@@ -86,7 +86,7 @@ public abstract class AbsActionBarView extends ViewGroup {
* Sets whether the bar should be split right now, no questions asked.
* @param split true if the bar should split
*/
public void setSplitActionBar(boolean split) {
public void setSplitToolbar(boolean split) {
mSplitActionBar = split;
}
@@ -107,7 +107,7 @@ public abstract class AbsActionBarView extends ViewGroup {
return mContentHeight;
}
public void setSplitView(ActionBarContainer splitView) {
public void setSplitView(ViewGroup splitView) {
mSplitView = splitView;
}
@@ -214,6 +214,10 @@ public abstract class AbsActionBarView extends ViewGroup {
return mActionMenuPresenter != null && mActionMenuPresenter.isOverflowReserved();
}
public boolean canShowOverflowMenu() {
return isOverflowReserved() && getVisibility() == VISIBLE;
}
public void dismissPopupMenus() {
if (mActionMenuPresenter != null) {
mActionMenuPresenter.dismissPopupMenus();

View File

@@ -36,7 +36,7 @@ import android.widget.FrameLayout;
public class ActionBarContainer extends FrameLayout {
private boolean mIsTransitioning;
private View mTabContainer;
private ActionBarView mActionBarView;
private View mActionBarView;
private Drawable mBackground;
private Drawable mStackedBackground;
@@ -76,7 +76,7 @@ public class ActionBarContainer extends FrameLayout {
@Override
public void onFinishInflate() {
super.onFinishInflate();
mActionBarView = (ActionBarView) findViewById(com.android.internal.R.id.action_bar);
mActionBarView = findViewById(com.android.internal.R.id.action_bar);
}
public void setPrimaryBackground(Drawable bg) {
@@ -251,6 +251,10 @@ public class ActionBarContainer extends FrameLayout {
return null;
}
private boolean isCollapsed(View view) {
return view == null || view.getVisibility() == GONE || view.getMeasuredHeight() == 0;
}
@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (mActionBarView == null &&
@@ -263,7 +267,7 @@ public class ActionBarContainer extends FrameLayout {
if (mActionBarView == null) return;
final LayoutParams lp = (LayoutParams) mActionBarView.getLayoutParams();
final int actionBarViewHeight = mActionBarView.isCollapsed() ? 0 :
final int actionBarViewHeight = isCollapsed(mActionBarView) ? 0 :
mActionBarView.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;
if (mTabContainer != null && mTabContainer.getVisibility() != GONE) {
@@ -298,9 +302,8 @@ public class ActionBarContainer extends FrameLayout {
}
} else {
if (mBackground != null) {
final ActionBarView actionBarView = mActionBarView;
mBackground.setBounds(actionBarView.getLeft(), actionBarView.getTop(),
actionBarView.getRight(), actionBarView.getBottom());
mBackground.setBounds(mActionBarView.getLeft(), mActionBarView.getTop(),
mActionBarView.getRight(), mActionBarView.getBottom());
needsInvalidate = true;
}
mIsStacked = hasTabs;

View File

@@ -83,7 +83,7 @@ public class ActionBarContextView extends AbsActionBarView implements AnimatorLi
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.ActionMode, defStyleAttr, defStyleRes);
setBackgroundDrawable(a.getDrawable(
setBackground(a.getDrawable(
com.android.internal.R.styleable.ActionMode_background));
mTitleStyleRes = a.getResourceId(
com.android.internal.R.styleable.ActionMode_titleTextStyle, 0);
@@ -109,7 +109,7 @@ public class ActionBarContextView extends AbsActionBarView implements AnimatorLi
}
@Override
public void setSplitActionBar(boolean split) {
public void setSplitToolbar(boolean split) {
if (mSplitActionBar != split) {
if (mActionMenuPresenter != null) {
// Mode is already active; move everything over and adjust the menu itself.
@@ -137,7 +137,7 @@ public class ActionBarContextView extends AbsActionBarView implements AnimatorLi
mSplitView.addView(mMenuView, layoutParams);
}
}
super.setSplitActionBar(split);
super.setSplitToolbar(split);
}
}

View File

@@ -39,6 +39,7 @@ import android.view.ViewPropertyAnimator;
import android.view.Window;
import android.view.WindowInsets;
import android.widget.OverScroller;
import android.widget.Toolbar;
import com.android.internal.view.menu.MenuPresenter;
/**
@@ -59,7 +60,7 @@ public class ActionBarOverlayLayout extends ViewGroup implements DecorContentPar
private ActionBarContainer mActionBarTop;
// Some interior UI elements.
private ActionBarView mActionBarView;
private DecorToolbar mDecorToolbar;
// Content overlay drawable - generally the action bar's shadow
private Drawable mWindowContentOverlay;
@@ -401,7 +402,7 @@ public class ActionBarOverlayLayout extends ViewGroup implements DecorContentPar
topInset = mActionBarTop.getMeasuredHeight();
}
if (mActionBarView.isSplitActionBar()) {
if (mDecorToolbar.isSplit()) {
// If action bar is split, adjust bottom insets for it.
if (mActionBarBottom != null) {
if (stable) {
@@ -563,12 +564,23 @@ public class ActionBarOverlayLayout extends ViewGroup implements DecorContentPar
mContent = findViewById(com.android.internal.R.id.content);
mActionBarTop = (ActionBarContainer) findViewById(
com.android.internal.R.id.action_bar_container);
mActionBarView = (ActionBarView) findViewById(com.android.internal.R.id.action_bar);
mDecorToolbar = getDecorToolbar(findViewById(com.android.internal.R.id.action_bar));
mActionBarBottom = (ActionBarContainer) findViewById(
com.android.internal.R.id.split_action_bar);
}
}
private DecorToolbar getDecorToolbar(View view) {
if (view instanceof DecorToolbar) {
return (DecorToolbar) view;
} else if (view instanceof Toolbar) {
return ((Toolbar) view).getWrapper();
} else {
throw new IllegalStateException("Can't make a decor toolbar out of " +
view.getClass().getSimpleName());
}
}
public void setHideOnContentScrollEnabled(boolean hideOnContentScroll) {
if (hideOnContentScroll != mHideOnContentScroll) {
mHideOnContentScroll = hideOnContentScroll;
@@ -648,9 +660,9 @@ public class ActionBarOverlayLayout extends ViewGroup implements DecorContentPar
final int action = event.getAction();
// Collapse any expanded action views.
if (mActionBarView != null && mActionBarView.hasExpandedActionView()) {
if (mDecorToolbar != null && mDecorToolbar.hasExpandedActionView()) {
if (action == KeyEvent.ACTION_UP) {
mActionBarView.collapseActionView();
mDecorToolbar.collapseActionView();
}
return true;
}
@@ -662,19 +674,19 @@ public class ActionBarOverlayLayout extends ViewGroup implements DecorContentPar
@Override
public void setWindowCallback(Window.Callback cb) {
pullChildren();
mActionBarView.setWindowCallback(cb);
mDecorToolbar.setWindowCallback(cb);
}
@Override
public void setWindowTitle(CharSequence title) {
pullChildren();
mActionBarView.setWindowTitle(title);
mDecorToolbar.setWindowTitle(title);
}
@Override
public CharSequence getTitle() {
pullChildren();
return mActionBarView.getTitle();
return mDecorToolbar.getTitle();
}
@Override
@@ -682,10 +694,10 @@ public class ActionBarOverlayLayout extends ViewGroup implements DecorContentPar
pullChildren();
switch (windowFeature) {
case Window.FEATURE_PROGRESS:
mActionBarView.initProgress();
mDecorToolbar.initProgress();
break;
case Window.FEATURE_INDETERMINATE_PROGRESS:
mActionBarView.initIndeterminateProgress();
mDecorToolbar.initIndeterminateProgress();
break;
case Window.FEATURE_ACTION_BAR_OVERLAY:
setOverlayMode(true);
@@ -704,15 +716,15 @@ public class ActionBarOverlayLayout extends ViewGroup implements DecorContentPar
}
if (splitActionBar) {
pullChildren();
if (mActionBarBottom != null) {
mActionBarView.setSplitView(mActionBarBottom);
mActionBarView.setSplitActionBar(splitActionBar);
mActionBarView.setSplitWhenNarrow(splitWhenNarrow);
if (mActionBarBottom != null && mDecorToolbar.canSplit()) {
mDecorToolbar.setSplitView(mActionBarBottom);
mDecorToolbar.setSplitToolbar(splitActionBar);
mDecorToolbar.setSplitWhenNarrow(splitWhenNarrow);
final ActionBarContextView cab = (ActionBarContextView) findViewById(
com.android.internal.R.id.action_context_bar);
cab.setSplitView(mActionBarBottom);
cab.setSplitActionBar(splitActionBar);
cab.setSplitToolbar(splitActionBar);
cab.setSplitWhenNarrow(splitWhenNarrow);
} else if (splitActionBar) {
Log.e(TAG, "Requested split action bar with " +
@@ -724,91 +736,91 @@ public class ActionBarOverlayLayout extends ViewGroup implements DecorContentPar
@Override
public boolean hasIcon() {
pullChildren();
return mActionBarView.hasIcon();
return mDecorToolbar.hasIcon();
}
@Override
public boolean hasLogo() {
pullChildren();
return mActionBarView.hasLogo();
return mDecorToolbar.hasLogo();
}
@Override
public void setIcon(int resId) {
pullChildren();
mActionBarView.setIcon(resId);
mDecorToolbar.setIcon(resId);
}
@Override
public void setIcon(Drawable d) {
pullChildren();
mActionBarView.setIcon(d);
mDecorToolbar.setIcon(d);
}
@Override
public void setLogo(int resId) {
pullChildren();
mActionBarView.setLogo(resId);
mDecorToolbar.setLogo(resId);
}
@Override
public boolean canShowOverflowMenu() {
pullChildren();
return mActionBarView.isOverflowReserved() && mActionBarView.getVisibility() == VISIBLE;
return mDecorToolbar.canShowOverflowMenu();
}
@Override
public boolean isOverflowMenuShowing() {
pullChildren();
return mActionBarView.isOverflowMenuShowing();
return mDecorToolbar.isOverflowMenuShowing();
}
@Override
public boolean isOverflowMenuShowPending() {
pullChildren();
return mActionBarView.isOverflowMenuShowPending();
return mDecorToolbar.isOverflowMenuShowPending();
}
@Override
public boolean showOverflowMenu() {
pullChildren();
return mActionBarView.showOverflowMenu();
return mDecorToolbar.showOverflowMenu();
}
@Override
public boolean hideOverflowMenu() {
pullChildren();
return mActionBarView.hideOverflowMenu();
return mDecorToolbar.hideOverflowMenu();
}
@Override
public void setMenuPrepared() {
pullChildren();
mActionBarView.setMenuPrepared();
mDecorToolbar.setMenuPrepared();
}
@Override
public void setMenu(Menu menu, MenuPresenter.Callback cb) {
pullChildren();
mActionBarView.setMenu(menu, cb);
mDecorToolbar.setMenu(menu, cb);
}
@Override
public void saveToolbarHierarchyState(SparseArray<Parcelable> toolbarStates) {
pullChildren();
mActionBarView.saveHierarchyState(toolbarStates);
mDecorToolbar.saveHierarchyState(toolbarStates);
}
@Override
public void restoreToolbarHierarchyState(SparseArray<Parcelable> toolbarStates) {
pullChildren();
mActionBarView.restoreHierarchyState(toolbarStates);
mDecorToolbar.restoreHierarchyState(toolbarStates);
}
@Override
public void dismissPopups() {
pullChildren();
mActionBarView.dismissPopupMenus();
mDecorToolbar.dismissPopupMenus();
}
public static class LayoutParams extends MarginLayoutParams {

View File

@@ -18,7 +18,6 @@ package com.android.internal.widget;
import android.animation.LayoutTransition;
import android.app.ActionBar;
import android.app.ActionBar.OnNavigationListener;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
@@ -63,7 +62,7 @@ import com.android.internal.view.menu.SubMenuBuilder;
/**
* @hide
*/
public class ActionBarView extends AbsActionBarView {
public class ActionBarView extends AbsActionBarView implements DecorToolbar {
private static final String TAG = "ActionBarView";
/**
@@ -117,8 +116,7 @@ public class ActionBarView extends AbsActionBarView {
private boolean mUserTitle;
private boolean mIncludeTabs;
private boolean mIsCollapsable;
private boolean mIsCollapsed;
private boolean mIsCollapsible;
private boolean mWasHomeEnabled; // Was it enabled before action view expansion?
private MenuBuilder mOptionsMenu;
@@ -129,7 +127,7 @@ public class ActionBarView extends AbsActionBarView {
private ActionMenuItem mLogoNavItem;
private SpinnerAdapter mSpinnerAdapter;
private OnNavigationListener mCallback;
private AdapterView.OnItemSelectedListener mNavItemSelectedListener;
private Runnable mTabSelector;
@@ -138,18 +136,6 @@ public class ActionBarView extends AbsActionBarView {
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) {
@@ -178,8 +164,6 @@ public class ActionBarView extends AbsActionBarView {
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);
@@ -260,7 +244,7 @@ public class ActionBarView extends AbsActionBarView {
}
if (mHomeDescriptionRes != 0) {
setHomeActionContentDescription(mHomeDescriptionRes);
setNavigationContentDescription(mHomeDescriptionRes);
}
if (mTabScrollView != null && mIncludeTabs) {
@@ -313,7 +297,7 @@ public class ActionBarView extends AbsActionBarView {
}
@Override
public void setSplitActionBar(boolean splitActionBar) {
public void setSplitToolbar(boolean splitActionBar) {
if (mSplitActionBar != splitActionBar) {
if (mMenuView != null) {
final ViewGroup oldParent = (ViewGroup) mMenuView.getParent();
@@ -349,18 +333,26 @@ public class ActionBarView extends AbsActionBarView {
mActionMenuPresenter.setItemLimit(Integer.MAX_VALUE);
}
}
super.setSplitActionBar(splitActionBar);
super.setSplitToolbar(splitActionBar);
}
}
public boolean isSplitActionBar() {
public boolean isSplit() {
return mSplitActionBar;
}
public boolean canSplit() {
return true;
}
public boolean hasEmbeddedTabs() {
return mIncludeTabs;
}
public void setEmbeddedTabView(View view) {
setEmbeddedTabView((ScrollingTabContainerView) view);
}
public void setEmbeddedTabView(ScrollingTabContainerView tabs) {
if (mTabScrollView != null) {
removeView(mTabScrollView);
@@ -376,10 +368,6 @@ public class ActionBarView extends AbsActionBarView {
}
}
public void setCallback(OnNavigationListener callback) {
mCallback = callback;
}
public void setMenuPrepared() {
mMenuPrepared = true;
}
@@ -473,7 +461,7 @@ public class ActionBarView extends AbsActionBarView {
}
}
public void setCustomNavigationView(View view) {
public void setCustomView(View view) {
final boolean showCustom = (mDisplayOptions & ActionBar.DISPLAY_SHOW_CUSTOM) != 0;
if (showCustom) {
ActionBarTransition.beginDelayedTransition(this);
@@ -765,15 +753,16 @@ public class ActionBarView extends AbsActionBarView {
}
}
public void setDropdownAdapter(SpinnerAdapter adapter) {
public void setDropdownParams(SpinnerAdapter adapter, AdapterView.OnItemSelectedListener l) {
mSpinnerAdapter = adapter;
mNavItemSelectedListener = l;
if (mSpinner != null) {
mSpinner.setAdapter(adapter);
}
}
public SpinnerAdapter getDropdownAdapter() {
return mSpinnerAdapter;
public int getDropdownItemCount() {
return mSpinnerAdapter != null ? mSpinnerAdapter.getCount() : 0;
}
public void setDropdownSelectedPosition(int position) {
@@ -784,7 +773,7 @@ public class ActionBarView extends AbsActionBarView {
return mSpinner.getSelectedItemPosition();
}
public View getCustomNavigationView() {
public View getCustomView() {
return mCustomNavView;
}
@@ -796,6 +785,11 @@ public class ActionBarView extends AbsActionBarView {
return mDisplayOptions;
}
@Override
public ViewGroup getViewGroup() {
return this;
}
@Override
protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
// Used by custom nav views if they don't supply layout params. Everything else
@@ -860,12 +854,8 @@ public class ActionBarView extends AbsActionBarView {
mContextView = view;
}
public void setCollapsable(boolean collapsable) {
mIsCollapsable = collapsable;
}
public boolean isCollapsed() {
return mIsCollapsed;
public void setCollapsible(boolean collapsible) {
mIsCollapsible = collapsible;
}
/**
@@ -893,7 +883,7 @@ public class ActionBarView extends AbsActionBarView {
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int childCount = getChildCount();
if (mIsCollapsable) {
if (mIsCollapsible) {
int visibleChildren = 0;
for (int i = 0; i < childCount; i++) {
final View child = getChildAt(i);
@@ -915,11 +905,9 @@ public class ActionBarView extends AbsActionBarView {
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) {
@@ -1323,20 +1311,20 @@ public class ActionBarView extends AbsActionBarView {
}
}
public void setHomeAsUpIndicator(Drawable indicator) {
public void setNavigationIcon(Drawable indicator) {
mHomeLayout.setUpIndicator(indicator);
}
public void setHomeAsUpIndicator(int resId) {
public void setNavigationIcon(int resId) {
mHomeLayout.setUpIndicator(resId);
}
public void setHomeActionContentDescription(CharSequence description) {
public void setNavigationContentDescription(CharSequence description) {
mHomeDescription = description;
updateHomeAccessibility(mUpGoerFive.isEnabled());
}
public void setHomeActionContentDescription(int resId) {
public void setNavigationContentDescription(int resId) {
mHomeDescriptionRes = resId;
mHomeDescription = resId != 0 ? getResources().getText(resId) : null;
updateHomeAccessibility(mUpGoerFive.isEnabled());

View File

@@ -0,0 +1,94 @@
/*
* Copyright (C) 2014 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 android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.Parcelable;
import android.util.SparseArray;
import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.AdapterView;
import android.widget.SpinnerAdapter;
import com.android.internal.view.menu.MenuPresenter;
/**
* Common interface for a toolbar that sits as part of the window decor.
* Layouts that control window decor use this as a point of interaction with different
* bar implementations.
*
* @hide
*/
public interface DecorToolbar {
ViewGroup getViewGroup();
Context getContext();
boolean isSplit();
boolean hasExpandedActionView();
void collapseActionView();
void setWindowCallback(Window.Callback cb);
void setWindowTitle(CharSequence title);
CharSequence getTitle();
void setTitle(CharSequence title);
CharSequence getSubtitle();
void setSubtitle(CharSequence subtitle);
void initProgress();
void initIndeterminateProgress();
boolean canSplit();
void setSplitView(ViewGroup splitView);
void setSplitToolbar(boolean split);
void setSplitWhenNarrow(boolean splitWhenNarrow);
boolean hasIcon();
boolean hasLogo();
void setIcon(int resId);
void setIcon(Drawable d);
void setLogo(int resId);
void setLogo(Drawable d);
boolean canShowOverflowMenu();
boolean isOverflowMenuShowing();
boolean isOverflowMenuShowPending();
boolean showOverflowMenu();
boolean hideOverflowMenu();
void setMenuPrepared();
void setMenu(Menu menu, MenuPresenter.Callback cb);
void dismissPopupMenus();
int getDisplayOptions();
void setDisplayOptions(int opts);
void setEmbeddedTabView(View tabView);
boolean hasEmbeddedTabs();
boolean isTitleTruncated();
void setCollapsible(boolean collapsible);
void setHomeButtonEnabled(boolean enable);
int getNavigationMode();
void setNavigationMode(int mode);
void setDropdownParams(SpinnerAdapter adapter, AdapterView.OnItemSelectedListener listener);
void setDropdownSelectedPosition(int position);
int getDropdownSelectedPosition();
int getDropdownItemCount();
void setCustomView(View view);
View getCustomView();
void animateToVisibility(int visibility);
void setNavigationIcon(Drawable icon);
void setNavigationIcon(int resId);
void setNavigationContentDescription(CharSequence description);
void setNavigationContentDescription(int resId);
void saveHierarchyState(SparseArray<Parcelable> toolbarStates);
void restoreHierarchyState(SparseArray<Parcelable> toolbarStates);
}

View File

@@ -0,0 +1,526 @@
/*
* Copyright (C) 2014 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 android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.app.ActionBar;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.os.Parcelable;
import android.util.Log;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.ActionMenuPresenter;
import android.widget.AdapterView;
import android.widget.Spinner;
import android.widget.SpinnerAdapter;
import android.widget.Toolbar;
import com.android.internal.R;
import com.android.internal.view.menu.ActionMenuItem;
import com.android.internal.view.menu.MenuBuilder;
import com.android.internal.view.menu.MenuPresenter;
/**
* Internal class used to interact with the Toolbar widget without
* exposing interface methods to the public API.
*
* <p>ToolbarWidgetWrapper manages the differences between Toolbar and ActionBarView
* so that either variant acting as a
* {@link com.android.internal.app.WindowDecorActionBar WindowDecorActionBar} can behave
* in the same way.</p>
*
* @hide
*/
public class ToolbarWidgetWrapper implements DecorToolbar {
private static final String TAG = "ToolbarWidgetWrapper";
private static final int AFFECTS_LOGO_MASK =
ActionBar.DISPLAY_SHOW_HOME | ActionBar.DISPLAY_USE_LOGO;
private Toolbar mToolbar;
private int mDisplayOpts;
private View mTabView;
private Spinner mSpinner;
private View mCustomView;
private Drawable mIcon;
private Drawable mLogo;
private Drawable mNavIcon;
private boolean mTitleSet;
private CharSequence mTitle;
private CharSequence mSubtitle;
private Window.Callback mWindowCallback;
private boolean mMenuPrepared;
private ActionMenuPresenter mActionMenuPresenter;
public ToolbarWidgetWrapper(Toolbar toolbar) {
mToolbar = toolbar;
final TypedArray a = toolbar.getContext().obtainStyledAttributes(null,
R.styleable.ActionBar, R.attr.actionBarStyle, 0);
final CharSequence title = a.getText(R.styleable.ActionBar_title);
if (title != null) {
setTitle(title);
}
final CharSequence subtitle = a.getText(R.styleable.ActionBar_subtitle);
if (subtitle != null) {
setSubtitle(subtitle);
}
final Drawable logo = a.getDrawable(R.styleable.ActionBar_logo);
if (logo != null) {
setLogo(logo);
}
final Drawable icon = a.getDrawable(R.styleable.ActionBar_icon);
if (icon != null) {
setIcon(icon);
}
final Drawable navIcon = a.getDrawable(R.styleable.ActionBar_homeAsUpIndicator);
if (navIcon != null) {
setNavigationIcon(navIcon);
}
setDisplayOptions(a.getInt(R.styleable.ActionBar_displayOptions, 0));
final int customNavId = a.getResourceId(R.styleable.ActionBar_customNavigationLayout, 0);
if (customNavId != 0) {
setCustomView(LayoutInflater.from(mToolbar.getContext()).inflate(customNavId,
mToolbar, false));
setDisplayOptions(mDisplayOpts | ActionBar.DISPLAY_SHOW_CUSTOM);
}
final int height = a.getLayoutDimension(R.styleable.ActionBar_height, 0);
if (height > 0) {
final ViewGroup.LayoutParams lp = mToolbar.getLayoutParams();
lp.height = height;
mToolbar.setLayoutParams(lp);
}
final int contentInsetStart = a.getDimensionPixelOffset(
R.styleable.ActionBar_contentInsetStart, 0);
final int contentInsetEnd = a.getDimensionPixelOffset(
R.styleable.ActionBar_contentInsetEnd, 0);
if (contentInsetStart > 0 || contentInsetEnd > 0) {
mToolbar.setContentInsetsRelative(contentInsetStart, contentInsetEnd);
}
a.recycle();
mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
final ActionMenuItem mNavItem = new ActionMenuItem(mToolbar.getContext(),
0, android.R.id.home, 0, 0, mTitle);
@Override
public void onClick(View v) {
if (mWindowCallback != null && mMenuPrepared) {
mWindowCallback.onMenuItemSelected(Window.FEATURE_OPTIONS_PANEL, mNavItem);
}
}
});
}
@Override
public ViewGroup getViewGroup() {
return mToolbar;
}
@Override
public Context getContext() {
return mToolbar.getContext();
}
@Override
public boolean isSplit() {
return false;
}
@Override
public boolean hasExpandedActionView() {
return mToolbar.hasExpandedActionView();
}
@Override
public void collapseActionView() {
mToolbar.collapseActionView();
}
@Override
public void setWindowCallback(Window.Callback cb) {
mWindowCallback = cb;
}
@Override
public void setWindowTitle(CharSequence title) {
// "Real" title always trumps window title.
if (!mTitleSet) {
setTitleInt(title);
}
}
@Override
public CharSequence getTitle() {
return mToolbar.getTitle();
}
@Override
public void setTitle(CharSequence title) {
mTitleSet = true;
setTitleInt(title);
}
private void setTitleInt(CharSequence title) {
mTitle = title;
if ((mDisplayOpts & ActionBar.DISPLAY_SHOW_TITLE) != 0) {
mToolbar.setTitle(title);
}
}
@Override
public CharSequence getSubtitle() {
return mToolbar.getSubtitle();
}
@Override
public void setSubtitle(CharSequence subtitle) {
mSubtitle = subtitle;
if ((mDisplayOpts & ActionBar.DISPLAY_SHOW_TITLE) != 0) {
mToolbar.setSubtitle(subtitle);
}
}
@Override
public void initProgress() {
Log.i(TAG, "Progress display unsupported");
}
@Override
public void initIndeterminateProgress() {
Log.i(TAG, "Progress display unsupported");
}
@Override
public boolean canSplit() {
return false;
}
@Override
public void setSplitView(ViewGroup splitView) {
}
@Override
public void setSplitToolbar(boolean split) {
if (split) {
throw new UnsupportedOperationException("Cannot split an android.widget.Toolbar");
}
}
@Override
public void setSplitWhenNarrow(boolean splitWhenNarrow) {
// Ignore.
}
@Override
public boolean hasIcon() {
return mIcon != null;
}
@Override
public boolean hasLogo() {
return mLogo != null;
}
@Override
public void setIcon(int resId) {
setIcon(resId != 0 ? getContext().getDrawable(resId) : null);
}
@Override
public void setIcon(Drawable d) {
mIcon = d;
updateToolbarLogo();
}
@Override
public void setLogo(int resId) {
setLogo(resId != 0 ? getContext().getDrawable(resId) : null);
}
@Override
public void setLogo(Drawable d) {
mLogo = d;
updateToolbarLogo();
}
private void updateToolbarLogo() {
Drawable logo = null;
if ((mDisplayOpts & ActionBar.DISPLAY_SHOW_HOME) != 0) {
if ((mDisplayOpts & ActionBar.DISPLAY_USE_LOGO) != 0) {
logo = mLogo != null ? mLogo : mIcon;
} else {
logo = mIcon;
}
}
mToolbar.setLogo(logo);
}
@Override
public boolean canShowOverflowMenu() {
return mToolbar.canShowOverflowMenu();
}
@Override
public boolean isOverflowMenuShowing() {
return mToolbar.isOverflowMenuShowing();
}
@Override
public boolean isOverflowMenuShowPending() {
return mToolbar.isOverflowMenuShowPending();
}
@Override
public boolean showOverflowMenu() {
return mToolbar.showOverflowMenu();
}
@Override
public boolean hideOverflowMenu() {
return mToolbar.hideOverflowMenu();
}
@Override
public void setMenuPrepared() {
mMenuPrepared = true;
}
@Override
public void setMenu(Menu menu, MenuPresenter.Callback cb) {
if (mActionMenuPresenter == null) {
mActionMenuPresenter = new ActionMenuPresenter(mToolbar.getContext());
mActionMenuPresenter.setId(com.android.internal.R.id.action_menu_presenter);
}
mActionMenuPresenter.setCallback(cb);
mToolbar.setMenu((MenuBuilder) menu, mActionMenuPresenter);
}
@Override
public void dismissPopupMenus() {
mToolbar.dismissPopupMenus();
}
@Override
public int getDisplayOptions() {
return mDisplayOpts;
}
@Override
public void setDisplayOptions(int newOpts) {
final int oldOpts = mDisplayOpts;
final int changed = oldOpts ^ newOpts;
mDisplayOpts = newOpts;
if (changed != 0) {
if ((changed & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
if ((newOpts & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
mToolbar.setNavigationIcon(mNavIcon);
} else {
mToolbar.setNavigationIcon(null);
}
}
if ((changed & AFFECTS_LOGO_MASK) != 0) {
updateToolbarLogo();
}
if ((changed & ActionBar.DISPLAY_SHOW_TITLE) != 0) {
if ((newOpts & ActionBar.DISPLAY_SHOW_TITLE) != 0) {
mToolbar.setTitle(mTitle);
mToolbar.setSubtitle(mSubtitle);
} else {
mToolbar.setTitle(null);
mToolbar.setSubtitle(null);
}
}
if ((changed & ActionBar.DISPLAY_SHOW_CUSTOM) != 0 && mCustomView != null) {
if ((newOpts & ActionBar.DISPLAY_SHOW_CUSTOM) != 0) {
mToolbar.addView(mCustomView);
} else {
mToolbar.removeView(mCustomView);
}
}
}
}
@Override
public void setEmbeddedTabView(View tabView) {
mTabView = tabView;
}
@Override
public boolean hasEmbeddedTabs() {
return mTabView != null;
}
@Override
public boolean isTitleTruncated() {
return mToolbar.isTitleTruncated();
}
@Override
public void setCollapsible(boolean collapsible) {
// Ignore
}
@Override
public void setHomeButtonEnabled(boolean enable) {
// Ignore
}
@Override
public int getNavigationMode() {
return 0;
}
@Override
public void setNavigationMode(int mode) {
if (mode != ActionBar.NAVIGATION_MODE_STANDARD) {
throw new IllegalArgumentException(
"Navigation modes not supported in this configuration");
}
}
@Override
public void setDropdownParams(SpinnerAdapter adapter,
AdapterView.OnItemSelectedListener listener) {
if (mSpinner == null) {
mSpinner = new Spinner(getContext());
}
mSpinner.setAdapter(adapter);
mSpinner.setOnItemSelectedListener(listener);
}
@Override
public void setDropdownSelectedPosition(int position) {
if (mSpinner == null) {
throw new IllegalStateException(
"Can't set dropdown selected position without an adapter");
}
mSpinner.setSelection(position);
}
@Override
public int getDropdownSelectedPosition() {
return mSpinner != null ? mSpinner.getSelectedItemPosition() : 0;
}
@Override
public int getDropdownItemCount() {
return mSpinner != null ? mSpinner.getCount() : 0;
}
@Override
public void setCustomView(View view) {
if (mCustomView != null && (mDisplayOpts & ActionBar.DISPLAY_SHOW_CUSTOM) != 0) {
mToolbar.removeView(mCustomView);
}
mCustomView = view;
if (view != null && (mDisplayOpts & ActionBar.DISPLAY_SHOW_CUSTOM) != 0) {
mToolbar.addView(mCustomView);
}
}
@Override
public View getCustomView() {
return mCustomView;
}
@Override
public void animateToVisibility(int visibility) {
if (visibility == View.GONE) {
mToolbar.animate().translationY(mToolbar.getHeight()).alpha(0)
.setListener(new AnimatorListenerAdapter() {
private boolean mCanceled = false;
@Override
public void onAnimationEnd(Animator animation) {
if (!mCanceled) {
mToolbar.setVisibility(View.GONE);
}
}
@Override
public void onAnimationCancel(Animator animation) {
mCanceled = true;
}
});
} else if (visibility == View.VISIBLE) {
mToolbar.animate().translationY(0).alpha(1)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
mToolbar.setVisibility(View.VISIBLE);
}
});
}
}
@Override
public void setNavigationIcon(Drawable icon) {
mNavIcon = icon;
if ((mDisplayOpts & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
mToolbar.setNavigationIcon(icon);
}
}
@Override
public void setNavigationIcon(int resId) {
setNavigationIcon(mToolbar.getContext().getDrawable(resId));
}
@Override
public void setNavigationContentDescription(CharSequence description) {
mToolbar.setNavigationContentDescription(description);
}
@Override
public void setNavigationContentDescription(int resId) {
mToolbar.setNavigationContentDescription(resId);
}
@Override
public void saveHierarchyState(SparseArray<Parcelable> toolbarStates) {
mToolbar.saveHierarchyState(toolbarStates);
}
@Override
public void restoreHierarchyState(SparseArray<Parcelable> toolbarStates) {
mToolbar.restoreHierarchyState(toolbarStates);
}
}

View File

@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2014 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.
-->
<!--
This is an optimized layout for a screen with a toolbar enabled.
-->
<com.android.internal.widget.ActionBarOverlayLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/decor_content_parent"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:splitMotionEvents="false"
android:theme="?attr/actionBarTheme">
<FrameLayout android:id="@android:id/content"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.android.internal.widget.ActionBarContainer
android:id="@+id/action_bar_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
style="?attr/actionBarStyle"
android:viewName="android:action_bar"
android:gravity="top">
<Toolbar
android:id="@+id/action_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="?attr/toolbarStyle" />
<com.android.internal.widget.ActionBarContextView
android:id="@+id/action_context_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
style="?attr/actionModeStyle" />
</com.android.internal.widget.ActionBarContainer>
</com.android.internal.widget.ActionBarOverlayLayout>

View File

@@ -493,6 +493,9 @@
{@link android.view.Window#setAllowExitTransitionOverlap(boolean)}. -->
<attr name="windowAllowExitTransitionOverlap" format="boolean"/>
<!-- Internal layout used internally for window decor -->
<attr name="windowActionBarFullscreenDecorLayout" format="reference" />
<!-- ============ -->
<!-- Alert Dialog styles -->
<!-- ============ -->
@@ -685,6 +688,7 @@
<!-- Default ActivityChooserView style. -->
<attr name="activityChooserViewStyle" format="reference" />
<!-- Default Toolbar style. -->
<attr name="toolbarStyle" format="reference" />
<!-- Fast scroller styles -->
@@ -1713,6 +1717,7 @@
<attr name="windowSwipeToDismiss" />
<attr name="windowContentTransitions" />
<attr name="windowContentTransitionManager" />
<attr name="windowActionBarFullscreenDecorLayout" />
<!-- The minimum width the window is allowed to be, along the major
axis of the screen. That is, when in landscape. Can be either
@@ -6398,11 +6403,17 @@
<attr name="indeterminateProgressStyle" format="reference" />
<!-- Specifies the horizontal padding on either end for an embedded progress bar. -->
<attr name="progressBarPadding" format="dimension" />
<!-- Up navigation glyph -->
<attr name="homeAsUpIndicator" />
<!-- Specifies padding that should be applied to the left and right sides of
system-provided items in the bar. -->
<attr name="itemPadding" format="dimension" />
<!-- Set true to hide the action bar on a vertical nested scroll of content. -->
<attr name="hideOnContentScroll" format="boolean" />
<attr name="contentInsetStart" format="dimension" />
<attr name="contentInsetEnd" format="dimension" />
<attr name="contentInsetLeft" format="dimension" />
<attr name="contentInsetRight" format="dimension" />
</declare-styleable>
<declare-styleable name="ActionMode">
@@ -6653,10 +6664,19 @@
<attr name="titleMarginEnd" format="dimension" />
<attr name="titleMarginTop" format="dimension" />
<attr name="titleMarginBottom" format="dimension" />
<attr name="contentInsetStart" format="dimension" />
<attr name="contentInsetEnd" format="dimension" />
<attr name="contentInsetLeft" format="dimension" />
<attr name="contentInsetRight" format="dimension" />
<attr name="contentInsetStart" />
<attr name="contentInsetEnd" />
<attr name="contentInsetLeft" />
<attr name="contentInsetRight" />
<attr name="maxButtonHeight" format="dimension" />
<attr name="navigationButtonStyle" format="reference" />
<attr name="buttonGravity">
<!-- Push object to the top of its container, not changing its size. -->
<flag name="top" value="0x30" />
<!-- Push object to the bottom of its container, not changing its size. -->
<flag name="bottom" value="0x50" />
</attr>
<attr name="collapseIcon" format="reference" />
</declare-styleable>
<declare-styleable name="Toolbar_LayoutParams">

View File

@@ -1197,6 +1197,16 @@ please see styles_device_defaults.xml.
<item name="android:subtitleTextAppearance">@android:style/TextAppearance.Widget.Toolbar.Subtitle</item>
<item name="android:minHeight">?android:attr/actionBarSize</item>
<item name="android:titleMargins">4dp</item>
<item name="android:maxButtonHeight">56dp</item>
<item name="android:buttonGravity">top</item>
<item name="android:navigationButtonStyle">@android:style/Widget.Toolbar.Button.Navigation</item>
<item name="android:collapseIcon">?android:attr/homeAsUpIndicator</item>
</style>
<style name="Widget.Toolbar.Button.Navigation" parent="@android:style/Widget">
<item name="android:background">?android:attr/selectableItemBackground</item>
<item name="android:minWidth">56dp</item>
<item name="android:scaleType">center</item>
</style>
<style name="TextAppearance.Widget.ActionBar.Title"
@@ -2394,7 +2404,6 @@ please see styles_device_defaults.xml.
<item name="android:background">@android:drawable/ab_transparent_light_holo</item>
<item name="android:backgroundStacked">@android:drawable/ab_stacked_transparent_light_holo</item>
<item name="android:backgroundSplit">@android:drawable/ab_bottom_transparent_light_holo</item>
<item name="android:homeAsUpIndicator">@android:drawable/ic_ab_back_holo_light</item>
<item name="android:progressBarStyle">@android:style/Widget.Holo.Light.ProgressBar.Horizontal</item>
<item name="android:indeterminateProgressStyle">@android:style/Widget.Holo.Light.ProgressBar</item>
</style>

View File

@@ -773,7 +773,7 @@ please see styles_device_defaults.xml.
<item name="background">@null</item>
<item name="backgroundStacked">@null</item>
<item name="backgroundSplit">@null</item>
<item name="displayOptions">useLogo|showHome|showTitle</item>
<item name="displayOptions">showTitle</item>
<item name="divider">?attr/dividerVertical</item>
<item name="titleTextStyle">@style/TextAppearance.Quantum.Widget.ActionBar.Title</item>
<item name="subtitleTextStyle">@style/TextAppearance.Quantum.Widget.ActionBar.Subtitle</item>
@@ -783,6 +783,7 @@ please see styles_device_defaults.xml.
<item name="itemPadding">8dip</item>
<item name="homeLayout">@layout/action_bar_home_quantum</item>
<item name="gravity">center_vertical</item>
<item name="contentInsetStart">56dp</item>
</style>
<style name="Widget.Quantum.ActionBar.Solid">

View File

@@ -1862,6 +1862,7 @@
<java-symbol type="attr" name="toolbarStyle" />
<java-symbol type="attr" name="titleTextAppearance" />
<java-symbol type="attr" name="subtitleTextAppearance" />
<java-symbol type="attr" name="windowActionBarFullscreenDecorLayout" />
<java-symbol type="drawable" name="ic_lock_bugreport" />
<java-symbol type="id" name="icon_frame" />
<java-symbol type="style" name="Animation.VolumePanel" />

View File

@@ -192,6 +192,7 @@ please see themes_device_defaults.xml.
<item name="windowDrawsSystemBarBackgrounds">false</item>
<item name="statusBarColor">@android:color/black</item>
<item name="navigationBarColor">@android:color/black</item>
<item name="windowActionBarFullscreenDecorLayout">@layout/screen_action_bar</item>
<!-- Define these here; ContextThemeWrappers around themes that define them should
always clear these values. -->

View File

@@ -162,6 +162,7 @@ please see themes_device_defaults.xml.
<item name="windowActionBar">true</item>
<item name="windowActionModeOverlay">false</item>
<item name="windowDrawsSystemBarBackgrounds">true</item>
<item name="windowActionBarFullscreenDecorLayout">@layout/screen_toolbar</item>
<item name="statusBarColor">?attr/colorPrimaryDark</item>
<item name="navigationBarColor">?attr/colorPrimaryDark</item>
@@ -505,6 +506,7 @@ please see themes_device_defaults.xml.
<item name="windowActionBar">true</item>
<item name="windowActionModeOverlay">false</item>
<item name="windowDrawsSystemBarBackgrounds">true</item>
<item name="windowActionBarFullscreenDecorLayout">@layout/screen_toolbar</item>
<item name="statusBarColor">?attr/colorPrimaryDark</item>
<item name="navigationBarColor">?attr/colorPrimaryDark</item>

View File

@@ -3179,7 +3179,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
com.android.internal.R.attr.dialogTitleDecorLayout, res, true);
layoutResource = res.resourceId;
} else if ((features & (1 << FEATURE_ACTION_BAR)) != 0) {
layoutResource = com.android.internal.R.layout.screen_action_bar;
layoutResource = a.getResourceId(
com.android.internal.R.styleable.Window_windowActionBarFullscreenDecorLayout,
com.android.internal.R.layout.screen_action_bar);
} else {
layoutResource = com.android.internal.R.layout.screen_title;
}