diff options
-rw-r--r-- | core/java/android/view/View.java | 17 | ||||
-rw-r--r-- | core/java/android/view/ViewRootImpl.java | 1 | ||||
-rw-r--r-- | core/java/com/android/internal/app/ActionBarImpl.java | 154 | ||||
-rw-r--r-- | core/java/com/android/internal/widget/ActionBarOverlayLayout.java | 31 |
4 files changed, 162 insertions, 41 deletions
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index d1d036c..269760e 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -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 @@ -16913,6 +16925,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. */ diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 5eeb211..5b3eca5 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -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) { diff --git a/core/java/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/ActionBarImpl.java index 93cf9d0..2cbd9cc 100644 --- a/core/java/com/android/internal/app/ActionBarImpl.java +++ b/core/java/com/android/internal/app/ActionBarImpl.java @@ -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 diff --git a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java index d1652df..a129496 100644 --- a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java +++ b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java @@ -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(); } } |