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

Commit 9b0dc289 authored by Adam Powell's avatar Adam Powell
Browse files

Fix a regression where android:windowContentOverlay did not draw properly.

This was the victim of an earlier refactoring. Have the
ActionBarOverlayLayout draw this directly over the content so that it
can stay properly in sync with any animations and also remove an extra
couple of views from the decor layout.

Some apps now expect the broken behavior in default themes. Protect
them from themselves until they bump their targetSdkVersion.

Public bug https://code.google.com/p/android/issues/detail?id=58280

Change-Id: I4284503577e322f3e68d4a7fabda8441d3749b98
parent 3a6f2551
Loading
Loading
Loading
Loading
+38 −31
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.internal.app;

import android.animation.ValueAnimator;
import android.view.ViewParent;
import com.android.internal.view.ActionBarPolicy;
import com.android.internal.view.menu.MenuBuilder;
import com.android.internal.view.menu.MenuPopupHelper;
@@ -75,7 +77,6 @@ public class ActionBarImpl extends ActionBar {

    private ActionBarOverlayLayout mOverlayLayout;
    private ActionBarContainer mContainerView;
    private ViewGroup mTopVisibilityView;
    private ActionBarView mActionView;
    private ActionBarContextView mContextView;
    private ActionBarContainer mSplitView;
@@ -125,12 +126,12 @@ public class ActionBarImpl extends ActionBar {
        public void onAnimationEnd(Animator animation) {
            if (mContentAnimations && mContentView != null) {
                mContentView.setTranslationY(0);
                mTopVisibilityView.setTranslationY(0);
                mContainerView.setTranslationY(0);
            }
            if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) {
                mSplitView.setVisibility(View.GONE);
            }
            mTopVisibilityView.setVisibility(View.GONE);
            mContainerView.setVisibility(View.GONE);
            mContainerView.setTransitioning(false);
            mCurrentShowAnim = null;
            completeDeferredDestroyActionMode();
@@ -144,7 +145,16 @@ public class ActionBarImpl extends ActionBar {
        @Override
        public void onAnimationEnd(Animator animation) {
            mCurrentShowAnim = null;
            mTopVisibilityView.requestLayout();
            mContainerView.requestLayout();
        }
    };

    final ValueAnimator.AnimatorUpdateListener mUpdateListener =
            new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            final ViewParent parent = mContainerView.getParent();
            ((View) parent).invalidate();
        }
    };

