summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/java/android/view/View.java17
-rw-r--r--core/java/android/view/ViewRootImpl.java1
-rw-r--r--core/java/com/android/internal/app/ActionBarImpl.java154
-rw-r--r--core/java/com/android/internal/widget/ActionBarOverlayLayout.java31
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();
}
}