* commit '7bedac9417d60608003d739c8caed7ca81683825': Fix issue #6404215: New ActionBar auto-hide can conflict with application
This commit is contained in:
@@ -15212,6 +15212,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
|
||||
@@ -16872,6 +16884,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.
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user