@@ -153,7 +163,7 @@ public class ActionBarImpl extends ActionBar {
        Window window = activity.getWindow();
        View decor = window.getDecorView();
        boolean overlayMode = mActivity.getWindow().hasFeature(Window.FEATURE_ACTION_BAR_OVERLAY);
        init(decor, overlayMode);
        init(decor);
        if (!overlayMode) {
            mContentView = decor.findViewById(android.R.id.content);
        }
@@ -161,26 +171,21 @@ public class ActionBarImpl extends ActionBar {

    public ActionBarImpl(Dialog dialog) {
        mDialog = dialog;
        init(dialog.getWindow().getDecorView(), false);
        init(dialog.getWindow().getDecorView());
    }

    private void init(View decor, boolean overlayMode) {
    private void init(View decor) {
        mContext = decor.getContext();
        mOverlayLayout = (ActionBarOverlayLayout) decor.findViewById(
                com.android.internal.R.id.action_bar_overlay_layout);
        if (mOverlayLayout != null) {
            mOverlayLayout.setActionBar(this, overlayMode);
            mOverlayLayout.setActionBar(this);
        }
        mActionView = (ActionBarView) 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(
                com.android.internal.R.id.action_bar_container);
        mTopVisibilityView = (ViewGroup)decor.findViewById(
                com.android.internal.R.id.top_action_bar);
        if (mTopVisibilityView == null) {
            mTopVisibilityView = mContainerView;
        }
        mSplitView = (ActionBarContainer) decor.findViewById(
                com.android.internal.R.id.split_action_bar);

@@ -675,29 +680,30 @@ public class ActionBarImpl extends ActionBar {
        if (mCurrentShowAnim != null) {
            mCurrentShowAnim.end();
        }
        mTopVisibilityView.setVisibility(View.VISIBLE);
        mContainerView.setVisibility(View.VISIBLE);

        if (mCurWindowVisibility == View.VISIBLE && (mShowHideAnimationEnabled
                || fromSystem)) {
            mTopVisibilityView.setTranslationY(0); // because we're about to ask its window loc
            float startingY = -mTopVisibilityView.getHeight();
            mContainerView.setTranslationY(0); // because we're about to ask its window loc
            float startingY = -mContainerView.getHeight();
            if (fromSystem) {
                int topLeft[] = {0, 0};
                mTopVisibilityView.getLocationInWindow(topLeft);
                mContainerView.getLocationInWindow(topLeft);
                startingY -= topLeft[1];
            }
            mTopVisibilityView.setTranslationY(startingY);
            mContainerView.setTranslationY(startingY);
            AnimatorSet anim = new AnimatorSet();
            AnimatorSet.Builder b = anim.play(ObjectAnimator.ofFloat(mTopVisibilityView,
                    "translationY", 0));
            ObjectAnimator a = ObjectAnimator.ofFloat(mContainerView, View.TRANSLATION_Y, 0);
            a.addUpdateListener(mUpdateListener);
            AnimatorSet.Builder b = anim.play(a);
            if (mContentAnimations && mContentView != null) {
                b.with(ObjectAnimator.ofFloat(mContentView, "translationY",
                b.with(ObjectAnimator.ofFloat(mContentView, View.TRANSLATION_Y,
                        startingY, 0));
            }
            if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) {
                mSplitView.setTranslationY(mSplitView.getHeight());
                mSplitView.setVisibility(View.VISIBLE);
                b.with(ObjectAnimator.ofFloat(mSplitView, "translationY", 0));
                b.with(ObjectAnimator.ofFloat(mSplitView, View.TRANSLATION_Y, 0));
            }
            anim.setInterpolator(AnimationUtils.loadInterpolator(mContext,
                    com.android.internal.R.interpolator.decelerate_cubic));
@@ -713,8 +719,8 @@ public class ActionBarImpl extends ActionBar {
            mCurrentShowAnim = anim;
            anim.start();
        } else {
            mTopVisibilityView.setAlpha(1);
            mTopVisibilityView.setTranslationY(0);
            mContainerView.setAlpha(1);
            mContainerView.setTranslationY(0);
            if (mContentAnimations && mContentView != null) {
                mContentView.setTranslationY(0);
            }
@@ -737,24 +743,25 @@ public class ActionBarImpl extends ActionBar {

        if (mCurWindowVisibility == View.VISIBLE && (mShowHideAnimationEnabled
                || fromSystem)) {
            mTopVisibilityView.setAlpha(1);
            mContainerView.setAlpha(1);
            mContainerView.setTransitioning(true);
            AnimatorSet anim = new AnimatorSet();
            float endingY = -mTopVisibilityView.getHeight();
            float endingY = -mContainerView.getHeight();
            if (fromSystem) {
                int topLeft[] = {0, 0};
                mTopVisibilityView.getLocationInWindow(topLeft);
                mContainerView.getLocationInWindow(topLeft);
                endingY -= topLeft[1];
            }
            AnimatorSet.Builder b = anim.play(ObjectAnimator.ofFloat(mTopVisibilityView,
                    "translationY", endingY));
            ObjectAnimator a = ObjectAnimator.ofFloat(mContainerView, View.TRANSLATION_Y, endingY);
            a.addUpdateListener(mUpdateListener);
            AnimatorSet.Builder b = anim.play(a);
            if (mContentAnimations && mContentView != null) {
                b.with(ObjectAnimator.ofFloat(mContentView, "translationY",
                b.with(ObjectAnimator.ofFloat(mContentView, View.TRANSLATION_Y,
                        0, endingY));
            }
            if (mSplitView != null && mSplitView.getVisibility() == View.VISIBLE) {
                mSplitView.setAlpha(1);
                b.with(ObjectAnimator.ofFloat(mSplitView, "translationY",
                b.with(ObjectAnimator.ofFloat(mSplitView, View.TRANSLATION_Y,
                        mSplitView.getHeight()));
            }
            anim.setInterpolator(AnimationUtils.loadInterpolator(mContext,
+50 −13
Original line number Diff line number Diff line
@@ -16,6 +16,10 @@

package com.android.internal.widget;

import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.util.Log;
import android.view.ViewGroup;
import com.android.internal.app.ActionBarImpl;

@@ -31,18 +35,23 @@ import android.view.View;
 * has request that its layout ignore them.
 */
public class ActionBarOverlayLayout extends ViewGroup {
    private static final String TAG = "ActionBarOverlayLayout";

    private int mActionBarHeight;
    private ActionBarImpl mActionBar;
    private int mWindowVisibility = View.VISIBLE;

    // The main UI elements that we handle the layout of.
    private View mContent;
    private View mActionBarTop;
    private View mActionBarBottom;
    private ActionBarContainer mActionBarTop;

    // Some interior UI elements.
    private ActionBarContainer mContainerView;
    private ActionBarView mActionView;
    private ActionBarView mActionBarView;

    // Content overlay drawable - generally the action bar's shadow
    private Drawable mWindowContentOverlay;
    private boolean mIgnoreWindowContentOverlay;

    private boolean mOverlayMode;
    private int mLastSystemUiVisibility;
@@ -53,8 +62,9 @@ public class ActionBarOverlayLayout extends ViewGroup {
    private final Rect mInnerInsets = new Rect();
    private final Rect mLastInnerInsets = new Rect();

    static final int[] mActionBarSizeAttr = new int [] {
            com.android.internal.R.attr.actionBarSize
    static final int[] ATTRS = new int [] {
            com.android.internal.R.attr.actionBarSize,
            com.android.internal.R.attr.windowContentOverlay
    };

    public ActionBarOverlayLayout(Context context) {
@@ -68,14 +78,18 @@ public class ActionBarOverlayLayout extends ViewGroup {
    }

    private void init(Context context) {
        TypedArray ta = getContext().getTheme().obtainStyledAttributes(mActionBarSizeAttr);
        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.KEY_LIME_PIE;
    }

    public void setActionBar(ActionBarImpl impl, boolean overlayMode) {
    public void setActionBar(ActionBarImpl impl) {
        mActionBar = impl;
        mOverlayMode = overlayMode;
        if (getWindowToken() != null) {
            // This is being initialized after being added to a window;
            // make sure to update all state now.
@@ -88,6 +102,18 @@ public class ActionBarOverlayLayout extends ViewGroup {
        }
    }

    public void setOverlayMode(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.KEY_LIME_PIE;
    }

    public void setShowingForActionMode(boolean showing) {
        if (showing) {
            // Here's a fun hack: if the status bar is currently being hidden,
@@ -253,7 +279,7 @@ public class ActionBarOverlayLayout extends ViewGroup {
            // we can't depend on the size currently reported by it -- this must remain constant.
            topInset = mActionBarHeight;
            if (mActionBar != null && mActionBar.hasNonEmbeddedTabs()) {
                View tabs = mContainerView.getTabContainer();
                View tabs = mActionBarTop.getTabContainer();
                if (tabs != null) {
                    // If tabs are not embedded, increase space on top to account for them.
                    topInset += mActionBarHeight;
@@ -265,7 +291,7 @@ public class ActionBarOverlayLayout extends ViewGroup {
            topInset = mActionBarTop.getMeasuredHeight();
        }

        if (mActionView.isSplitActionBar()) {
        if (mActionBarView.isSplitActionBar()) {
            // If action bar is split, adjust bottom insets for it.
            if (mActionBarBottom != null) {
                if (stable) {
@@ -351,6 +377,18 @@ public class ActionBarOverlayLayout extends ViewGroup {
        }
    }

    @Override
    public void draw(Canvas c) {
        super.draw(c);
        if (mWindowContentOverlay != null && !mIgnoreWindowContentOverlay) {
            final int top = mActionBarTop.getVisibility() == VISIBLE ?
                    (int) (mActionBarTop.getBottom() + mActionBarTop.getTranslationY() + 0.5f) : 0;
            mWindowContentOverlay.setBounds(0, top, getWidth(),
                    top + mWindowContentOverlay.getIntrinsicHeight());
            mWindowContentOverlay.draw(c);
        }
    }

    @Override
    public boolean shouldDelayChildPressedState() {
        return false;
@@ -359,10 +397,9 @@ public class ActionBarOverlayLayout extends ViewGroup {
    void pullChildren() {
        if (mContent == null) {
            mContent = findViewById(com.android.internal.R.id.content);
            mActionBarTop = findViewById(com.android.internal.R.id.top_action_bar);
            mContainerView = (ActionBarContainer)findViewById(
            mActionBarTop = (ActionBarContainer)findViewById(
                    com.android.internal.R.id.action_bar_container);
            mActionView = (ActionBarView) findViewById(com.android.internal.R.id.action_bar);
            mActionBarView = (ActionBarView) findViewById(com.android.internal.R.id.action_bar);
            mActionBarBottom = findViewById(com.android.internal.R.id.split_action_bar);
        }
    }
+17 −24
Original line number Diff line number Diff line
@@ -28,10 +28,8 @@ the Action Bar enabled overlaying application content.
    <FrameLayout android:id="@android:id/content"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
    <LinearLayout android:id="@+id/top_action_bar"
                  android:layout_width="match_parent"
                  android:layout_height="wrap_content">
        <com.android.internal.widget.ActionBarContainer android:id="@+id/action_bar_container"
    <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"
@@ -49,9 +47,4 @@ the Action Bar enabled overlaying application content.
            android:visibility="gone"
            style="?android:attr/actionModeStyle" />
    </com.android.internal.widget.ActionBarContainer>
        <ImageView android:src="?android:attr/windowContentOverlay"
                   android:scaleType="fitXY"
                   android:layout_width="match_parent"
                   android:layout_height="wrap_content" />
    </LinearLayout>
</com.android.internal.widget.ActionBarOverlayLayout>
+18 −25
Original line number Diff line number Diff line
@@ -27,10 +27,8 @@ This is an optimized layout for a screen with the Action Bar enabled.
    <FrameLayout android:id="@android:id/content"
                 android:layout_width="match_parent"
                 android:layout_height="match_parent" />
    <LinearLayout android:id="@+id/top_action_bar"
                  android:layout_width="match_parent"
                  android:layout_height="wrap_content">
        <com.android.internal.widget.ActionBarContainer android:id="@+id/action_bar_container"
    <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"
@@ -48,11 +46,6 @@ This is an optimized layout for a screen with the Action Bar enabled.
            android:visibility="gone"
            style="?android:attr/actionModeStyle" />
    </com.android.internal.widget.ActionBarContainer>
        <ImageView android:src="?android:attr/windowContentOverlay"
                   android:scaleType="fitXY"
                   android:layout_width="match_parent"
                   android:layout_height="wrap_content" />
    </LinearLayout>
    <com.android.internal.widget.ActionBarContainer android:id="@+id/split_action_bar"
                  android:layout_width="match_parent"
                  android:layout_height="wrap_content"
+0 −1
Original line number Diff line number Diff line
@@ -175,7 +175,6 @@
  <java-symbol type="id" name="to_common" />
  <java-symbol type="id" name="to_org" />
  <java-symbol type="id" name="to_org_unit" />
  <java-symbol type="id" name="top_action_bar" />
  <java-symbol type="id" name="topPanel" />
  <java-symbol type="id" name="up" />
  <java-symbol type="id" name="value" />
Loading