FileDocCategorySizeDatePackage
ActionBarOverlayLayout.javaAPI DocAndroid 5.1 API30199Thu Mar 12 22:22:56 GMT 2015android.support.v7.internal.widget

ActionBarOverlayLayout

public class ActionBarOverlayLayout extends android.view.ViewGroup implements DecorContentParent
Special layout for the containing of an overlay action bar (and its content) to correctly handle fitting system windows when the content has request that its layout ignore them.
hide

Fields Summary
private static final String
TAG
private int
mActionBarHeight
private int
mWindowVisibility
private ContentFrameLayout
mContent
private ActionBarContainer
mActionBarBottom
private ActionBarContainer
mActionBarTop
private DecorToolbar
mDecorToolbar
private android.graphics.drawable.Drawable
mWindowContentOverlay
private boolean
mIgnoreWindowContentOverlay
private boolean
mOverlayMode
private boolean
mHasNonEmbeddedTabs
private boolean
mHideOnContentScroll
private boolean
mAnimatingForFling
private int
mHideOnContentScrollReference
private int
mLastSystemUiVisibility
private final android.graphics.Rect
mBaseContentInsets
private final android.graphics.Rect
mLastBaseContentInsets
private final android.graphics.Rect
mContentInsets
private final android.graphics.Rect
mBaseInnerInsets
private final android.graphics.Rect
mInnerInsets
private final android.graphics.Rect
mLastInnerInsets
private ActionBarVisibilityCallback
mActionBarVisibilityCallback
private final int
ACTION_BAR_ANIMATE_DELAY
private android.support.v4.widget.ScrollerCompat
mFlingEstimator
private android.support.v4.view.ViewPropertyAnimatorCompat
mCurrentActionBarTopAnimator
private android.support.v4.view.ViewPropertyAnimatorCompat
mCurrentActionBarBottomAnimator
private final android.support.v4.view.ViewPropertyAnimatorListener
mTopAnimatorListener
private final android.support.v4.view.ViewPropertyAnimatorListener
mBottomAnimatorListener
private final Runnable
mRemoveActionBarHideOffset
private final Runnable
mAddActionBarHideOffset
static final int[]
ATTRS
Constructors Summary
public ActionBarOverlayLayout(android.content.Context context)


       
        super(context);
        init(context);
    
public ActionBarOverlayLayout(android.content.Context context, android.util.AttributeSet attrs)

        super(context, attrs);
        init(context);
    
Methods Summary
private voidaddActionBarHideOffset()

        haltActionBarHideOffsetAnimations();
        mAddActionBarHideOffset.run();
    
private booleanapplyInsets(android.view.View view, android.graphics.Rect insets, boolean left, boolean top, boolean bottom, boolean right)

        boolean changed = false;
        LayoutParams lp = (LayoutParams)view.getLayoutParams();
        if (left && lp.leftMargin != insets.left) {
            changed = true;
            lp.leftMargin = insets.left;
        }
        if (top && lp.topMargin != insets.top) {
            changed = true;
            lp.topMargin = insets.top;
        }
        if (right && lp.rightMargin != insets.right) {
            changed = true;
            lp.rightMargin = insets.right;
        }
        if (bottom && lp.bottomMargin != insets.bottom) {
            changed = true;
            lp.bottomMargin = insets.bottom;
        }
        return changed;
    
public booleancanShowOverflowMenu()

        pullChildren();
        return mDecorToolbar.canShowOverflowMenu();
    
protected booleancheckLayoutParams(ViewGroup.LayoutParams p)

        return p instanceof LayoutParams;
    
public voiddismissPopups()

        pullChildren();
        mDecorToolbar.dismissPopupMenus();
    
