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

Commit 7bedac94 authored by Dianne Hackborn's avatar Dianne Hackborn Committed by Android Git Automerger
Browse files

am 139e5aa1: Fix issue #6404215: New ActionBar auto-hide can conflict with application

* commit '139e5aa1':
  Fix issue #6404215: New ActionBar auto-hide can conflict with application
parents aa048661 139e5aa1
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -15236,6 +15236,18 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
        }
    }
    /** @hide */
    public void setDisabledSystemUiVisibility(int flags) {
        if (mAttachInfo != null) {
            if (mAttachInfo.mDisabledSystemUiVisibility != flags) {
                mAttachInfo.mDisabledSystemUiVisibility = flags;
                if (mParent != null) {
                    mParent.recomputeViewAttributes(this);
                }
            }
        }
    }
    /**
     * Creates an image that the system displays during the drag and drop
     * operation. This is called a "drag shadow". The default implementation
@@ -16912,6 +16924,11 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
         */
        int mSystemUiVisibility;
        /**
         * Hack to force certain system UI visibility flags to be cleared.
         */
        int mDisabledSystemUiVisibility;
        /**
         * True if a view in this hierarchy has an OnSystemUiVisibilityChangeListener
         * attached.
+1 −0
Original line number Diff line number Diff line
@@ -1025,6 +1025,7 @@ public final class ViewRootImpl implements ViewParent,
            attachInfo.mSystemUiVisibility = 0;
            attachInfo.mHasSystemUiListeners = false;
            mView.dispatchCollectViewAttributes(attachInfo, 0);
            attachInfo.mSystemUiVisibility &= ~attachInfo.mDisabledSystemUiVisibility;
            if (attachInfo.mKeepScreenOn != oldScreenOn
                    || attachInfo.mSystemUiVisibility != oldVis
                    || attachInfo.mHasSystemUiListeners != oldHasSystemUiListeners) {
+117 −37
Original line number Diff line number Diff line
@@ -39,8 +39,8 @@ import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Handler;
import android.util.Log;
import android.util.TypedValue;
import android.view.ActionMode;
import android.view.ContextThemeWrapper;
@@ -110,10 +110,14 @@ public class ActionBarImpl extends ActionBar {

    private int mCurWindowVisibility = View.VISIBLE;

    private boolean mHiddenByApp;
    private boolean mHiddenBySystem;
    private boolean mShowingForMode;

    private boolean mNowShowing = true;

    private Animator mCurrentShowAnim;
    private Animator mCurrentModeAnim;
    private boolean mShowHideAnimationEnabled;
    boolean mWasHiddenBeforeMode;

    final AnimatorListener mHideListener = new AnimatorListenerAdapter() {
        @Override
@@ -129,6 +133,9 @@ public class ActionBarImpl extends ActionBar {
            mContainerView.setTransitioning(false);
            mCurrentShowAnim = null;
            completeDeferredDestroyActionMode();
            if (mOverlayLayout != null) {
                mOverlayLayout.requestFitSystemWindows();
            }
        }
    };

@@ -430,16 +437,13 @@ public class ActionBarImpl extends ActionBar {
    }

    public ActionMode startActionMode(ActionMode.Callback callback) {
        boolean wasHidden = false;
        if (mActionMode != null) {
            wasHidden = mWasHiddenBeforeMode;
            mActionMode.finish();
        }

        mContextView.killMode();
        ActionModeImpl mode = new ActionModeImpl(callback);
        if (mode.dispatchOnCreate()) {
            mWasHiddenBeforeMode = !isShowing() || wasHidden;
            mode.invalidate();
            mContextView.initForMode(mode);
            animateToMode(true);
@@ -584,21 +588,91 @@ public class ActionBarImpl extends ActionBar {

    @Override
    public void show() {
        show(true, false);
        if (mHiddenByApp) {
            mHiddenByApp = false;
            updateVisibility(false);
        }
    }

    public void show(boolean markHiddenBeforeMode, boolean alwaysAnimate) {
    private void showForActionMode() {
        if (!mShowingForMode) {
            mShowingForMode = true;
            if (mOverlayLayout != null) {
                mOverlayLayout.setShowingForActionMode(true);
            }
            updateVisibility(false);
        }
    }

    public void showForSystem() {
        if (mHiddenBySystem) {
            mHiddenBySystem = false;
            updateVisibility(true);
        }
    }

    @Override
    public void hide() {
        if (!mHiddenByApp) {
            mHiddenByApp = true;
            updateVisibility(false);
        }
    }

    private void hideForActionMode() {
        if (mShowingForMode) {
            mShowingForMode = false;
            if (mOverlayLayout != null) {
                mOverlayLayout.setShowingForActionMode(false);
            }
            updateVisibility(false);
        }
    }

    public void hideForSystem() {
        if (!mHiddenBySystem) {
            mHiddenBySystem = true;
            updateVisibility(true);
        }
    }

    private static boolean checkShowingFlags(boolean hiddenByApp, boolean hiddenBySystem,
            boolean showingForMode) {
        if (showingForMode) {
            return true;
        } else if (hiddenByApp || hiddenBySystem) {
            return false;
        } else {
            return true;
        }
    }

    private void updateVisibility(boolean fromSystem) {
        // Based on the current state, should we be hidden or shown?
        final boolean shown = checkShowingFlags(mHiddenByApp, mHiddenBySystem,
                mShowingForMode);

        if (shown) {
            if (!mNowShowing) {
                mNowShowing = true;
                doShow(fromSystem);
            }
        } else {
            if (mNowShowing) {
                mNowShowing = false;
                doHide(fromSystem);
            }
        }
    }

    public void doShow(boolean fromSystem) {
        if (mCurrentShowAnim != null) {
            mCurrentShowAnim.end();
        }
        if (mTopVisibilityView.getVisibility() == View.VISIBLE) {
            if (markHiddenBeforeMode) mWasHiddenBeforeMode = false;
            return;
        }
        mTopVisibilityView.setVisibility(View.VISIBLE);

        if (mCurWindowVisibility == View.VISIBLE && (mShowHideAnimationEnabled
                || alwaysAnimate)) {
                || fromSystem)) {
            mTopVisibilityView.setAlpha(0);
            mTopVisibilityView.setTranslationY(-mTopVisibilityView.getHeight());
            AnimatorSet anim = new AnimatorSet();
@@ -619,6 +693,16 @@ public class ActionBarImpl extends ActionBar {
                    com.android.internal.R.interpolator.decelerate_quad));
            anim.setDuration(mContext.getResources().getInteger(
                    com.android.internal.R.integer.config_mediumAnimTime));
            // If this is being shown from the system, add a small delay.
            // This is because we will also be animating in the status bar,
            // and these two elements can't be done in lock-step.  So we give
            // a little time for the status bar to start its animation before
            // the action bar animates.  (This corresponds to the corresponding
            // case when hiding, where the status bar has a small delay before
            // starting.)
            if (fromSystem) {
                anim.setStartDelay(100);
            }
            anim.addListener(mShowListener);
            mCurrentShowAnim = anim;
            anim.start();
@@ -627,23 +711,18 @@ public class ActionBarImpl extends ActionBar {
            mContainerView.setTranslationY(0);
            mShowListener.onAnimationEnd(null);
        }
        if (mOverlayLayout != null) {
            mOverlayLayout.requestFitSystemWindows();
        }

    @Override
    public void hide() {
        hide(false);
    }

    public void hide(boolean alwaysAnimate) {
    public void doHide(boolean fromSystem) {
        if (mCurrentShowAnim != null) {
            mCurrentShowAnim.end();
        }
        if (mTopVisibilityView.getVisibility() == View.GONE) {
            return;
        }

        if (mCurWindowVisibility == View.VISIBLE && (mShowHideAnimationEnabled
                || alwaysAnimate)) {
                || fromSystem)) {
            mTopVisibilityView.setAlpha(1);
            mContainerView.setTransitioning(true);
            AnimatorSet anim = new AnimatorSet();
@@ -673,15 +752,18 @@ public class ActionBarImpl extends ActionBar {
    }

    public boolean isShowing() {
        return mTopVisibilityView.getVisibility() == View.VISIBLE;
        return mNowShowing;
    }

    public boolean isSystemShowing() {
        return !mHiddenBySystem;
    }

    void animateToMode(boolean toActionMode) {
        if (toActionMode) {
            show(false, false);
        }
        if (mCurrentModeAnim != null) {
            mCurrentModeAnim.end();
            showForActionMode();
        } else {
            hideForActionMode();
        }

        mActionView.animateToVisibility(toActionMode ? View.GONE : View.VISIBLE);
@@ -740,11 +822,13 @@ public class ActionBarImpl extends ActionBar {
                return;
            }

            // If we were hidden before the mode was shown, defer the onDestroy
            // callback until the animation is finished and associated relayout
            // is about to happen. This lets apps better anticipate visibility
            // and layout behavior.
            if (mWasHiddenBeforeMode) {
            // If this change in state is going to cause the action bar
            // to be hidden, defer the onDestroy callback until the animation
            // is finished and associated relayout is about to happen. This lets
            // apps better anticipate visibility and layout behavior.
            if (!checkShowingFlags(mHiddenByApp, mHiddenBySystem, false)) {
                // With the current state but the action bar hidden, our
                // overall showing state is going to be false.
                mDeferredDestroyActionMode = this;
                mDeferredModeDestroyCallback = mCallback;
            } else {
@@ -758,10 +842,6 @@ public class ActionBarImpl extends ActionBar {
            mActionView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);

            mActionMode = null;

            if (mWasHiddenBeforeMode) {
                hide();
            }
        }

        @Override
+27 −4
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.FrameLayout;

@@ -76,6 +77,26 @@ public class ActionBarOverlayLayout extends FrameLayout {
        }
    }

    public void setShowingForActionMode(boolean showing) {
        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);
        }
    }

    @Override
    public void onWindowSystemUiVisibilityChanged(int visible) {
        super.onWindowSystemUiVisibilityChanged(visible);
@@ -83,11 +104,13 @@ public class ActionBarOverlayLayout extends FrameLayout {
        final int diff = mLastSystemUiVisibility ^ visible;
        mLastSystemUiVisibility = visible;
        final boolean barVisible = (visible&SYSTEM_UI_FLAG_FULLSCREEN) == 0;
        final boolean wasVisible = mActionBar != null ? mActionBar.isShowing() : true;
        if (barVisible != wasVisible || (diff&SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0) {
        final boolean wasVisible = mActionBar != null ? mActionBar.isSystemShowing() : true;
        if (mActionBar != null) {
            if (barVisible) mActionBar.showForSystem();
            else mActionBar.hideForSystem();
        }
        if ((diff&SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0) {
            if (mActionBar != null) {
                if (barVisible) mActionBar.show(true, true);
                else mActionBar.hide(true);
                requestFitSystemWindows();
            }
        }