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

* commit '7bedac9417d60608003d739c8caed7ca81683825':
  Fix issue #6404215: New ActionBar auto-hide can conflict with application
This commit is contained in:
Dianne Hackborn
2012-05-06 12:51:47 -07:00
committed by Android Git Automerger
4 changed files with 162 additions and 41 deletions

View File

@@ -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.

View File

@@ -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) {

View File

@@ -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

View File

@@ -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();
}
}