public voiddraw(android.graphics.Canvas c)

        super.draw(c);
        if (mWindowContentOverlay != null && !mIgnoreWindowContentOverlay) {
            final int top = mActionBarTop.getVisibility() == VISIBLE ?
                    (int) (mActionBarTop.getBottom() + ViewCompat.getTranslationY(mActionBarTop) + 0.5f)
                    : 0;
            mWindowContentOverlay.setBounds(0, top, getWidth(),
                    top + mWindowContentOverlay.getIntrinsicHeight());
            mWindowContentOverlay.draw(c);
        }
    
protected booleanfitSystemWindows(android.graphics.Rect insets)

        pullChildren();

        final int vis = ViewCompat.getWindowSystemUiVisibility(this);
        final boolean stable = (vis & SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0;
        final Rect systemInsets = insets;

        // The top and bottom action bars are always within the content area.
        boolean changed = applyInsets(mActionBarTop, systemInsets, true, true, false, true);
        if (mActionBarBottom != null) {
            changed |= applyInsets(mActionBarBottom, systemInsets, true, false, true, true);
        }

        mBaseInnerInsets.set(systemInsets);
        ViewUtils.computeFitSystemWindows(this, mBaseInnerInsets, mBaseContentInsets);
        if (!mLastBaseContentInsets.equals(mBaseContentInsets)) {
            changed = true;
            mLastBaseContentInsets.set(mBaseContentInsets);
        }

        if (changed) {
            requestLayout();
        }

        // We don't do any more at this point.  To correctly compute the content/inner
        // insets in all cases, we need to know the measured size of the various action
        // bar elements. fitSystemWindows() happens before the measure pass, so we can't
        // do that here. Instead we will take this up in onMeasure().
        return true;
    
protected android.support.v7.internal.widget.ActionBarOverlayLayout$LayoutParamsgenerateDefaultLayoutParams()

        return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
    
public android.support.v7.internal.widget.ActionBarOverlayLayout$LayoutParamsgenerateLayoutParams(android.util.AttributeSet attrs)

        return new LayoutParams(getContext(), attrs);
    
protected ViewGroup.LayoutParamsgenerateLayoutParams(ViewGroup.LayoutParams p)

        return new LayoutParams(p);
    
public intgetActionBarHideOffset()

        return mActionBarTop != null ? -((int) ViewCompat.getTranslationY(mActionBarTop)) : 0;
    
private DecorToolbargetDecorToolbar(android.view.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 java.lang.CharSequencegetTitle()

        pullChildren();
        return mDecorToolbar.getTitle();
    
private voidhaltActionBarHideOffsetAnimations()

        removeCallbacks(mRemoveActionBarHideOffset);
        removeCallbacks(mAddActionBarHideOffset);
        if (mCurrentActionBarTopAnimator != null) {
            mCurrentActionBarTopAnimator.cancel();
        }
        if (mCurrentActionBarBottomAnimator != null) {
            mCurrentActionBarBottomAnimator.cancel();
        }
    
public booleanhasIcon()

        pullChildren();
        return mDecorToolbar.hasIcon();
    
public booleanhasLogo()

        pullChildren();
        return mDecorToolbar.hasLogo();
    
public booleanhideOverflowMenu()

        pullChildren();
        return mDecorToolbar.hideOverflowMenu();
    
private voidinit(android.content.Context context)

        TypedArray ta = getContext().getTheme().obtainStyledAttributes(ATTRS);
        mActionBarHeight = ta.getDimensionPixelSize(0, 0);
        mWindowContentOverlay = ta.getDrawable(1);
        setWillNotDraw(mWindowContentOverlay == null);
        ta.recycle();

        mIgnoreWindowContentOverlay = context.getApplicationInfo().targetSdkVersion <
                Build.VERSION_CODES.KITKAT;

        mFlingEstimator = ScrollerCompat.create(context);
    
public voidinitFeature(int windowFeature)

        pullChildren();
        switch (windowFeature) {
            case Window.FEATURE_PROGRESS:
                mDecorToolbar.initProgress();
                break;
            case Window.FEATURE_INDETERMINATE_PROGRESS:
                mDecorToolbar.initIndeterminateProgress();
                break;
            case Window.FEATURE_ACTION_BAR_OVERLAY:
                setOverlayMode(true);
                break;
        }
    
public booleanisHideOnContentScrollEnabled()

        return mHideOnContentScroll;
    
public booleanisInOverlayMode()

        return mOverlayMode;
    
public booleanisOverflowMenuShowPending()

        pullChildren();
        return mDecorToolbar.isOverflowMenuShowPending();
    
public booleanisOverflowMenuShowing()

        pullChildren();
        return mDecorToolbar.isOverflowMenuShowing();
    
protected voidonConfigurationChanged(android.content.res.Configuration newConfig)

        if (Build.VERSION.SDK_INT >= 8) {
            super.onConfigurationChanged(newConfig);
        }
        init(getContext());
        ViewCompat.requestApplyInsets(this);
    
protected voidonDetachedFromWindow()

        super.onDetachedFromWindow();
        haltActionBarHideOffsetAnimations();
    
protected voidonLayout(boolean changed, int left, int top, int right, int bottom)

        final int count = getChildCount();

        final int parentLeft = getPaddingLeft();
        final int parentRight = right - left - getPaddingRight();

        final int parentTop = getPaddingTop();
        final int parentBottom = bottom - top - getPaddingBottom();

        for (int i = 0; i < count; i++) {
            final View child = getChildAt(i);
            if (child.getVisibility() != GONE) {
                final LayoutParams lp = (LayoutParams) child.getLayoutParams();

                final int width = child.getMeasuredWidth();
                final int height = child.getMeasuredHeight();

                int childLeft = parentLeft + lp.leftMargin;
                int childTop;
                if (child == mActionBarBottom) {
                    childTop = parentBottom - height - lp.bottomMargin;
                } else {
                    childTop = parentTop + lp.topMargin;
                }

                child.layout(childLeft, childTop, childLeft + width, childTop + height);
            }
        }
    
protected voidonMeasure(int widthMeasureSpec, int heightMeasureSpec)

        pullChildren();

        int maxHeight = 0;
        int maxWidth = 0;
        int childState = 0;

        int topInset = 0;
        int bottomInset = 0;

        measureChildWithMargins(mActionBarTop, widthMeasureSpec, 0, heightMeasureSpec, 0);
        LayoutParams lp = (LayoutParams) mActionBarTop.getLayoutParams();
        maxWidth = Math.max(maxWidth,
                mActionBarTop.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);
        maxHeight = Math.max(maxHeight,
                mActionBarTop.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);
        childState = ViewUtils.combineMeasuredStates(childState,
                ViewCompat.getMeasuredState(mActionBarTop));

        // xlarge screen layout doesn't have bottom action bar.
        if (mActionBarBottom != null) {
            measureChildWithMargins(mActionBarBottom, widthMeasureSpec, 0, heightMeasureSpec, 0);
            lp = (LayoutParams) mActionBarBottom.getLayoutParams();
            maxWidth = Math.max(maxWidth,
                    mActionBarBottom.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);
            maxHeight = Math.max(maxHeight,
                    mActionBarBottom.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);
            childState = ViewUtils.combineMeasuredStates(childState,
                    ViewCompat.getMeasuredState(mActionBarBottom));
        }

        final int vis = ViewCompat.getWindowSystemUiVisibility(this);
        final boolean stable = (vis & SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0;

        if (stable) {
            // This is the standard space needed for the action bar.  For stable measurement,
            // we can't depend on the size currently reported by it -- this must remain constant.
            topInset = mActionBarHeight;
            if (mHasNonEmbeddedTabs) {
                final View tabs = mActionBarTop.getTabContainer();
                if (tabs != null) {
                    // If tabs are not embedded, increase space on top to account for them.
                    topInset += mActionBarHeight;
                }
            }
        } else if (mActionBarTop.getVisibility() != GONE) {
            // This is the space needed on top of the window for all of the action bar
            // and tabs.
            topInset = mActionBarTop.getMeasuredHeight();
        }

        if (mDecorToolbar.isSplit()) {
            // If action bar is split, adjust bottom insets for it.
            if (mActionBarBottom != null) {
                if (stable) {
                    bottomInset = mActionBarHeight;
                } else {
                    bottomInset = mActionBarBottom.getMeasuredHeight();
                }
            }
        }

        // If the window has not requested system UI layout flags, we need to
        // make sure its content is not being covered by system UI...  though it
        // will still be covered by the action bar if they have requested it to
        // overlay.
        mContentInsets.set(mBaseContentInsets);
        mInnerInsets.set(mBaseInnerInsets);
        if (!mOverlayMode && !stable) {
            mContentInsets.top += topInset;
            mContentInsets.bottom += bottomInset;
        } else {
            mInnerInsets.top += topInset;
            mInnerInsets.bottom += bottomInset;
        }
        applyInsets(mContent, mContentInsets, true, true, true, true);

        if (!mLastInnerInsets.equals(mInnerInsets)) {
            // If the inner insets have changed, we need to dispatch this down to
            // the app's fitSystemWindows().  We do this before measuring the content
            // view to keep the same semantics as the normal fitSystemWindows() call.
            mLastInnerInsets.set(mInnerInsets);

            mContent.dispatchFitSystemWindows(mInnerInsets);
        }

        measureChildWithMargins(mContent, widthMeasureSpec, 0, heightMeasureSpec, 0);
        lp = (LayoutParams) mContent.getLayoutParams();
        maxWidth = Math.max(maxWidth,
                mContent.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);
        maxHeight = Math.max(maxHeight,
                mContent.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);
        childState = ViewUtils.combineMeasuredStates(childState,
                ViewCompat.getMeasuredState(mContent));

        // Account for padding too
        maxWidth += getPaddingLeft() + getPaddingRight();
        maxHeight += getPaddingTop() + getPaddingBottom();

        // Check against our minimum height and width
        maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
        maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());

        setMeasuredDimension(
                ViewCompat.resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
                ViewCompat.resolveSizeAndState(maxHeight, heightMeasureSpec,
                        childState << MEASURED_HEIGHT_STATE_SHIFT));
    
public booleanonNestedFling(android.view.View target, float velocityX, float velocityY, boolean consumed)

        if (!mHideOnContentScroll || !consumed) {
            return false;
        }
        if (shouldHideActionBarOnFling(velocityX, velocityY)) {
            addActionBarHideOffset();
        } else {
            removeActionBarHideOffset();
        }
        mAnimatingForFling = true;
        return true;
    
public voidonNestedScroll(android.view.View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed)

        mHideOnContentScrollReference += dyConsumed;
        setActionBarHideOffset(mHideOnContentScrollReference);
    
public voidonNestedScrollAccepted(android.view.View child, android.view.View target, int axes)

        super.onNestedScrollAccepted(child, target, axes);
        mHideOnContentScrollReference = getActionBarHideOffset();
        haltActionBarHideOffsetAnimations();
        if (mActionBarVisibilityCallback != null) {
            mActionBarVisibilityCallback.onContentScrollStarted();
        }
    
public booleanonStartNestedScroll(android.view.View child, android.view.View target, int axes)

        if ((axes & SCROLL_AXIS_VERTICAL) == 0 || mActionBarTop.getVisibility() != VISIBLE) {
            return false;
        }
        return mHideOnContentScroll;
    
public voidonStopNestedScroll(android.view.View target)

        super.onStopNestedScroll(target);
        if (mHideOnContentScroll && !mAnimatingForFling) {
            if (mHideOnContentScrollReference <= mActionBarTop.getHeight()) {
                postRemoveActionBarHideOffset();
            } else {
                postAddActionBarHideOffset();
            }
        }
        if (mActionBarVisibilityCallback != null) {
            mActionBarVisibilityCallback.onContentScrollStopped();
        }
    
public voidonWindowSystemUiVisibilityChanged(int visible)

        if (Build.VERSION.SDK_INT >= 16) {
            super.onWindowSystemUiVisibilityChanged(visible);
        }
        pullChildren();
        final int diff = mLastSystemUiVisibility ^ visible;
        mLastSystemUiVisibility = visible;
        final boolean barVisible = (visible & SYSTEM_UI_FLAG_FULLSCREEN) == 0;
        final boolean stable = (visible & SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0;
        if (mActionBarVisibilityCallback != null) {
            // We want the bar to be visible if it is not being hidden,
            // or the app has not turned on a stable UI mode (meaning they
            // are performing explicit layout around the action bar).
            mActionBarVisibilityCallback.enableContentAnimations(!stable);
            if (barVisible || !stable) mActionBarVisibilityCallback.showForSystem();
            else mActionBarVisibilityCallback.hideForSystem();
        }
        if ((diff & SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0) {
            if (mActionBarVisibilityCallback != null) {
                ViewCompat.requestApplyInsets(this);
            }
        }
    
protected voidonWindowVisibilityChanged(int visibility)

        super.onWindowVisibilityChanged(visibility);
        mWindowVisibility = visibility;
        if (mActionBarVisibilityCallback != null) {
            mActionBarVisibilityCallback.onWindowVisibilityChanged(visibility);
        }
    
private voidpostAddActionBarHideOffset()

        haltActionBarHideOffsetAnimations();
        postDelayed(mAddActionBarHideOffset, ACTION_BAR_ANIMATE_DELAY);
    
private voidpostRemoveActionBarHideOffset()

        haltActionBarHideOffsetAnimations();
        postDelayed(mRemoveActionBarHideOffset, ACTION_BAR_ANIMATE_DELAY);
    
voidpullChildren()

        if (mContent == null) {
            mContent = (ContentFrameLayout) findViewById(R.id.action_bar_activity_content);
            mActionBarTop = (ActionBarContainer) findViewById(R.id.action_bar_container);
            mDecorToolbar = getDecorToolbar(findViewById(R.id.action_bar));
            mActionBarBottom = (ActionBarContainer) findViewById(R.id.split_action_bar);
        }
    
private voidremoveActionBarHideOffset()

        haltActionBarHideOffsetAnimations();
        mRemoveActionBarHideOffset.run();
    
public voidrestoreToolbarHierarchyState(android.util.SparseArray toolbarStates)

        pullChildren();
        mDecorToolbar.restoreHierarchyState(toolbarStates);
    
public voidsaveToolbarHierarchyState(android.util.SparseArray toolbarStates)

        pullChildren();
        mDecorToolbar.saveHierarchyState(toolbarStates);
    
public voidsetActionBarHideOffset(int offset)

        haltActionBarHideOffsetAnimations();
        final int topHeight = mActionBarTop.getHeight();
        offset = Math.max(0, Math.min(offset, topHeight));
        ViewCompat.setTranslationY(mActionBarTop, -offset);
        if (mActionBarBottom != null && mActionBarBottom.getVisibility() != GONE) {
            // Match the hide offset proportionally for a split bar
            final float fOffset = (float) offset / topHeight;
            final int bOffset = (int) (mActionBarBottom.getHeight() * fOffset);
            ViewCompat.setTranslationY(mActionBarBottom, bOffset);
        }
    
public voidsetActionBarVisibilityCallback(android.support.v7.internal.widget.ActionBarOverlayLayout$ActionBarVisibilityCallback cb)

        mActionBarVisibilityCallback = cb;
        if (getWindowToken() != null) {
            // This is being initialized after being added to a window;
            // make sure to update all state now.
            mActionBarVisibilityCallback.onWindowVisibilityChanged(mWindowVisibility);
            if (mLastSystemUiVisibility != 0) {
                int newVis = mLastSystemUiVisibility;
                onWindowSystemUiVisibilityChanged(newVis);
                ViewCompat.requestApplyInsets(this);
            }
        }
    
public voidsetHasNonEmbeddedTabs(boolean hasNonEmbeddedTabs)

        mHasNonEmbeddedTabs = hasNonEmbeddedTabs;
    
public voidsetHideOnContentScrollEnabled(boolean hideOnContentScroll)

        if (hideOnContentScroll != mHideOnContentScroll) {
            mHideOnContentScroll = hideOnContentScroll;
            if (!hideOnContentScroll) {
                if (VersionUtils.isAtLeastL()) {
                    stopNestedScroll();
                }
                haltActionBarHideOffsetAnimations();
                setActionBarHideOffset(0);
            }
        }
    
public voidsetIcon(int resId)

        pullChildren();
        mDecorToolbar.setIcon(resId);
    
public voidsetIcon(android.graphics.drawable.Drawable d)

        pullChildren();
        mDecorToolbar.setIcon(d);
    
public voidsetLogo(int resId)

        pullChildren();
        mDecorToolbar.setLogo(resId);
    
public voidsetMenu(android.view.Menu menu, MenuPresenter.Callback cb)

        pullChildren();
        mDecorToolbar.setMenu(menu, cb);
    
public voidsetMenuPrepared()

        pullChildren();
        mDecorToolbar.setMenuPrepared();
    
public voidsetOverlayMode(boolean overlayMode)

        mOverlayMode = overlayMode;

        /*
         * Drawing the window content overlay was broken before K so starting to draw it
         * again unexpectedly will cause artifacts in some apps. They should fix it.
         */
        mIgnoreWindowContentOverlay = overlayMode &&
                getContext().getApplicationInfo().targetSdkVersion <
                        Build.VERSION_CODES.KITKAT;
    
public voidsetShowingForActionMode(boolean showing)

        // TODO: Add workaround for this
//        if (showing) {
//            // Here's a fun hack: if the status bar is currently being hidden,
//            // and the application has asked for stable content insets, then
//            // we will end up with the action mode action bar being shown
//            // without the status bar, but moved below where the status bar
//            // would be.  Not nice.  Trying to have this be positioned
//            // correctly is not easy (basically we need yet *another* content
//            // inset from the window manager to know where to put it), so
//            // instead we will just temporarily force the status bar to be shown.
//            if ((getWindowSystemUiVisibility() & (SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
//                    | SYSTEM_UI_FLAG_LAYOUT_STABLE))
//                    == (SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | SYSTEM_UI_FLAG_LAYOUT_STABLE)) {
//                setDisabledSystemUiVisibility(SYSTEM_UI_FLAG_FULLSCREEN);
//            }
//        } else {
//            setDisabledSystemUiVisibility(0);
//        }
    
public voidsetUiOptions(int uiOptions)

        // Split Action Bar not included.
    
public voidsetWindowCallback(android.support.v7.internal.app.WindowCallback cb)

        pullChildren();
        mDecorToolbar.setWindowCallback(cb);
    
public voidsetWindowTitle(java.lang.CharSequence title)

        pullChildren();
        mDecorToolbar.setWindowTitle(title);
    
public booleanshouldDelayChildPressedState()

        return false;
    
private booleanshouldHideActionBarOnFling(float velocityX, float velocityY)

        mFlingEstimator.fling(0, 0, 0, (int) velocityY, 0, 0, Integer.MIN_VALUE, Integer.MAX_VALUE);
        final int finalY = mFlingEstimator.getFinalY();
        return finalY > mActionBarTop.getHeight();
    
public booleanshowOverflowMenu()

        pullChildren();
        return mDecorToolbar.showOverflowMenu();