Merge "Refactoring of action bar internals"

This commit is contained in:
Adam Powell
2011-05-02 22:17:24 -07:00
committed by Android (Google) Code Review
13 changed files with 461 additions and 253 deletions

View File

@@ -254,6 +254,15 @@ public class LinearLayout extends ViewGroup {
return mDividerPadding;
}
/**
* Get the width of the current divider drawable.
*
* @hide Used internally by framework.
*/
public int getDividerWidth() {
return mDividerWidth;
}
@Override
protected void onDraw(Canvas canvas) {
if (mDivider == null) {

View File

@@ -19,6 +19,7 @@ package com.android.internal.app;
import com.android.internal.view.menu.MenuBuilder;
import com.android.internal.view.menu.MenuPopupHelper;
import com.android.internal.view.menu.SubMenuBuilder;
import com.android.internal.widget.AbsActionBarView;
import com.android.internal.widget.ActionBarContainer;
import com.android.internal.widget.ActionBarContextView;
import com.android.internal.widget.ActionBarView;
@@ -46,7 +47,6 @@ import android.view.ViewGroup;
import android.view.Window;
import android.view.animation.DecelerateInterpolator;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;
import android.widget.SpinnerAdapter;
import java.lang.ref.WeakReference;
@@ -61,8 +61,6 @@ import java.util.ArrayList;
*/
public class ActionBarImpl extends ActionBar {
private static final String TAG = "ActionBarImpl";
private static final int NORMAL_VIEW = 0;
private static final int CONTEXT_VIEW = 1;
private Context mContext;
private Activity mActivity;
@@ -70,8 +68,8 @@ public class ActionBarImpl extends ActionBar {
private ActionBarContainer mContainerView;
private ActionBarView mActionView;
private ActionBarContextView mUpperContextView;
private LinearLayout mLowerView;
private ActionBarContextView mContextView;
private ActionBarContainer mSplitView;
private View mContentView;
private ViewGroup mExternalTabView;
@@ -102,26 +100,6 @@ public class ActionBarImpl extends ActionBar {
private static final TimeInterpolator sFadeOutInterpolator = new DecelerateInterpolator();
final AnimatorListener[] mAfterAnimation = new AnimatorListener[] {
new AnimatorListenerAdapter() { // NORMAL_VIEW
@Override
public void onAnimationEnd(Animator animation) {
if (mLowerView != null) {
mLowerView.removeAllViews();
}
mCurrentModeAnim = null;
hideAllExcept(NORMAL_VIEW);
}
},
new AnimatorListenerAdapter() { // CONTEXT_VIEW
@Override
public void onAnimationEnd(Animator animation) {
mCurrentModeAnim = null;
hideAllExcept(CONTEXT_VIEW);
}
}
};
final AnimatorListener mHideListener = new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
@@ -160,19 +138,19 @@ public class ActionBarImpl extends ActionBar {
private void init(View decor) {
mContext = decor.getContext();
mActionView = (ActionBarView) decor.findViewById(com.android.internal.R.id.action_bar);
mUpperContextView = (ActionBarContextView) decor.findViewById(
mContextView = (ActionBarContextView) decor.findViewById(
com.android.internal.R.id.action_context_bar);
mLowerView = (LinearLayout) decor.findViewById(
com.android.internal.R.id.lower_action_context_bar);
mContainerView = (ActionBarContainer) decor.findViewById(
com.android.internal.R.id.action_bar_container);
mSplitView = (ActionBarContainer) decor.findViewById(
com.android.internal.R.id.split_action_bar);
if (mActionView == null || mUpperContextView == null || mContainerView == null) {
if (mActionView == null || mContextView == null || mContainerView == null) {
throw new IllegalStateException(getClass().getSimpleName() + " can only be used " +
"with a compatible window decor layout");
}
mActionView.setContextView(mUpperContextView);
mActionView.setContextView(mContextView);
mContextDisplayMode = mActionView.isSplitActionBar() ?
CONTEXT_DISPLAY_SPLIT : CONTEXT_DISPLAY_NORMAL;
@@ -341,16 +319,16 @@ public class ActionBarImpl extends ActionBar {
mActionMode.finish();
}
mUpperContextView.killMode();
mContextView.killMode();
ActionMode mode = new ActionModeImpl(callback);
if (callback.onCreateActionMode(mode, mode.getMenu())) {
mWasHiddenBeforeMode = !isShowing();
mode.invalidate();
mUpperContextView.initForMode(mode);
animateTo(CONTEXT_VIEW);
if (mLowerView != null) {
mContextView.initForMode(mode);
animateToMode(true);
if (mSplitView != null) {
// TODO animate this
mLowerView.setVisibility(View.VISIBLE);
mSplitView.setVisibility(View.VISIBLE);
}
mActionMode = mode;
return mode;
@@ -495,6 +473,10 @@ public class ActionBarImpl extends ActionBar {
mContainerView.setTranslationY(-mContainerView.getHeight());
b.with(ObjectAnimator.ofFloat(mContainerView, "translationY", 0));
}
if (mSplitView != null) {
mSplitView.setAlpha(0);
b.with(ObjectAnimator.ofFloat(mSplitView, "alpha", 1));
}
anim.addListener(mShowListener);
mCurrentShowAnim = anim;
anim.start();
@@ -525,6 +507,10 @@ public class ActionBarImpl extends ActionBar {
b.with(ObjectAnimator.ofFloat(mContainerView, "translationY",
-mContainerView.getHeight()));
}
if (mSplitView != null) {
mSplitView.setAlpha(1);
b.with(ObjectAnimator.ofFloat(mSplitView, "alpha", 0));
}
anim.addListener(mHideListener);
mCurrentShowAnim = anim;
anim.start();
@@ -537,45 +523,14 @@ public class ActionBarImpl extends ActionBar {
return mContainerView.getVisibility() == View.VISIBLE;
}
long animateTo(int viewIndex) {
void animateToMode(boolean toActionMode) {
show(false);
if (mCurrentModeAnim != null) {
mCurrentModeAnim.end();
}
AnimatorSet set = new AnimatorSet();
final View targetChild = mContainerView.getChildAt(viewIndex);
targetChild.setVisibility(View.VISIBLE);
targetChild.setAlpha(0);
AnimatorSet.Builder b = set.play(ObjectAnimator.ofFloat(targetChild, "alpha", 1));
final int count = mContainerView.getChildCount();
for (int i = 0; i < count; i++) {
final View child = mContainerView.getChildAt(i);
if (i == viewIndex || child == mContainerView.getTabContainer()) {
continue;
}
if (child.getVisibility() != View.GONE) {
Animator a = ObjectAnimator.ofFloat(child, "alpha", 0);
a.setInterpolator(sFadeOutInterpolator);
b.with(a);
}
}
set.addListener(mAfterAnimation[viewIndex]);
mCurrentModeAnim = set;
set.start();
return set.getDuration();
}
private void hideAllExcept(int viewIndex) {
final int count = mContainerView.getChildCount();
for (int i = 0; i < count; i++) {
mContainerView.getChildAt(i).setVisibility(i == viewIndex ? View.VISIBLE : View.GONE);
}
mActionView.animateToVisibility(toActionMode ? View.GONE : View.VISIBLE);
mContextView.animateToVisibility(toActionMode ? View.VISIBLE : View.GONE);
}
/**
@@ -612,14 +567,10 @@ public class ActionBarImpl extends ActionBar {
mCallback.onDestroyActionMode(this);
mCallback = null;
animateTo(NORMAL_VIEW);
animateToMode(false);
// Clear out the context mode views after the animation finishes
mUpperContextView.closeMode();
if (mLowerView != null && mLowerView.getVisibility() != View.GONE) {
// TODO Animate this
mLowerView.setVisibility(View.GONE);
}
mContextView.closeMode();
mActionMode = null;
if (mWasHiddenBeforeMode) {
@@ -636,18 +587,18 @@ public class ActionBarImpl extends ActionBar {
@Override
public void setCustomView(View view) {
mUpperContextView.setCustomView(view);
mContextView.setCustomView(view);
mCustomView = new WeakReference<View>(view);
}
@Override
public void setSubtitle(CharSequence subtitle) {
mUpperContextView.setSubtitle(subtitle);
mContextView.setSubtitle(subtitle);
}
@Override
public void setTitle(CharSequence title) {
mUpperContextView.setTitle(title);
mContextView.setTitle(title);
}
@Override
@@ -662,12 +613,12 @@ public class ActionBarImpl extends ActionBar {
@Override
public CharSequence getTitle() {
return mUpperContextView.getTitle();
return mContextView.getTitle();
}
@Override
public CharSequence getSubtitle() {
return mUpperContextView.getSubtitle();
return mContextView.getSubtitle();
}
@Override
@@ -707,7 +658,7 @@ public class ActionBarImpl extends ActionBar {
return;
}
invalidate();
mUpperContextView.showOverflowMenu();
mContextView.showOverflowMenu();
}
}

View File

@@ -36,11 +36,14 @@ import java.util.ArrayList;
* MenuPresenter for building action menus as seen in the action bar and action modes.
*/
public class ActionMenuPresenter extends BaseMenuPresenter {
private static final String TAG = "ActionMenuPresenter";
private View mOverflowButton;
private boolean mReserveOverflow;
private int mWidthLimit;
private int mActionItemWidthLimit;
private int mMaxItems;
private boolean mStrictWidthLimit;
// Group IDs that have been added as actions - used temporarily, allocated here for reuse.
private final SparseBooleanArray mActionButtonGroups = new SparseBooleanArray();
@@ -89,11 +92,12 @@ public class ActionMenuPresenter extends BaseMenuPresenter {
mScrapActionButtonView = null;
}
public void setWidthLimit(int width) {
public void setWidthLimit(int width, boolean strict) {
if (mReserveOverflow) {
width -= mOverflowButton.getMeasuredWidth();
}
mActionItemWidthLimit = width;
mStrictWidthLimit = strict;
}
public void setItemLimit(int itemCount) {
@@ -131,6 +135,8 @@ public class ActionMenuPresenter extends BaseMenuPresenter {
if (mReserveOverflow && mMenu.getNonActionItems().size() > 0) {
if (mOverflowButton == null) {
mOverflowButton = new OverflowMenuButton(mContext);
mOverflowButton.setLayoutParams(
((ActionMenuView) mMenuView).generateOverflowButtonLayoutParams());
}
ViewGroup parent = (ViewGroup) mOverflowButton.getParent();
if (parent != mMenuView) {
@@ -308,6 +314,8 @@ public class ActionMenuPresenter extends BaseMenuPresenter {
v.measure(querySpec, querySpec);
final int measuredWidth = v.getMeasuredWidth();
widthLimit -= measuredWidth;
Log.d(TAG, "flagActionItems required item " + i + " measured width " +
measuredWidth + " - " + widthLimit + " left");
if (firstActionWidth == 0) {
firstActionWidth = measuredWidth;
}
@@ -334,13 +342,19 @@ public class ActionMenuPresenter extends BaseMenuPresenter {
v.measure(querySpec, querySpec);
final int measuredWidth = v.getMeasuredWidth();
widthLimit -= measuredWidth;
Log.d(TAG, "flagActionItems requested item " + i + " measured width " +
measuredWidth + " - " + widthLimit + " left");
if (firstActionWidth == 0) {
firstActionWidth = measuredWidth;
}
// Did this push the entire first item past halfway?
if (widthLimit + firstActionWidth <= 0) {
isAction = false;
if (mStrictWidthLimit) {
isAction = widthLimit >= 0;
Log.d(TAG, " --> strict width limit: isAction? " + isAction);
} else {
// Did this push the entire first item past the limit?
isAction = widthLimit + firstActionWidth > 0;
Log.d(TAG, " --> normal width limit: isAction? " + isAction);
}
}

View File

@@ -20,6 +20,7 @@ import android.content.res.Configuration;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.view.ViewDebug;
import android.view.ViewGroup;
import android.widget.LinearLayout;
@@ -33,6 +34,8 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo
private boolean mReserveOverflow;
private ActionMenuPresenter mPresenter;
private boolean mUpdateContentsBeforeMeasure;
private boolean mFormatItems;
public ActionMenuView(Context context) {
this(context, null);
@@ -58,6 +61,95 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo
}
}
@Override
public void requestLayout() {
// Layout can influence how many action items fit.
mUpdateContentsBeforeMeasure = true;
super.requestLayout();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (mUpdateContentsBeforeMeasure && mMenu != null) {
mMenu.onItemsChanged(true);
mUpdateContentsBeforeMeasure = false;
}
// If we've been given an exact size to match, apply special formatting during layout.
mFormatItems = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY;
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
if (!mFormatItems) {
super.onLayout(changed, left, top, right, bottom);
return;
}
final int childCount = getChildCount();
final int midVertical = (top + bottom) / 2;
final int dividerWidth = getDividerWidth();
boolean hasOverflow = false;
int overflowWidth = 0;
int nonOverflowWidth = 0;
int nonOverflowCount = 0;
int widthRemaining = right - left - getPaddingRight() - getPaddingLeft();
for (int i = 0; i < childCount; i++) {
final View v = getChildAt(i);
if (v.getVisibility() == GONE) {
continue;
}
LayoutParams p = (LayoutParams) v.getLayoutParams();
if (p.isOverflowButton) {
hasOverflow = true;
overflowWidth = v.getMeasuredWidth();
if (hasDividerBeforeChildAt(i)) {
overflowWidth += dividerWidth;
}
int height = v.getMeasuredHeight();
int r = getPaddingRight();
int l = r - overflowWidth;
int t = midVertical - (height / 2);
int b = t + height;
v.layout(l, t, r, b);
widthRemaining -= overflowWidth;
} else {
nonOverflowWidth += v.getMeasuredWidth() + p.leftMargin + p.rightMargin;
if (hasDividerBeforeChildAt(i)) {
nonOverflowWidth += dividerWidth;
}
nonOverflowCount++;
}
}
// Try to center non-overflow items with uniformly spaced padding, including on the edges.
// Overflow will always pin to the right edge. If there isn't enough room for that,
// center in the remaining space.
if (nonOverflowWidth <= widthRemaining - overflowWidth) {
widthRemaining -= overflowWidth;
}
final int spacing = (widthRemaining - nonOverflowWidth) / (nonOverflowCount + 1);
int startLeft = getPaddingLeft() + overflowWidth + spacing;
for (int i = 0; i < childCount; i++) {
final View v = getChildAt(i);
final LayoutParams lp = (LayoutParams) v.getLayoutParams();
if (v.getVisibility() == GONE || lp.isOverflowButton) {
continue;
}
startLeft += lp.leftMargin;
int width = v.getMeasuredWidth();
int height = v.getMeasuredHeight();
int t = midVertical - (height / 2);
v.layout(startLeft, t, startLeft + width, t + height);
startLeft += width + lp.rightMargin + spacing;
}
}
@Override
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
@@ -97,6 +189,12 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo
return p instanceof LayoutParams;
}
public LayoutParams generateOverflowButtonLayoutParams() {
LayoutParams result = generateDefaultLayoutParams();
result.isOverflowButton = true;
return result;
}
public boolean invokeItem(MenuItemImpl item) {
return mMenu.performItemAction(item, 0);
}
@@ -127,4 +225,28 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo
public boolean needsDividerBefore();
public boolean needsDividerAfter();
}
public static class LayoutParams extends LinearLayout.LayoutParams {
@ViewDebug.ExportedProperty(category = "layout")
public boolean isOverflowButton;
public LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
}
public LayoutParams(LayoutParams other) {
super((LinearLayout.LayoutParams) other);
isOverflowButton = other.isOverflowButton;
}
public LayoutParams(int width, int height) {
super(width, height);
isOverflowButton = false;
}
public LayoutParams(int width, int height, boolean isOverflowButton) {
super(width, height);
this.isOverflowButton = isOverflowButton;
}
}
}

View File

@@ -226,6 +226,7 @@ public class MenuBuilder implements Menu {
private void dispatchPresenterUpdate(boolean cleared) {
if (mPresenters.isEmpty()) return;
stopDispatchingItemsChanged();
for (WeakReference<MenuPresenter> ref : mPresenters) {
final MenuPresenter presenter = ref.get();
if (presenter == null) {
@@ -234,6 +235,7 @@ public class MenuBuilder implements Menu {
presenter.updateMenuView(cleared);
}
}
startDispatchingItemsChanged();
}
private boolean dispatchSubMenuSelected(SubMenuBuilder subMenu) {

View File

@@ -0,0 +1,211 @@
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.internal.widget;
import com.android.internal.view.menu.ActionMenuPresenter;
import com.android.internal.view.menu.ActionMenuView;
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.DecelerateInterpolator;
public abstract class AbsActionBarView extends ViewGroup {
protected ActionMenuView mMenuView;
protected ActionMenuPresenter mMenuPresenter;
protected ActionBarContainer mSplitView;
protected Animator mVisibilityAnim;
protected final VisibilityAnimListener mVisAnimListener = new VisibilityAnimListener();
private static final TimeInterpolator sAlphaInterpolator = new DecelerateInterpolator();
private static final int FADE_DURATION = 200;
public AbsActionBarView(Context context) {
super(context);
}
public AbsActionBarView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public AbsActionBarView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public void setSplitView(ActionBarContainer splitView) {
mSplitView = splitView;
}
public void animateToVisibility(int visibility) {
if (mVisibilityAnim != null) {
mVisibilityAnim.cancel();
}
if (visibility == VISIBLE) {
if (getVisibility() != VISIBLE) {
setAlpha(0);
if (mSplitView != null && mMenuView != null) {
mMenuView.setAlpha(0);
}
}
ObjectAnimator anim = ObjectAnimator.ofFloat(this, "alpha", 1);
anim.setDuration(FADE_DURATION);
anim.setInterpolator(sAlphaInterpolator);
if (mSplitView != null && mMenuView != null) {
AnimatorSet set = new AnimatorSet();
ObjectAnimator splitAnim = ObjectAnimator.ofFloat(mMenuView, "alpha", 1);
splitAnim.setDuration(FADE_DURATION);
set.addListener(mVisAnimListener.withFinalVisibility(visibility));
set.play(anim).with(splitAnim);
} else {
anim.addListener(mVisAnimListener.withFinalVisibility(visibility));
anim.start();
}
} else {
ObjectAnimator anim = ObjectAnimator.ofFloat(this, "alpha", 0);
anim.setDuration(FADE_DURATION);
anim.setInterpolator(sAlphaInterpolator);
if (mSplitView != null && mMenuView != null) {
AnimatorSet set = new AnimatorSet();
ObjectAnimator splitAnim = ObjectAnimator.ofFloat(mMenuView, "alpha", 0);
splitAnim.setDuration(FADE_DURATION);
set.addListener(mVisAnimListener.withFinalVisibility(visibility));
set.play(anim).with(splitAnim);
} else {
anim.addListener(mVisAnimListener.withFinalVisibility(visibility));
anim.start();
}
}
}
@Override
public void setVisibility(int visibility) {
if (mVisibilityAnim != null) {
mVisibilityAnim.end();
}
super.setVisibility(visibility);
}
public boolean showOverflowMenu() {
if (mMenuPresenter != null) {
return mMenuPresenter.showOverflowMenu();
}
return false;
}
public void postShowOverflowMenu() {
post(new Runnable() {
public void run() {
showOverflowMenu();
}
});
}
public boolean hideOverflowMenu() {
if (mMenuPresenter != null) {
return mMenuPresenter.hideOverflowMenu();
}
return false;
}
public boolean isOverflowMenuShowing() {
if (mMenuPresenter != null) {
return mMenuPresenter.isOverflowMenuShowing();
}
return false;
}
public boolean isOverflowReserved() {
return mMenuPresenter != null && mMenuPresenter.isOverflowReserved();
}
public void dismissPopupMenus() {
if (mMenuPresenter != null) {
mMenuPresenter.dismissPopupMenus();
}
}
protected int measureChildView(View child, int availableWidth, int childSpecHeight,
int spacing) {
child.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST),
childSpecHeight);
availableWidth -= child.getMeasuredWidth();
availableWidth -= spacing;
return availableWidth;
}
protected int positionChild(View child, int x, int y, int contentHeight) {
int childWidth = child.getMeasuredWidth();
int childHeight = child.getMeasuredHeight();
int childTop = y + (contentHeight - childHeight) / 2;
child.layout(x, childTop, x + childWidth, childTop + childHeight);
return childWidth;
}
protected int positionChildInverse(View child, int x, int y, int contentHeight) {
int childWidth = child.getMeasuredWidth();
int childHeight = child.getMeasuredHeight();
int childTop = y + (contentHeight - childHeight) / 2;
child.layout(x - childWidth, childTop, x, childTop + childHeight);
return childWidth;
}
protected class VisibilityAnimListener implements Animator.AnimatorListener {
private boolean mCanceled = false;
private int mFinalVisibility;
public VisibilityAnimListener withFinalVisibility(int visibility) {
mFinalVisibility = visibility;
return this;
}
@Override
public void onAnimationStart(Animator animation) {
setVisibility(VISIBLE);
mVisibilityAnim = animation;
mCanceled = false;
}
@Override
public void onAnimationEnd(Animator animation) {
if (mCanceled) return;
mVisibilityAnim = null;
setVisibility(mFinalVisibility);
}
@Override
public void onAnimationCancel(Animator animation) {
mCanceled = true;
}
@Override
public void onAnimationRepeat(Animator animation) {
}
}
}

View File

@@ -19,6 +19,7 @@ package com.android.internal.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.ActionMode;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
@@ -84,6 +85,12 @@ public class ActionBarContainer extends FrameLayout {
return mTabContainer;
}
@Override
public ActionMode startActionModeForChild(View child, ActionMode.Callback callback) {
// No starting an action mode for an action bar child! (Where would it go?)
return null;
}
@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);

View File

@@ -30,7 +30,7 @@ import android.util.AttributeSet;
import android.view.ActionMode;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.animation.DecelerateInterpolator;
import android.widget.LinearLayout;
import android.widget.TextView;
@@ -38,7 +38,7 @@ import android.widget.TextView;
/**
* @hide
*/
public class ActionBarContextView extends ViewGroup implements AnimatorListener {
public class ActionBarContextView extends AbsActionBarView implements AnimatorListener {
private static final String TAG = "ActionBarContextView";
private int mContentHeight;
@@ -53,8 +53,6 @@ public class ActionBarContextView extends ViewGroup implements AnimatorListener
private TextView mSubtitleView;
private int mTitleStyleRes;
private int mSubtitleStyleRes;
private ActionMenuView mMenuView;
private ActionMenuPresenter mPresenter;
private Animator mCurrentAnimation;
private boolean mAnimateInOnLayout;
@@ -87,12 +85,6 @@ public class ActionBarContextView extends ViewGroup implements AnimatorListener
com.android.internal.R.styleable.ActionMode_height, 0);
a.recycle();
}
@Override
public ActionMode startActionModeForChild(View child, ActionMode.Callback callback) {
// No starting an action mode for an existing action mode UI child! (Where would it go?)
return null;
}
public void setHeight(int height) {
mContentHeight = height;
@@ -178,10 +170,25 @@ public class ActionBarContextView extends ViewGroup implements AnimatorListener
});
final MenuBuilder menu = (MenuBuilder) mode.getMenu();
mPresenter = new ActionMenuPresenter();
menu.addMenuPresenter(mPresenter);
mMenuView = (ActionMenuView) mPresenter.getMenuView(this);
addView(mMenuView);
mMenuPresenter = new ActionMenuPresenter();
menu.addMenuPresenter(mMenuPresenter);
mMenuView = (ActionMenuView) mMenuPresenter.getMenuView(this);
final LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.MATCH_PARENT);
mMenuView.setLayoutParams(layoutParams);
if (mSplitView == null) {
addView(mMenuView);
} else {
// Allow full screen width in split mode.
mMenuPresenter.setWidthLimit(
getContext().getResources().getDisplayMetrics().widthPixels, true);
// No limit to the item count; use whatever will fit.
mMenuPresenter.setItemLimit(Integer.MAX_VALUE);
// Span the whole width
layoutParams.width = LayoutParams.MATCH_PARENT;
mSplitView.addView(mMenuView);
}
mAnimateInOnLayout = true;
}
@@ -213,28 +220,31 @@ public class ActionBarContextView extends ViewGroup implements AnimatorListener
public void killMode() {
finishAnimation();
removeAllViews();
if (mSplitView != null) {
mSplitView.removeView(mMenuView);
}
mCustomView = null;
mMenuView = null;
mAnimateInOnLayout = false;
}
public boolean showOverflowMenu() {
if (mPresenter != null) {
return mPresenter.showOverflowMenu();
if (mMenuPresenter != null) {
return mMenuPresenter.showOverflowMenu();
}
return false;
}
public boolean hideOverflowMenu() {
if (mPresenter != null) {
return mPresenter.hideOverflowMenu();
if (mMenuPresenter != null) {
return mMenuPresenter.hideOverflowMenu();
}
return false;
}
public boolean isOverflowMenuShowing() {
if (mPresenter != null) {
return mPresenter.isOverflowMenuShowing();
if (mMenuPresenter != null) {
return mMenuPresenter.isOverflowMenuShowing();
}
return false;
}
@@ -342,7 +352,7 @@ public class ActionBarContextView extends ViewGroup implements AnimatorListener
private Animator makeOutAnimation() {
ObjectAnimator buttonAnimator = ObjectAnimator.ofFloat(mClose, "translationX",
0, -mClose.getWidth());
-mClose.getWidth());
buttonAnimator.setDuration(200);
buttonAnimator.addListener(this);
buttonAnimator.setInterpolator(new DecelerateInterpolator());
@@ -356,7 +366,7 @@ public class ActionBarContextView extends ViewGroup implements AnimatorListener
for (int i = 0; i < 0; i++) {
View child = mMenuView.getChildAt(i);
child.setScaleY(0);
ObjectAnimator a = ObjectAnimator.ofFloat(child, "scaleY", 1, 0);
ObjectAnimator a = ObjectAnimator.ofFloat(child, "scaleY", 0);
a.setDuration(100);
a.setStartDelay(i * 70);
b.with(a);
@@ -383,7 +393,7 @@ public class ActionBarContextView extends ViewGroup implements AnimatorListener
mAnimateInOnLayout = false;
}
}
if (mTitleLayout != null && mCustomView == null) {
x += positionChild(mTitleLayout, x, y, contentHeight);
}
@@ -399,36 +409,6 @@ public class ActionBarContextView extends ViewGroup implements AnimatorListener
}
}
private int measureChildView(View child, int availableWidth, int childSpecHeight, int spacing) {
child.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST),
childSpecHeight);
availableWidth -= child.getMeasuredWidth();
availableWidth -= spacing;
return availableWidth;
}
private int positionChild(View child, int x, int y, int contentHeight) {
int childWidth = child.getMeasuredWidth();
int childHeight = child.getMeasuredHeight();
int childTop = y + (contentHeight - childHeight) / 2;
child.layout(x, childTop, x + childWidth, childTop + childHeight);
return childWidth;
}
private int positionChildInverse(View child, int x, int y, int contentHeight) {
int childWidth = child.getMeasuredWidth();
int childHeight = child.getMeasuredHeight();
int childTop = y + (contentHeight - childHeight) / 2;
child.layout(x - childWidth, childTop, x, childTop + childHeight);
return childWidth;
}
@Override
public void onAnimationStart(Animator animation) {
}

View File

@@ -38,7 +38,6 @@ import android.text.TextUtils.TruncateAt;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.ActionMode;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
@@ -59,7 +58,7 @@ import android.widget.TextView;
/**
* @hide
*/
public class ActionBarView extends ViewGroup {
public class ActionBarView extends AbsActionBarView {
private static final String TAG = "ActionBarView";
/**
@@ -115,11 +114,8 @@ public class ActionBarView extends ViewGroup {
private boolean mIncludeTabs;
private MenuBuilder mOptionsMenu;
private ActionMenuView mMenuView;
private ActionMenuPresenter mActionMenuPresenter;
private ActionBarContextView mContextView;
private ViewGroup mSplitView;
private ActionMenuItem mLogoNavItem;
@@ -274,12 +270,6 @@ public class ActionBarView extends ViewGroup {
mTabLayout = tabLayout;
}
@Override
public ActionMode startActionModeForChild(View child, ActionMode.Callback callback) {
// No starting an action mode for an action bar child! (Where would it go?)
return null;
}
public void setCallback(OnNavigationListener callback) {
mCallback = callback;
}
@@ -288,7 +278,7 @@ public class ActionBarView extends ViewGroup {
if (menu == mOptionsMenu) return;
if (mOptionsMenu != null) {
mOptionsMenu.removeMenuPresenter(mActionMenuPresenter);
mOptionsMenu.removeMenuPresenter(mMenuPresenter);
}
MenuBuilder builder = (MenuBuilder) menu;
@@ -296,12 +286,12 @@ public class ActionBarView extends ViewGroup {
if (mMenuView != null) {
removeView(mMenuView);
}
if (mActionMenuPresenter == null) {
mActionMenuPresenter = new ActionMenuPresenter();
mActionMenuPresenter.setCallback(cb);
builder.addMenuPresenter(mActionMenuPresenter);
if (mMenuPresenter == null) {
mMenuPresenter = new ActionMenuPresenter();
mMenuPresenter.setCallback(cb);
builder.addMenuPresenter(mMenuPresenter);
}
final ActionMenuView menuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this);
final ActionMenuView menuView = (ActionMenuView) mMenuPresenter.getMenuView(this);
final LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.MATCH_PARENT);
menuView.setLayoutParams(layoutParams);
@@ -309,10 +299,12 @@ public class ActionBarView extends ViewGroup {
addView(menuView);
} else {
// Allow full screen width in split mode.
mActionMenuPresenter.setWidthLimit(
getContext().getResources().getDisplayMetrics().widthPixels);
mMenuPresenter.setWidthLimit(
getContext().getResources().getDisplayMetrics().widthPixels, true);
// No limit to the item count; use whatever will fit.
mActionMenuPresenter.setItemLimit(Integer.MAX_VALUE);
mMenuPresenter.setItemLimit(Integer.MAX_VALUE);
// Span the whole width
layoutParams.width = LayoutParams.MATCH_PARENT;
if (mSplitView != null) {
mSplitView.addView(menuView);
} // We'll add this later if we missed it this time.
@@ -320,59 +312,6 @@ public class ActionBarView extends ViewGroup {
mMenuView = menuView;
}
public void setSplitView(ViewGroup splitView) {
mSplitView = splitView;
splitView.setVisibility(VISIBLE);
if (mMenuView != null) {
splitView.addView(mMenuView);
}
}
public boolean showOverflowMenu() {
if (mActionMenuPresenter != null) {
return mActionMenuPresenter.showOverflowMenu();
}
return false;
}
public void openOverflowMenu() {
if (mActionMenuPresenter != null) {
showOverflowMenu();
}
}
public void postShowOverflowMenu() {
post(new Runnable() {
public void run() {
showOverflowMenu();
}
});
}
public boolean hideOverflowMenu() {
if (mActionMenuPresenter != null) {
return mActionMenuPresenter.hideOverflowMenu();
}
return false;
}
public boolean isOverflowMenuShowing() {
if (mActionMenuPresenter != null) {
return mActionMenuPresenter.isOverflowMenuShowing();
}
return false;
}
public boolean isOverflowReserved() {
return mActionMenuPresenter != null && mActionMenuPresenter.isOverflowReserved();
}
public void dismissPopupMenus() {
if (mActionMenuPresenter != null) {
mActionMenuPresenter.dismissPopupMenus();
}
}
public void setCustomNavigationView(View view) {
final boolean showCustom = (mDisplayOptions & ActionBar.DISPLAY_SHOW_CUSTOM) != 0;
if (mCustomNavView != null && showCustom) {
@@ -876,16 +815,6 @@ public class ActionBarView extends ViewGroup {
}
}
private int measureChildView(View child, int availableWidth, int childSpecHeight, int spacing) {
child.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST),
childSpecHeight);
availableWidth -= child.getMeasuredWidth();
availableWidth -= spacing;
return availableWidth;
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int x = getPaddingLeft();
@@ -998,26 +927,6 @@ public class ActionBarView extends ViewGroup {
}
}
private int positionChild(View child, int x, int y, int contentHeight) {
int childWidth = child.getMeasuredWidth();
int childHeight = child.getMeasuredHeight();
int childTop = y + (contentHeight - childHeight) / 2;
child.layout(x, childTop, x + childWidth, childTop + childHeight);
return childWidth;
}
private int positionChildInverse(View child, int x, int y, int contentHeight) {
int childWidth = child.getMeasuredWidth();
int childHeight = child.getMeasuredHeight();
int childTop = y + (contentHeight - childHeight) / 2;
child.layout(x - childWidth, childTop, x, childTop + childHeight);
return childWidth;
}
private static class TabView extends LinearLayout {
private ActionBar.Tab mTab;

View File

@@ -28,5 +28,6 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:ellipsize="end" />
android:ellipsize="end"
android:visibility="gone" />
</LinearLayout>

View File

@@ -43,7 +43,7 @@ This is an optimized layout for a screen with the Action Bar enabled.
android:layout_weight="1"
android:foregroundGravity="fill_horizontal|top"
android:foreground="?android:attr/windowContentOverlay" />
<LinearLayout android:id="@+id/lower_action_context_bar"
<com.android.internal.widget.ActionBarContainer android:id="@+id/split_action_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="?android:attr/actionBarStyle"

View File

@@ -46,7 +46,7 @@ the Action Bar enabled overlaying application content.
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/action_bar_container" />
<LinearLayout android:id="@+id/lower_action_context_bar"
<com.android.internal.widget.ActionBarContainer android:id="@+id/split_action_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"

View File

@@ -28,17 +28,15 @@ import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
import com.android.internal.view.RootViewSurfaceTaker;
import com.android.internal.view.StandaloneActionMode;
import com.android.internal.view.menu.ActionMenuView;
import com.android.internal.view.menu.ContextMenuBuilder;
import com.android.internal.view.menu.ListMenuPresenter;
import com.android.internal.view.menu.IconMenuPresenter;
import com.android.internal.view.menu.ListMenuPresenter;
import com.android.internal.view.menu.MenuBuilder;
import com.android.internal.view.menu.MenuDialogHelper;
import com.android.internal.view.menu.MenuItemImpl;
import com.android.internal.view.menu.MenuPopupHelper;
import com.android.internal.view.menu.MenuView;
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.ActionBarContainer;
import com.android.internal.widget.ActionBarContextView;
import com.android.internal.widget.ActionBarView;
@@ -625,7 +623,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
}
}
private void checkCloseActionMenu(Menu menu) {
void checkCloseActionMenu(Menu menu) {
if (mClosingActionMenu) {
return;
}
@@ -882,7 +880,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
final PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, true);
if (cb.onPreparePanel(FEATURE_OPTIONS_PANEL, st.createdPanelView, st.menu)) {
cb.onMenuOpened(FEATURE_ACTION_BAR, st.menu);
mActionBar.openOverflowMenu();
mActionBar.showOverflowMenu();
}
}
} else {
@@ -2591,11 +2589,15 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
final boolean splitActionBar = getWindowStyle().getBoolean(
com.android.internal.R.styleable.Window_windowSplitActionBar, false);
if (splitActionBar) {
final ViewGroup splitView = (ViewGroup) findViewById(
com.android.internal.R.id.lower_action_context_bar);
final ActionBarContainer splitView = (ActionBarContainer) findViewById(
com.android.internal.R.id.split_action_bar);
if (splitView != null) {
mActionBar.setSplitActionBar(splitActionBar);
mActionBar.setSplitView(splitView);
final ActionBarContextView cab = (ActionBarContextView) findViewById(
com.android.internal.R.id.action_context_bar);
cab.setSplitView(splitView);
} else {
Log.e(TAG, "Window style requested split action bar with " +
"incompatible window decor! Ignoring request.");