Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 04748bef authored by Adam Powell's avatar Adam Powell Committed by Android (Google) Code Review
Browse files

Merge "Refactoring of action bar internals"

parents df0a7fbd 640a66ea
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -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) {
+32 −81
Original line number Diff line number Diff line
@@ -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();
        }
    }

+18 −4
Original line number Diff line number Diff line
@@ -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);
                    }
                }

+122 −0
Original line number Diff line number Diff line
@@ -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;
        }
    }
}
+2 −0
Original line number Diff line number Diff line
@@ -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) {
Loading